I’ve been trying to get a firm understanding of the MVC design pattern so that I can write my own framework for implementing the back-end of a forum web application using Slim 3. In particular, after reading this, and asking this and this question myself I’m now at a point where I think I understand how the model should be a layer composed of data mappers, services and domain objects. However I have some more questions regarding domain objects.

At the moment with a very similar structure from an answer given to this question I asked. I have a basic model layer structure for registering a user to my forum application. However it seems to me that my User ‘domain object’ isn’t really doing anything at the moment, it only has getters and setters and I could probably do without it.

User domain object:

class User
{
    private $id;
    private $email;
    private $username;
    private $password;

    public function __construct(Email $email, Username $username, Password $password)
    {
        $this->email = $email;
        $this->username = $username;
        $this->password = $password;
    }

    public function getId()
    {
        return $this->id;
    }

    public function setId(int $id)
    {
        $this->id = $id;
    }

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail(Email $email)
    {
        $this->email = $email;
    }

    public function getUsername()
    {
        return $this->username;
    }

    public function setUsername(Username $username)
    {
        $this->username = $username;
    }

    public function getPassword()
    {
        return $this->password;
    }

    public function setPassword(Password $password)
    {
        $this->password = $password;
    }
}

This user domain object directly mirrors that of my ‘user’ SQL table that is populated when a user registers. In fact this created user domain object is passed to my data mapper then the fields of the passed in user object are extracted and inserted into the database.

Inserting a user object into my ‘user’ table:

 private function insertUser(User $user) 
 {
      $sql = 'INSERT INTO users (email, username, password) 
              VALUES (:email, :username, :password)';

      $statement = $this->connection->prepare($sql);
      $statement->execute([':email' => $user->getEmail(),
                           ':username' => $user->getUsername(),
                            ':password' => $user->getPassword()]);

      $user->setId($this->connection->lastInsertId());

      return $user;
 }

Could I not just directly pass in the strings that the user typed into the form (after validation and sanitation) instead of having to create this user domain object. It just seems unnecessary at the moment.

This is where I’m confused as to what exactly a domain object should be. I understand they should encompass business logic, but identifying what business logic I would need for a forum application is proving difficult. For example I would like each user to have their own profile page that is publicly visible, that they can only edit and update when the user in question is logged in.

Would I need to create a ‘profile’ domain object together with a new profile table that links to my original user table and user domain object? Or could I simply extend my existing user table and user domain object to have properties and methods that can allow a user to display and update their profile?

I understand this is a matter of design and can be subjective, but some advice on what should be in a domain object (especially for the previous example with a profile) and if they need to marry up to a table or not would be helpful.

A lot of the tutorials I see such as this, simply have a single model object that has data mappers methods in them which doesn’t seem right. A lot of tutorials also use frameworks that utilise ORM which is something I’m trying to avoid using as I want to write everything from scratch, although I’m fine with using Slim 3 / 4 PHP.

有帮助吗?

解决方案

I’ve been trying to get a firm understanding of the MVC design pattern

Model View Controller is an impossibly simple pattern. As long as you have something that focuses on the model, the view, and the control then poof you're using MVC. The pattern is so old that no one agrees how those things communicate or how they should be separated. Anything beyond the three responsibilities is just someones idea. The rest isn't standardized. If you want me to understand how your stuff communicates and is separated then you gotta say more than "I use MVC".

However it seems to me that my User ‘domain object’ isn’t really doing anything at the moment, it only has getters and setters and I could probably do without it.

This isn't a true object oriented object. It's a pile of debugging code (getters and setters) around a data structure. There is no true encapsulation. There is no behavior logic. Does that mean it's useless? No. It's exactly what you need to move data across boundaries in a type safe way (if you don't need type safe just use a collection). But it's no true object. It is a pattern though. It's called a bean. They were invented to make writing persistence frameworks easier. They don't teach you real encapsulation or how to make good objects.

This user domain object directly mirrors that of my ‘user’ SQL table...

That's exactly why it's not a domain object. A domain object is not a slave to a repository. It's an independent abstraction in the domain. It represents an idea from the domain, not a mechanical need of the system like persistence.

If it has an ID it's an entity. Entities are allowed to have state that doesn't persist.

If you'll forgive an analogy, persisted entities are freeze dried. Add water and they come to life with new properties and features. Don't insist that they be the same in both forms. It's very useful to have custom transformations from one to the other. It's very hard to have that if you use an ORM.

This is all to say that an entity has a life outside of it's persistence representation.

Could I not just directly pass in the strings that the user typed into the form (after validation and sanitation) instead of having to create this user domain object. It just seems unnecessary at the moment.

Exactly right. Objects should have a reason to exist. A true object is a bag of functions that change and move together. You could pass insertUser() the user fields it needs and be done. You could also move insertUser() into the user class and let it get the fields from object state.

The only reason good to stick with the behaviorless data structure (that bean) is if the data needs to cross a broundry between different systems. A boundary that prevents you from moving behavior (like insertUser()) into a proper object.

One of the things object oriented programming has you do is stop moving data around and instead move the behavior (functions/methods) together with that data. Problem is you can't always do that. Sometimes the data needs to move. That's when you fling around data structures.

许可以下: CC-BY-SA归因
scroll top