Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web MVC: how to structure the Model layer? [closed]

I'm going to take the example of a user object. A user needs to be registered, logged in, logged out, edited (e.g., email change), etc.

So on one hand I have a user object, which includes a variety of class variables (pseudo, email, etc) along with getters and setters and maybe some functions that do not deal with the db.

On the other I have a DAO class which is the object that directly deals with the database through a variety of MySQL / PDO queries (create record, update, retrieve info, etc).

Is there any reason to not have the user object interact directly with the DAO object? In other words, when the Controller request a database query relating to an existing user instance (e.g., during the registration process), should it simply call a function in user which itself calls a function in DAO, or should there be a layer in between?

I have seen examples where the controller calls a 3rd class to interact with the DAO, and passes a user instance as an arg. Sometimes instead, this third layer is in charge with creating the user instance and dealing with the DAO. It seems to me that all the functions used to deal with the DAO could reside inside the user object. What am I missing?

like image 969
JDelage Avatar asked Sep 12 '12 18:09

JDelage


2 Answers

If you are adhering to MVC design pattern, then there is not reason for the User instance to be in the controller. It should be part of model layer, instead of leaking over to presentation layer.

It seems that what you call "controller" is actually more of a service, which should be a part of the model layer, that handles the interaction between domain objects on the data storage related structures (mappers, repositories, DAOs).

Basically, what you are missing is correct separation of concerns.

The controller should be just passing the data to recognition or some user management service, instead of dealing with domain business logic. Said service should initialize the User object, validate the data and try to save it. Controller should no be aware of any of this.

Something like this:

class SomeController
{
     // ---- snip ----

     public function postRegister( $request )
     {
          $accounts = $this->serviceFactory->create('AccountManagement');
          $account->create( $request->getPost('username'),
                            $request->getPost('email'),
                            $request->getPost('password'),
                            $request->getPost('password2') );

          $this->view->setState( View::STATE_POST );
     }

     // ---- snip ----
}

class AccountManagement extends Service
{
     // ---- snip ----

    public function addUser( $username, $email, $password, $repeated_password )
    {

        $user = $this->domainObjectFactory->create( 'User' );

        $user->setNickname( $username );
        $user->setEmail( $email );
        $user->setPassword( $password );
        $user->matchRepeatedPassword( $repeated_password );

        if ( $user->isValid() )
        {
            $dao = $this->DAOFactory->create( 'User' );
            $dao->save( $user );
        }

        // additional code for saving the error state
        // if domain object turns out to be invalid
        // or DAO returns an error
    }

     // ---- snip ----
}

P.S. you might find this post relevant.

like image 184
tereško Avatar answered Oct 25 '22 20:10

tereško


I think you’re describing some sort of adapter or gateway for models, where you have a class that calls an adapter (it may interact with a database, or an XML data source) and then assigns the results to instances of your model (i.e. assigns each matching user result to an instance of your User model).

In the past, I’ve taken the approach you’ve described where you have models that represent one item, and then a DAO to save and retrieve these items to a data source (be it a database or whatever), and the controller that does the logic. So an extremely basic version:

UsersDAO.php

class UsersDAO extends DAO
{
    public function save(User $user)
    {
        return is_null($user->id) ? $this->insert($user)
                                  : $this->update($user);
    }

    public function insert(User $user)
    {
        $sql = "INSERT INTO `users` (`username`, `password`)
                VALUES (:username, :password)";

        $stmt = $this->db->prepare($sql);
        $stmt->bindParam(':username', $user->username);
        $stmt->bindParam(':password', $user->password);
        $stmt->execute();
    }
}

User.php

class User
{
    public $id;
    public $username;
    public $password;
    public $email;
}

UsersController.php

class UserController extends Controller
{
    public function register()
    {
        $usersDao = new UserDAO;

        if ($_POST) {
            $user = new User;
            $user->username = $_POST['username'];
            $user->password = $_POST['password'];

            $userDao->save($user);
        }
    }
}

Hope this helps.

like image 21
Martin Bean Avatar answered Oct 25 '22 18:10

Martin Bean