3

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.

1 Answer 1

3

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.

9
  • Thanks for the answer that’s really helpful, however I have some further questions if you don’t mind? So really the persistence mechanism should be completely separate from the idea of a domain object? And my user class could be considered a bean instead of a domain object for the pure purpose of moving data from different areas of the program, in this case the database? Commented Jan 12, 2020 at 10:59
  • Your domain object (user) should be encapsulated. It's members should be private with no getters. Rather than ask it about it's state you tell it to do things. This works well when you move logic that uses that state into the class. But it breaks down if that logic can't be moved, like with persistence. In that case you ask the domain object to create a bean with the current state. This you can send off to be persisted. That moves the data across the boundary. But no, you don't make the bean into a domain object. You can construct your domain object from a bean and persist it with a bean. Commented Jan 12, 2020 at 11:12
  • You say that if the object has an ID it’s an entity. In my case my user object does have an ID. So could my user object be considered a bean and an entity at the same time? And is it the case that entities are basically beans with ID’s? I’m a little confused on that. If beans and true objects are separate, are beans, entities and the persistence mechanism still considered to be part of the model layer? Commented Jan 12, 2020 at 11:14
  • If I wanted to create a ‘user’ profile, would it be best to create a proper ‘UserProfile’ domain object that doesn’t directly mirror a database (entity), with state and functionality that can retrieve data from the users table? For things like changing passwords. Commented Jan 12, 2020 at 11:14
  • If you wrap your domain object in getters it breaks encapsulation. You can do that, and some people do, but you turn your object inside out because now methods that should be inside the object could be anywhere. Changing existing code becomes really difficult. Commented Jan 12, 2020 at 11:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.