Domain-Driven Design: Sample Application


Last updated: 15 Feb, 2010

Part 1: Domain-Driven Design and MVC Architectures
Part 2: Domain-Driven Design: Data Access Strategies
Part 3: Domain-Driven Design: The Repository

Some of the Domain-driven design concepts explained above are applied in this sample application.

Directory Structure

app/
    config/
    controllers/
        UserController.php
    domain/
        entities/
            User.php
            UserProfile.php
        repositories/
            UserRepository.php
    views/
lib/
public/

The domain layer should be well separated from the other layers and it should have few dependencies on the framework you are using.

User Entity

The User and UserProfile objects have a one-to-one relationship and form an Aggregate. An Aggregate is as a collection of related objects that have references between each other. Within an Aggregate there’s always an Aggregate Root (parent Entity), in this case User:

class User
{
    private $id;
    private $name;

    /* @var UserProfile */
    private $profile;

    public function __construct($id, $name)
    {
        $this->id = $id;
        $this->name = $name;
    }

    public function setProfile(UserProfile $profile)
    {
        $this->profile = $profile;
    }

    public function getProfile()
    {
        return $this->profile;
    }
}

class UserProfile
{
    private $id;

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

Users Collection

A collection is simply an object that groups multiple elements into a single unit.

class Users
{
    private $elements = array();

    public function __construct(array $users)
    {
        foreach ($users as $user) {
            if (!($user instanceof User)) {
                throw new Exception();
            }
            $this->elements[] = $user;
        }
    }

    public function toArray()
    {
        return $this->elements;
    }
}

User DAO

The UserDAO class allows data access mechanisms to change independently of the code that uses the data:

interface UserDao
{
    public function find($id);
    public function findAll();
}

class UserDatabaseDao implements UserDao
{
    public function find($id)
    {
        $dataSource = Zf_Orm_Manager::getInstance()->getDataSource()
        $db = $dataSource->getConnection('slave');
        $query = $db->select()->from('user')->where('id = ?', $id);
        return $db->fetchRow($query);
    }

    public function findAll()
    {
        ...
        return $db->fetchAll($query);
    }
}

interface UserProfileDao
{
    public function find($id);
    public function findByUserId($id);
}

class UserProfileDatabaseDao implements UserProfileDao
{
    public function find($id)
    {
        ...
    }

    public function findByUserId($id)
    {
        $dataSource = Zf_Orm_Manager::getInstance()->getDataSource()
        $db = $dataSource->getConnection('slave');
        $query = $db->select()->from('user_profile')->where('user_id = ?', $id);
        return $db->fetchRow($query);
    }
}

User Repository

A Repository is basically a collection of Aggregate Roots. Collections are used to store, retrieve and manipulate Entities and Value objects, however, object management is beyond the scope of this post. The Repository object can inject dependencies on demand, making the instantiation process inexpensive.

class UserRepository
{
    /* @var UserDatabaseDao */
    private $userDao;

    /* @var UserProfileDatabaseDao */
    private $userProfileDao;

    public function __construct()
    {
    	$this->userDao = new UserDatabaseDao();
    	$this->userProfileDao = new UserProfileDatabaseDao();
    }

    public function find($id)
    {
        $row = $this->userDao->find($id);
        $user = new User($row['id'], $row['name']);

        $row = $this->userProfileDao->findByUserId($id);
        if (isset($row['id'])) {
            $profile = new UserProfile($row['id']);
            $user->setProfile($profile);
        }

        return $user;
    }

    public function findAll()
    {
        $users = array();
        $rows = $this->userDao->findAll();
        foreach ($rows as $row) {
            $users[] = new User($row['id'], $row['name']);
        }
        return new Users($users);
    }
}

Usage:

$repository = new UserRepository();
$user = $repository->find(1);
$profile = $user->getProfile();
$users = $repository->findAll();

Source Code

http://svn.fedecarg.com/repo/Zf/Orm

Links

If you’re interested in learning more about Domain-driven design, I recommend the following articles:

Domain Driven Design and Development In Practice
Domain-Driven Design in an Evolving Architecture


42 responses to “Domain-Driven Design: Sample Application”

  1. Is there any reason why the “entities” need extend a class? The whole movement in Java was to turn away from entity beans to using POJOs. This also makes your business objects more portable. They should have *no* dependency on anything. The responsibility of “hydrating” those objects and persisting them should be the responsibility of a third part transparent object. This is the way its done in EJB3. Unfortunately, in the PHP world, nothing like this exists. The closest things are the Outlet and Repose projects, which don’t seem to be moving very quickly, and Doctrine 2.0 which doesn’t exists yet.

  2. @Avi Yes, I agree with you, but PHP doesn’t support annotations, such as Configurable, Entity and OneToOne. I’m simulating marker annotations using OO techniques. You could, however, use a DI container, add EntityManager and EntityManagerFactory, and create your own persistence package. I believe Symfony 2 is going that direction. The combination of Doctrine and DDD makes DAO’s redundant.

  3. Great article, I am implementing something similar with zend framework and doctrine..

  4. In your final example of the User Repository, getUserDao() and getUserProfileDao() are handled by the __call() function.

    But where do you inject the actual DB adapter into the UserDao and UserProfileDao?

  5. I’m extending Zf_Persistence_Db_Adapter and getting the adapter from the registry. However, using Zend_Registry is not the best solution, as it introduces a hidden dependency.

  6. Thanks for the tutorial series.

    One thing that confuses me in this example is the purpose of abstracting the data layer.
    I.e. Why is it good to do it?

    Lets say , for example, that you suddenly decide to add a new property to Project_Model_User. You are going to have to also add a new column to the db table.

    Or, say, you come to realise that you have three types of user and hence need to make the user ID referenced by two fields UserTypeId+UserId to ensure they are unique within the app.

    Or, say you suddenly decide to use xml to persist the data – the model and app still have to change to accommodate.

    If a change in the db leads to a change in the model classes and a change in the model classes leads to a change in the db/persistance layer, why are we so desperate to keep them so separated?

  7. Federico,
    Thanks for the explanation great series btw. I am learning a lot.

    Another question

    You give the example of:

    $repo = new Project_Model_User_Repository();
    $user = $repo->getUserById(1);
    $profile = $user->getProfile();
    $users = $repo->getUsers();

    for retrieving a single user and a collection of users.

    But could you show an example of how you would use your current framework to to create a new user or delete a user?

    Would you instantiate a new user entity and populate it and pass it to createUser() on the UserRepository, or would you pass a array of new user data to createUser() on the UserRepository?

  8. Hi Ronny,

    When you abstract you do it to reduce details so that other developers can focus on a few concepts at a time. Keep in mind that software architectures are constantly evolving and changing. I guess abstraction helps deal with those changes in a more efficient way.

  9. Hi Matt,

    I would have an addUser() method in the Repository and a save() or saveFromArray() method in the DAO:

    $array = array(‘name’=>’Jim’);
    $user = new Project_Model_User($array);

    $repo = new Project_Model_User_Repository();
    $repo->addUser($user);

    And use the Repository to pass the data to the DAO:

    $this->getUserDao()->save($user);
    $this->getUserDao()->saveFromArray($array);

  10. > If a change in the db leads to a change in the model classes and a change in the model classes leads to a change in the db/persistance layer, why are we so desperate to keep them so separated?

    Hi Ronny, I’ve just realized that your question remained unanswered :)

    If you remove the properties field from the Project_Model_User class, then you are not defining any class properties, and you are free to pass n amount of array elements via the constructor.

  11. > Hi Matt,

    I would have an addUser() method in the Repository and a save() or saveFromArray() method in the DAO:

    …..

    Hey Federico,

    With this method of adding and saving users. Where do propose to handle input validation? (ie. “This username already exists” or “Invalid email adddress”).

    Within the Project_Model_User or Project_Model_User_Repository?

  12. Any chance of you writing a beginner level tutorials about domain driven design that doesn’t require the zend framework? Not suggesting any particular framework but I’ve read all your articles and many others and I still can’t fully grasp it all (and zend framework doesn’t work on my ancient servers). I’d like to see something that goes into the core concepts using generic and easily understandable code that even a novice can then take and re-implement in their framework of choice.

  13. Thanks for your answer Federico.

    Since writing those previous questions I have read the Domain Driven Design Book (Eric Evans). Now, when I come back to this tutorial series I’m reading it in a whole new light and these explanations are even more useful as i try to carve out my fist DDD bits of PHP code. So, thanks for pointing me in the direction of DDD- its a revelation.

    Amongst that, gushing, compliment is the answer menoknow’s question – read that DDD book for good intro – its worth it.

  14. Hi Federico,

    In your example you have a profile Object stored in the User Aggregate. As I understand it, you are currently always loading the profile data in the user object when you retreive a user object. Suppose this User Aggregate would extend and thus, would have extra entity’s/value objects related to it. In this example you would always load all the data for the User Aggregate but this seems not the best solution because you will create overhead (i.e. extra query’s to a database for example) where the data you are querying is not necesarry.
    It seems more logical to just load the “basic” data in the user aggregate and only load the extra data when it’s necesarry (i.e. only load the profile data when you actually call it $user->getProfile()). However when I follow this approach I would add something like this to the getProfile method:
    if(null == ($this->_profile)) {
    //retreive data and store it in profile field
    }
    return $this_profile;
    This implementation however is not valid because you would couple a db class or a repository to the User class.
    How would you solve this issue, or am I mistaking on this one?

  15. Hi Federico,
    First of all, your tutorials provide great insight into Domain Driven Design and Thanks.

    I am also interesting in finding out how to implement what Bert has mentioned above.

  16. Federico,

    I think we are talking about two different things. The profile is indeed an entitiy but that was not really my question.
    Suppose the Person Aggregate would have a Profile entity, an Address Entity, … and some other stuff related to the Person Aggregate. How would you manage the loading of those objects.
    Would you load all the entities of the Aggregate at once (so in fact when you retreive the aggregate from the repository, you load all the data). This implementation seems to have lots of overhead when you only need one field from the root Aggregate for example.
    Another implementation could be that you only initiate the main properties of the root Aggregate (=Person) and that you would only load the entities like Profile or Address when you need them (so in fact you would lazy load these entities with a proxy pattern for example).
    What is your opinion on this

  17. Gotcha. I guess that, if you are working with DAOs, there are different ways of doing it. You already mentioned 2 of them I think. You could also have a repository that represents the relationship between both entities, for example, UserProfileRepository. And then use UserProfileDAO to query the database, join the User and Profile tables and return the data to the repository so it can populate the User and Profile objects.

    I don’t know if this is allowed in DDD, but I haven’t develop a Repository that manages this complexity for me yet.

  18. Federico,

    As far as I know, only Aggregate Root is recomended to have a Repository. I’m really stuck with such implementation details. DDD concepts are obviosly interesting, but I’ve lots of misunderstandings relative to implementation :\

  19. […] Por otra parte los mappers heredarán de Zend_Mapper. A esta nueva orientación se le denomina Domain Driven Design (DDD). Estoy siguiendo el tema con este libro y la verdad es que todo tiene muy buena pinta, aunque […]

  20. Hi,

    I’m confused about domain and service, can someone provide a sample code for domain and service in action?

    Thanks

  21. Repositories are not part of the Service Layer, they are part of the Domain Layer. The Repository provides a higher level of data manipulation, and acts as a link between the Domain and Persistence Layers (Entity – Repository – DAO).

    Service classes are not part of the Domain or Persistence Layers and therefore do not provide methods to access data, such as finders. Finders are usually found in the Repository.

  22. Well, its purpose is to hold methods that implement business logic. They do not provide methods to access data.

  23. Others said business logic should be in the domain and only those logic that are not fit to any entity or value objects should be placed in the service.

  24. Here’s an example:

    class User {
        private $id; 
        private $name;
        private $password;
    
        public function setId($id)
        public function getId()
        public function setName($name)
        public function getName()
        public function setPassword($password)
        public function getPassword()
    }
    
    class UserRepository {
        public function find($id) 
    }
    
    class UserService {
        public function authenticate(User $user)
    }
    
  25. In DDD, Repository also serves as collection of aggregate roots, User and UserProfile domain objects are related and therefore constituting an aggregate where User domain is the aggregate root, why then there’s another Repository for UserProfile?

    Thanks

  26. The Repository is used to separate the domain object from its persistence mechanism.

  27. @Federico, my question is why there’s need for another Repository for UserProfile object? Repositories are provided for Aggregate Roots and UserProfile is not an Aggregate root but a child entity o User object.

  28. Hi Jeboy,

    > why there’s need for another Repository for UserProfile object?

    A Repository can also be used to manage entities and provide a higher level of data manipulation. In this example, the UserProfile object needs to persist some data, reason why it uses the Repository pattern to separate the persistence mechanism. However, it is up to you to decide which object is going to persist data and how it is going to do it. Some languages/frameworks, for example, use the Interceptor pattern instead of the Repository.

  29. I think the persistence of UserProfile object is User object’s responsibility since it is member of its aggregates, an aggregate which is stored in the Repository. Meaning storing/saving the User aggregate is also taking care of persisting its related objects, though saving this aggregate in storage is lil’ bit tedious without an ORM but still it complies to the purpose and design of the Repository which is a collection of Aggregate Roots and abstracting Persistence layer from the Domain.

  30. You are right. One Repository per Aggregate Root. In this case User is the Aggregate Root that controls access to the UserProfile.

  31. UserDAO interface/implementation seems to be unnecessary.
    It can’t be used without the repository and the repository can’t be used without some specific DAO implementation. What we need really is just
    repository interface and implementation. Agree?

  32. No. You need to separate a data resource’s client interface from its data access mechanisms.

  33. Let’s say I want another implementation of UserDAO, that would load users via http from a remote web service. I would have to convert all data that I load from that new data source into “rows” like if they were from flat db tables. This is not flexible at all. The logic of searching and loading data may vary from repository to repository, from data source to data source.

    The thing you really need is an interface like UserRepositoryInterface that would always return domain objects, and you may rely on it in your services.

  34. Im wondering if anybody has a good solution to handle database relationships with Domain Driven Design. Im complety lost at the moment about how to handle them.

  35. Hi Tom,
    There’s just one decent solution at the moment. More or less universal. Doctrine 2.

    Nothing else is even close.

  36. I was afraid of that answer, Im not a big fan of doctrine. The idea of using yaml, xml to make the mappings happen seems odd.

    I would rather code the mappings. Also there is to much magic going on in doctrine. And it has some perfomance impact.

Leave a comment