Building a Domain Model – An Introduction to Persistence Agnosticism

With so much water flowing under the Domain Models bridge over the last few years, it’s rather hard to dig deep into the key concepts without rippling even more confusion in the already agitated creek. Moreover, with tons of MVC implementations proliferating like hungry ants, the acronym’s “M” continues to suffer from the symptoms of an ad-hoc layer, usually known as a Database Model, which can pollute with total impunity the domain logic with code for database access (hence infrastructure), or with other type of underlying storage.

What makes a Database Model so appealing in many cases is that it performs fairly well from the perspective of client code. After all, it’s easily consumable, as it hides a lot of complexity behind an apparently harmless API (for example, something like $user->save()). The downside is that it clashes noisily when it comes to sticking to good object-oriented design practices, not to mention the plethora of scalability and testability issues that eventually bubble up to the surface.

From this standpoint, it would seem that popular data source architectural patterns, such as Active Record and Table Data Gateway should be considered potentially harmful intruders, when they’re coupled to domain logic. But throwing blame to the patterns for what they’re intended to do is nothing but a weak excuse for not embracing a Domain Model according to the purpose it was conceived in the first place: an independent, persistence-agnostic layer responsible for defining clearly the interactions between the entities of a system through data and behavior.

Of course, the above definition is a world away from being formal. Still, it highlights a few important ideas. First off, creating a rich Domain Model, where multiple domain objects with well-defined constraints and rules interact, can be a daunting task. Second, not only is it necessary to define from top to bottom the model itself, but it’s also necessary to implement from scratch or reuse a mapping layer in order to move data back and forward between the persistence layer and the model in question. The process requires at least one extra layer to get things sorted out, therefore moving away from more pragmatic approaches.

The payback, though, can be surprisingly gratifying in the end, especially when considering the model in its entirety can be ported without much hassle from one infrastructure to another. A big bonus, indeed.

You’re probably wondering if a Domain Model gets along with PHP. Well, in fact it does, albeit at the expenses of having to tackle the aforementioned issues. But claims like this must be always backed up with a decent proof of concept, so, allow me to provide a few examples.

Building a Basic Blog Domain Model

Unquestionably the nuts and bolts of a Domain Model is the strong focus put on the relationship between data and the behavior of domain objects while leaving any trace of infrastructure out of the picture. The beauty of this approach (and why I’m a big fan of it as well) is that the goal is achieved with elegance and simplicity. Quite often, simple PHP Domain Models are composed of a few POPOs (Plain Old PHP Objects), which encapsulate rich business logic, like validation and strategy, behind a clean API.

With that said, let’s see how to translate the conceptual stuff to tangible PHP code. So, say we need to build a pretty contrived blog program which must be capable of handling posts, comments, and users in a standard fashion. A good start to achieve this would be modeling the blog’s domain objects like POPOs.

Here’s the first one:

<?php
namespace Model;

interface PostInterface
{
 	public function setId($id);
 	public function getId();

 	public function setTitle($title);
 	public function getTitle();
	 
 	public function setContent($content);
 	public function getContent();

 	public function setComments(array $comments);
 	public function getComments();
}

The above interface is anything but complicated. Indeed, it’s clear to see that the purpose of PostInterface is to define a narrow contract for generic post objects which should have a one-to-many relationship with the related comments.

Since the interface’s code speaks for itself, let’s go one step further and create another interface to specify the contract for the corresponding comments:

<?php
namespace Model;

interface CommentInterface
{
    public function setId($id);
    public function getId();
	 
    public function setContent($content);
    public function getContent();

    public function setUser(UserInterface $user);
    public function getUser();
}

Similar to PostInterface, there’s not much to be said about CommentInterface. It drops into the model a simple contract for blog comment objects. Quite possibly the only detail worth noting in this case is the signature of its setUser() method, which appeals to the whip of Interface Injection for binding a user to a specific comment.

We’re almost done with creating the model’s interfaces. But before we can throw a well-deserved party and start toasting, it’s necessary to create one more which must outline the behavior of blog users. Here’s how this final interface looks:

<?php
namespace Model;

interface UserInterface
{
    public function setId($id);
    public function getId();

    public function setName($name);
    public function getName();

    public function setEmail($email);
    public function getEmail();

    public function setUrl($url);
    public function getUrl();
}

With this batch of interfaces, we’ve managed to define in a jiffy a simple – yet efficient – set of granular contracts which allow you to swap out concrete domain object implementations, as if we were using Lego blocks.

Next we need to hydrate our model with some interface implementers; let’s see now how to accomplish this in a fairly painless way.

Modeling Blog Posts, Comments, and Users with POPOs

Since we’re rather lazy developers who want to save ourselves the hassles of calling mutators and accessors every time we need to work with the fields of a domain object, we can use some boilerplate PHP magic for mapping client code references from nonexistent properties to the corresponding domain objects methods. This is a pretty common and pragmatic approach which is usually encapsulated inside the boundaries of an abstract class, like the one shown below:

<?php
namespace Model;

abstract class AbstractEntity
{
    /**
     * Map the setting of non-existing fields to a mutator when
     * possible, otherwise use the matching field
     */
    public function __set($name, $value) {
        $field = "_" . strtolower($name);

        if (!property_exists($this, $field)) {
            throw new InvalidArgumentException(
                "Setting the field '$field' is not valid for this entity.");
        }

        $mutator = "set" . ucfirst(strtolower($name));
        if (method_exists($this, $mutator) &&
            is_callable(array($this, $mutator))) {
            $this->$mutator($value)
        }
        else {
            $this->$field = $value;
        }

        return $this;
    }

    /**
     * Map the getting of non-existing properties to an accessor when 
     * possible, otherwise use the matching field
     */
    public function __get($name) {
        $field = "_" . strtolower($name);

        if (!property_exists($this, $field)) {
            throw new InvalidArgumentException(
                "Getting the field '$field' is not valid for this entity.");
        }

        $accessor = "get" . ucfirst(strtolower($name));
        return (method_exists($this, $accessor) &&
            is_callable(array($this, $accessor)))
            ? $this->$accessor() : $this->field;
    }

    /**
     * Get the entity fields
     */
    public function toArray() {
        return get_object_vars($this);
    }
}

I’m not a strong advocate of relying heavily on PHP’s magic methods, but in this case the __set() and __get() methods come in handy for shortening calls to setters and getters without cluttering too much of the model’s API. With the previous parent class doing the leg work behind the scenes when it comes to working with domain object fields, the creation of concrete implementations for blog post, comment, and user objects boils down to subclassing a parent, as follows:

<?php
namespace Model;

class Post extends AbstractEntity implements PostInterface
{
    protected $_id;
    protected $_title;
    protected $_content;
    protected $_comments;

    public function __construct($title, $content, array $comments = array()) {
        // map post fields to the corresponding mutators
        $this->setTitle($title);
        $this->setContent($content);
 
        if ($comments) {
            $this->setComments($comments);
        }
    }
    
    public function setId($id) {
        if ($this->_id !== null) {
            throw new BadMethodCallException(
                "The ID for this post has been set already.");
        }
 
        if (!is_int($id) || $id < 1) {
            throw new InvalidArgumentException("The post ID is invalid.");
        }
 
        $this->_id = $id;
        return $this;
    }
    
    public function setTitle($title) {
        if (!is_string($title)
            || strlen($title) < 2
            || strlen($title) > 100) {
            throw new InvalidArgumentException("The post title is invalid.");
        }
 
        $this->_title = htmlspecialchars(trim($title), ENT_QUOTES);
        return $this;
    }

    public function getTitle() {
        return $this->_title;
    }
    
    public function setContent($content)
    {
        if (!is_string($content) || strlen($content) < 2) {
            throw new InvalidArgumentException("The post content is invalid.");
        }
 
        $this->_content = htmlspecialchars(trim($content), ENT_QUOTES);
        return $this;
    }
    
    public function getContent() {
        return $this->_content;
    }
    
    public function setComments(array $comments) {
        foreach ($comments as $comment) {
            if (!$comment instanceof CommentInterface) {
                throw new InvalidArgumentException(
                    "One or more comments are invalid.");
            }
        }
 
        $this->_comments = $comments;
        return $this;
    }
    
    public function getComments() {
        return $this->_comments;
    }
}

As you might expect, modelling a blog post as a POPO is a very straightforward process, reduced to 1) implementing the methods defined by its associated interface, and 2) optionally extending the functionality of the base entity class. What’s more, since in this case the post is capable of validating itself through its mutators, thus carrying both data and behavior, there’s no need to pollute application logic with scattered validation blocks. This vaccinates the whole model against anemic issues and makes it much cleaner and DRYer.

Considering that the previous approach delivers what it promises at face value, let’s reuse it for modeling blog comments and users as well. Here are the subclasses that wrap these additional domain objects:

<?php
namespace Model;

class Comment extends AbstractEntity implements CommentInterface
{
    protected $_id;
    protected $_content;
    protected $_user;

    public function __construct($content, UserInterface $user) {
        $this->setContent($content);
        $this->setUser($user);
    }

    public function setId($id) {
        if ($this->_id !== null) {
            throw new BadMethodCallException(
                "The ID for this comment has been set already.");
        }
 
        if (!is_int($id) || $id < 1) {
            throw new InvalidArgumentException("The comment ID is invalid.");
        }
 
        $this->_id = $id;
        return $this;
    }
    
    public function getId() {
        return $this->_id;
    }
    
    public function setContent($content) {
        if (!is_string($content) || strlen($content) < 2) {
            throw new InvalidArgumentException(
                "The content of the comment is invalid.");
        }
     
        $this->_content = htmlspecialchars(trim($content), 
            ENT_QUOTES);
        return $this;
    }
    
    public function getContent() {
            return $this->_content;
    }
    
    public function setUser(UserInterface $user) {
        $this->_user = $user;
        return $this;
    }
    
    public function getuser() {
        return $this->_user;
    }
}
<?php

namespace Model;

class User extends AbstractEntity implements UserInterface
{
    protected $_id;
    protected $_name;
    protected $_email;
    protected $_url;

    public function __construct($name, $email, $url = null) {
        // map user fields to the corresponding mutators
        $this->setName($name);
        $this->setEmail($email);
     
        if ($url !== null) {
            $this->setUrl($url);
        }
    }
    
    public function setId($id) {
        if ($this->_id !== null) {
            throw new BadMethodCallException(
                "The ID for this user has been set already.");
        }
     
        if (!is_int($id) || $id < 1) {
            throw new InvalidArgumentException("The user ID is invalid.");
        }
 
        $this->_id = $id;
        return $this;
    }
    
    public function getId() {
        return $this->_id;
    }
    
    public function setName($name) {
        if (strlen($name) < 2 || strlen($name) > 30) {
            throw new InvalidArgumentException("The user name is invalid.");
        }
     
        $this->_name = htmlspecialchars(trim($name), ENT_QUOTES);
        return $this;
    }
    
    public function getName() {
        return $this->_name;
    }

    public function setEmail($email) {
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException("The user email is invalid.");
        }
     
        $this->_email = $email;
        return $this;
    }
    
    public function getEmail() {
        return $this->_email;
    }
    
    public function setUrl($url) {
        if (!filter_var($url, FILTER_VALIDATE_URL)) {
            throw new InvalidArgumentException("The user URL is invalid.");
        }
     
        $this->_url = $url;
        return $this;
    }
    
    public function getUrl() {
        return $this->_url;
    }
}

Mission accomplished!

Even at the risk of sounding somewhat verbose, at this moment it’s safe to say that the blog domain model is finally set. The underlying interfaces and classes are there, living in happy ignorance about the existence of any type of persistence mechanism that may be implemented down the line, be it a database, a web service, or anything else.

Furthermore, not only do they define a network of rules and rich relationships with each other, but the current domain object implementations can be replaced with custom ones without much fuss.

Now the question becomes how to consume the model. Well, that’s an easy one, indeed! If we were going to build a naive blog application, where all of its object graphs reside all the time in memory and don’t need to be persisted, the process would be a breeze to tackle as there would be no need to create a mapping layer at all. To elaborate a bit further this concept, however, let’s try out some concrete code samples.

Putting the Domain Model to Work

If we plan to use a multi-tier perspective in the design of the blog, the application could be easily broken down into well-defined layers. The first layer would be the typical bootstrap, which would simply include and initialize an autoloader, like this:

<?php
require_once __DIR__ . "/Autoloader.php";
$autoloader = new Autoloader();
$autoloader->register();

The bootstrap doesn’t doing anything weird; it just loads and registers a PSR-0 compliant autoloader.

The second layer would be the home to our domain model, which at its most basic level could be implemented as follows:

<?php
use ModelPost,
    ModelComment,
    ModelUser;

// create some posts
$postOne = new Post(
    "Welcome to SitePoint",
    "To become yourself a true PHP master, yeap you must first master PHP.");

$postTwo = new Post(
    "Welcome to SitePoint (Reprise)",
    "To become yourself a PHP Master, yeap you must first master... Wait! Did I post that already?");

// create a user
$user = new User(
    "Everchanging Joe",
    "joe@hisdomain.com");

// add some comments to the first post
$postOne->comments = array(
    new Comment(
        "I just love this post! Looking forward to seeing more of this stuff.",
        $user),
    new Comment(
        "I just changed my mind and dislike this post! Hope not seeing more of this stuff.",
        $user));

// add another comment to the second post
$postTwo->comments = array(
    new Comment(
        "Not quite sure if I like this post or not, so I cannot say anything for now.",
        $user));

Even though model performs only a few simple tasks, such as creating a couple of posts and binding some comments made by a rather irresolute guy, it comes in handy for showing how to wire the domain objects together and put them to work. In this case each object graph is spawned by using plain Dependency Injection, which is sufficient for demonstrative purposes.

If the situation warrants, however, object graph creation should be delegated to more versatile structures, such as a Dependency Injection Container or a Service Locator. In either case, at this point the model is already doing its business as expected.

Let’s move on and create the blog’s application layer (the controllers in an MVC stack) which is responsible for pulling in model data and passing it to the presentational layer.

Here’s how this tier looks:

<?php
$posts = array($postOne, $postTwo);

Could this layer be any simpler or shorter? I don’t think so.

Leaving all mockery aside, it demonstrates in a nutshell that a Domain Model is, quite possibly, the most glaring example of the Fat Models/Skinny Controllers mantra in action. Having all the emphasis placed on business logic, controllers are naturally diminished to the realm of simple mediators between the model and the user interface.

Now that our blog’s application layer is rolling smoothly, let’s make create the layer that dumps the previous blog posts to screen. As you might expect, this is a dull HTML template containing just a few PHP loops:

<!doctype html>
<html>
 <head>
  <meta charset="utf-8">
  <title>Building a Domain Model in PHP</title>
 </head>
 <body>
  <header>
   <h1>SitePoint.com</h1>
  </header>
  <section>
   <ul>
<?php
foreach ($posts as $post) {
?>
    <li>
     <h2><?php echo $post->title;?></h2>
     <p><?php echo $post->content;?></p>
<?php
    if ($post->comments) {
?>
     <ul>  
<?php
        foreach ($post->comments as $comment) {
?>
      <li>
       <h3><?php echo $comment->user->name;?> says:</h3>
       <p><?php echo $comment->content;?></p>
      </li>
<?
        }
?>
     </ul>
<?php
    }
?>
    </li>
<?php
}
?>
   </ul>
  </section>
 </body>
</html>

Given the banal responsibility of the blog’s presentation layer, I decided to implement it by using just PHP’s native templating capabilities. Regardless, the most relevant thing to stress here is the fact that hooking up our domain model to different layers was indeed a breeze to achieve. Best of all, the entire implementation didn’t require to tie up the model in question to any form of persistence infrastructure, therefore turning it into an easily portable and scalable creature!

Does this mean that a Domain Model is the panacea for all the flaws that a Database Model exposes behind the scenes? Well, in a sense it is, even with some caveats. As noted at the beginning, the biggest caveat is the hassle of having to map domain objects back and forward to the persistence layer, something that can’t be accomplished in a heartbeat unless we appeal to the goodies of a third-party ORM like Doctrine, RedBeanPHP, or something along those lines.

As usual, choosing between a prepackaged data mapper or a custom one is just a matter of personal requirements and taste. As the French philosopher Jean Paul Sartre said once, “men are condemned to be free”. So, use your freedom consciously and pick up the mapping library that suits your needs best.

Final Thoughts

With a huge number of HTTP frameworks gaining momentum in the PHP world (like Symfony 2.x, Aura, and even Zend Framework) which don’t provide users with a base Model up front (or worse, provide the infamous Database Model), hopefully we’ll see in the near future more advocates of rich Domain Models. In the interim, it’s pretty healthy to take an in-depth look at them and see how to implement a trivial one from scratch, as we just did before.

In a future article, I hope to dig even deeper into the nitty-gritty of Domain Models and developing a custom mapping layer to demonstrate how to transfer data between the previous model and MySQL. Stay tuned!

Image via kentoh/ Shutterstock

Win an Annual Membership to Learnable,

SitePoint's Learning Platform

  • http://www.webpagefavs.com Les

    IMHO there is a lot of bloat there, in regards to duplication between the POSTs and COMMENTs. Also I do not like the way you add a comment(s) to a post. I would use something like $post -> addComment( IComment_Interface $comment ) and return $this so you can add another comment if required?
    As a seasoned PHP developer I would have done things much more differently.

    • Alex Gervasio

      Hey Les,
      Sorry, but I don’t buy your argue. Duplicated implementation between posts and comments, or any other domain class that might be dropped further down the road (feel free to add your own one to the list) just happens at validation level, which is a “natural” yet easily-fixable effect, as in this case class dependencies have been modeled mostly around scalar types, rather than around value objects, in order to keep the whole model simpler and understandable. Modeling domain classes as reactive, self-validating structures is always a trade-off between having some eventual duplicated validation (if any) and simplicity. In more realistic use cases, however, validation is shifted to DTOs or services, thus stripping out entities from large chunks of behavior.
      Regarding the way that comments are added to posts, yeap, type hinting the interface is probably a bit clearer than doing the check in the method body. To say you, “Seasoned PHP developers” tend to do so.
      Thanks for the feedback.

  • http://bolderthinking.com/ dkanen

    We’ve managed to build a rich Domain Model centered architecture using the Zend Framework. The Zend Framework provides most of the infrastructure for receiving, handling and validating requests while our custom code implements the Domain Model.

    The persistence of these models is managed with an Identity Map. Each model then has a corresponding Table Data Gateway object that describes how to perform the basic operations as well as how to create collections based on various useful criteria. This combination of Identity Map and Table Data Gateway makes ensuring objects that changed are persisted a snap by simply putting a method call inside of each mutator that marks it ‘dirty’ when a member variable changes.

    • Alex Gervasio

      Sound pretty nice, indeed. Also, it looks like you’re having some lightweight Unit of Work humming behind the scenes, without having full transactional support. Coupling a Table Data Gateway implementation to a Domain Model is in general a good approach for pretty basic Domain Models, where each object has an isomorphic relationship with a database table. In most cases, however, this just won’t happen that way. That’s why a Data Mapper is more suitable for resolving such impedance mismatches, while keeping a clearer, well-differentiated separation between the domain and the persistence layer.
      Keep up the good work.

  • code4pay

    I love this, just started a job with PHP and I find the clean approach of the Domain Model very appealing. Question (excuse my ignorance) whats the point of your abstract class. I thought it was so you did not need to set getters and setters for all variables but you have anyway in the concrete classes?

    • Alex Gervasio

      Hey,
      The abstract entity class is just a cheap shortcut for setters and getters in the domain classes, so that you can call them as if you were actually using public properties in client code. Of course, dropping this class into the model is entirely optional, so if you feel more comfortable with a more traditional setter (if any)/getter notation, just go for it.
      Thanks for the comments.

  • Jiri Fornous

    Validation at domain model

    It seems to me redundant to make validations at domain model since you probably have consistent set of validations in your controller layer unless the model part is developed by different team.
    The only validation I see useful is checking the consistency of created model (object graph).
    Thus you stay again with anaemic model only, which is undesirable.

    Domain model entry point

    What I was wondering is the entry point to your object graph. Let us suppose you are populating the model as you shift in application DAG (directed acyclic graph) and you are storing the created object graph somewhere in session (the state of the object graph is often versioned to step back easily). It seems to be pretty straight forward to start always with user entity, but there are cases when object graph is user independent. There can also be more than one object graph in given time. Another problem could be reaching the same entity kind with different ID (you have set of clients, choose one client, get all of responsible employees, choose one employee, get all clients he/she is responsible of, choose one client and here we are back at client entity with different ID within the same object graph).

    • Alex Gervasio

      Keep in mind that validation is always CONTEXTUAL, which means that isn’t redundant to have a domain model defining its own business-related constraints, while performing some pre/post persistence validation within the application layer (controllers, services, you name it). In small, extremely naive Domain Model – VC applications, it’s possible to place validation in the controllers and still trust that entities will be created in a valid stated. With large applications, this is not a viable approach (at least without sinking your head in the cumbersome waters of duplicated implementation :-).
      In regard to the domain model’s entry point, I use to delegate object graphs creation to services, which in turn use DiCs, repositories and so forth, coupled to identity maps to keep track of which entities have been pulled in from the database.
      Hope that helps.

  • http://solsoft.biz/ Braulio Solano Rojas

    Hello. Take a look at http://flow3.typo3.org/. I think it is very similar to what you are proposing.
    Bests…

    • Alex Gervasio

      Thanks Braulio for dropping the link. Yeap, the guys from FLOW3 have done quite a great job in building a full-stacked Domain-Driven Design framework. We’ve been using it in large application development, and it delivers pretty well.

  • http://techishard.wordpress.com/ Grant Parks

    Thank you so much for articles like these. Especially explaining to people the difference between a data layer and a model. I am so weary of being overshouted over at LinkedIn regarding MVC and frameworks.

    • Alex Gervasio

      Hi Grant,
      Glad you liked the writeup. Keep up striving hard for breaking down the model = database myth. You’re not alone riding the wagon, trust me :-)

  • Jiri Fornous

    I have two more questions

    There is a lot of calculation done often on the domain model objects and the resulting data are very relative to the objects within the graph. They do not have any image in persistent storage and serve most for visualization or as a temporary result for next calculation (data modification). Do you also keep them inside the domain model at the entity objects and only ignore them during synchronization with DB or you don’t mix anything else than 1:1 DB data?

    You have mentioned Identity Map for keeping the track of changes. As you probably don’t have one request only domain model life time you should store the object graph somewhere in session from request to request. So you have to store also Identity Map beside the object graph. Does it mean you have domain model encapsulated in some domain model object, which is able to serialize itself as a whole? Or you use repository object to keep track of all domain model objects and pack Identity Map with?

    • Alex Gervasio

      To put it in a simpler way, the model is responsible for maintaining the state of your application. So, domain objects should carry state, and ideally a lot of business logic, including the batch of calculations you cleverly mentioned before, validation, strategy and so forth. Naturally, to keep all these operations in sync and nicely orchestrated, you might need to create some object graphs along the way. In a typical domain model implementation, the creation of those domain graphs is responsibility of the data mappers, which live and breath closer to the database and know how to pull in data from one or multiple tables, and also how to drop the graphs straight into memory. Eventually, (and this is just DDD parlance, so take it at face value), you might want to sit down a repository on top of the mapping layer and encapsulate query logic behind an API that’s closer to the domain and that also speaks the domain’s language. Bringing this layer to life, however, depends heavily on your application’s requirements.

      On the other hand, all the logic that doesn’t fall inside the boundaries of the domain model is usually placed in services (pure application logic, handy for interplaying with different client layers), or in simpler use cases, in the controllers. I hope my verbiage sheds some light on your first question.

      Regarding the second question, if you ever need to persist an object graph between requests (a shopping cart is a glaring example of this), then simply use sessions. What’s more, you can serialize/JSON-encode/etc. your domain object graphs. But it would be ultimately pointless, unless you use a noSQL database such as MongoDB or CouchDB.

      As a rule of thumb, put a mapping layer to do the hard work for you and let it create and persist your domain objects transparently. There’s a decent number of libraries out there that will assist you in this process.

  • http://objectic.cc/ Niko Kivelä

    Great article, I would buy it! Waiting for your next one considering datamappers.
    An interest aspect is that you’re advocating separation of concerns by separating model from data access (persistence)layers, so why is it Post and Comment models’ responsibility to apply htmlspecialchars for content and title? Same goes for User’s name. Or should it be handled at view layer? How do I handle title from model to model, in it’s original format? Is it fellow models and controllers responsibility to know that Post is handling view logic and not to apply, e.g. when copying content of Post to another.

    This is not ment to be criticism, but a question. How do you replace Models that should be quite easy, just follow the interfaces(!) but what doesn’t say anything about that it should be participating to view’s work.

    What @Les said is quite true: “I do not like the way you add a comment(s) to a post”. Enabling __magic methods for lazy programmers is going to generate more error-prone debugging nightmares. I could add comments $post->comments = array(…) or $post->comment (typoed). It goes nice and easy in. Enabling clever magic in the name of pragmatic shortening code is just an excuse for laziness (my opinion).

    • Alex Gervasio

      Nikko,
      I appreciate your feedback. In regard to your questions: 1) Entities are not handling presentation logic at all. They’re just sanitizing dependencies. 2) As I said before, feel free to implement an “addComment()” method that types hint the interface, instead of checking what it gets injected in the method body.
      Lastly, putting setter/getter magic in an abstract class is an optional addendum that doesn’t impact model’s logic at any level. It’s just a matter of personal preferences. So, if you feel a “little bit less lazy” by using plain vanilla setting/getting syntax, pick up that approach and stick to it all the way.

  • Charles

    Can I ask about your getters and setters in your abstractEntity. I have used the magic methods before but I have been told they are bad practice, they allow you to set and get private variables in the class hierarchy, is it because the class is an abstract class that have used them?? I have spent a good hour or so trying to look into this issue, but I am still unsure whether or not I should use them. The reason why I want to know is I recently failed an interview because my base class had getters and setters and my extended class had private and protected variables, it would be good to have an experts view on the matter.

  • http://objectic.cc/ Niko Kivelä

    @Charles: I recently read an article about “GetSet Methods vs. Public Properties”. Check it out here http://blog.everymansoftware.com/2012/03/getset-methods-vs-public-properties.html

    The problem with magic __set and __get methods is emphasized in the picture at the end of the article: “I don’t always make my properties private. But when I do, I make sure they’re public anyway.”. Quite funny tho :p

    (Would be nice (by the way) if phpmaster would send notifications via mail about replies to articles you’ve participated to.)

    • Alex Gervasio

      Thanks Niko for pitching the link. I guess it’ll be contributing to make the topic even easier to spot on.

    • Charles

      Thanks for replying Niko, I can see an argument for using them, but also a strong argument against them. In this example there are protected variables that can be set by the magic methods, it is a shame that php does not have some check for testing a variables visibility.

      On a separate note, I am in awe at the php coding level in these examples, I feel I have made huge leaps in my php knowledge, I thought I was pretty good until I read this, I really love being on a learning curve. I would love to learn more about architecting systems from the ground up, will be looking forward to more tutorials, thanks @Alex.

      • Alex Gervasio

        Charles,
        In fact, PHP does have a nice Reflection API http://www.php.net/manual/en/class.reflectionproperty.php, which will let you check in a snap the visibility of your class members, and do all sort of other clever stuff as well. Using the API for checking if the “__get/__set()” methods are mapping to public properties not only is plain overkill, but a clear sign of a design where encapsulation has been blatantly broken, either because of laziness or plain ignorance. To sum up: always declare your properties protected or private. On top of that up front shielding, you have plenty of room to decide where to code a setter or a getter (if any).

  • Alex Gervasio

    Hey Charles,
    From a strict OOP standpoint, setters and getters are considered a bad thing http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html, because they unavoidably break encapsulation (AKA information hiding). What’s more, even Inheritance breaks encapsulation as well http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html. But, would you give up using it ultimately? I hardly think so, even if you’re always nice and favor over Composition in every possible situation.
    In the case of the AbstractEntity class, the “__set()/__get()” duet is just used for mapping calls to the real mutators/accessors defined in entity subclasses. This “classic” approach allows to implement a fairly flexible mechanism for invoking setters/getter as if you were using public properties (which isn’t true, of course). The set()/get() debate is certainly old and plagued with lots of ins and outs. The flip side of the story is that setters/getters help in creating clear interfaces, where Command/Query Separation (CQS) is well defined, thus making easier to see what methods are mutating the state of an object and what aren’t. As a rule of thumb: use PHP magic with caution, and make your class properties always protected/private. If you ever need to code a getter, then do it for a really good reason. Otherwise, don’t mess yourself and throw it into the trash can.
    Thanks.

  • Fred

    Just some minor bugs.
    Fourth code listing (abstract class AbstractEntity) line 21 missing semicolumn on the end. Is: $this->$mutator($value) Should be: $this->$mutator($value);

    Code listing five (class Post) should implement method getId(). Just like the Comment and User classes do:
    public function getId() {
    return $this->_id;
    }
    On to reading the second part.

    • Alex Gervasio

      Thanks for catching those :-)

  • Fred

    But before I go. Changed HTML template just a little bit.

    Building a Domain Model in PHP

    PHPMaster.com

    title; ?>
    content; ?>
    comments): ?>

    comments as $comment): ?>

    user->name; ?> says:
    content; ?>

  • http://www.cellphoneaccessoriesdepot.com/ Dillip

    I am more comfortable with Zend framework.

    • Alex Gervasio

      Zend framework provides infrastructure, not business logic at all (and I’m so thankful for that). It’s up to you to implement the model.

  • http://25tolife.net/ Steve Again

    Secondarily, I love that you’ve made an abstract with __set and __get for your Models to inherit. Coming from a self-developed object model of a similar form, this was the very first thing I did in Zend, but wasn’t sure if t’were a Zend-like thing to be doing. Seems it is though. Hoorah! Thanks again :)

    • Alex Gervasio

      Hey Steve,
      Glad the post has been useful. In fact, I’m not quite a big fan of implementing too PHP magic, but in this particular case the “__set/()__get()” tandem does come in pretty handy for shortening calls to mutators/accessors. Thanks for the feedback.

  • http://uzaklab.com Wahyu Kristianto

    I would like to say thank you Alejandro for helping me to gain more knowledge :)

    • Alex Gervasio

      Thank you Wahyu for the compliments. Keep up the good work.

  • http://blog.mindplay.dk/ Rasmus Schultz

    To be truly agnostic, your domain model needs to reflect your transaction boundaries.

    In a nutshell, that means your Comment object cannot have a User property – only the ID of the User who wrote the Comment is physically a part of the Comment aggregate, and it would be unnatural to expect (for example) a cascading save of the the User’s name or e-mail address when you save a Comment.

    That fact is not reflected by your model, which means your ORM or data-mapper would need to be configured specifically for those entities, since otherwise there is no way to know whether to save the User object when saving a Comment. Even so, to a developer consuming your model API, the transaction boundaries are not apparent, unless your start poking through the ORM/mapper’s configuration. (The fact that the software can’t figure out what you want is always a sure indicator that it isn’t going to be anymore apparent to a person.)

    What’s more, loading a User object for every Comment you load, becomes obligatory. In this particular example, it’s unlikely you would want to load a Comment without loading the information about the User – but domain models in general should not force you to load domain objects that may not be necessary for the transaction you’re going to perform. A practical example would be posting a new Comment – you don’t need a User object to create a Comment, just the User’s ID, which you probably already have in a session variable – hence no need to load a User object to perform that transaction at all.

    I had a really hard time accepting this the first time I heard it, but we’ve been taught to build monolithic graph-like models that you can traverse across boundaries without thought. It simply isn’t right. Your life will be easier once you have this realization.

    I had a week-long debate with the very friendly (and patient) folks at the RavenDB forum, before this finally clicked for me – and I can never thank them enough! You can read the entire discussion and see how I came full circle here:

    https://groups.google.com/forum/#!topic/ravendb/WpD8OlUeTlY