DDD, Doctrine2, Aggregates and ArrayCollection: how to isolate the domain model?
Asked Answered
B

1

7

I'm trying to work effectively with DDD and Doctrine2 on a project with lot of business logic.

I understand that we need decouple the domain objects from other concepts related to the system, i.e. in a layered architecture, "the domain layer" must be isolate from other layers, like the persistence layer/service (Doctrine2 for me).

But there is one thing it's hard to understand for me: in several code examples of DDD with Doctrine 2, aggregates in domain entities are managed with Doctrine ArrayCollection, I found this kind of code :

namespace Acme\Domain\Model\Users;

use Doctrine\Common\Collections\ArrayCollection;

class User {

     //...

    /**
    * Collection of Roles
    *
    * @var Collection of Roles
    */
    protected $roles;

    /**
    * Constructor.
    */
    public function __construct()
    {
        $this->createdAt = new \DateTime();
        $this->roles = new ArrayCollection();
    }

    public function getRoles()
    {        
        return $this->roles;
    }
//...
}

For me, this implementation create a high coupling between domain models and the persistence service, Doctrine2.

On the other hand, if DDD Entity and Doctrine Entity classes are decoupled, there is to many layers/classes, in my opinion.

What do you think? Is there a better way to avoid/handle this?

Bromley answered 27/8, 2013 at 8:14 Comment(1)
You mentioned "lots of business logic". Consider starting a new question focusing on just one business rule that you feel might benefit from DDD.Fortenberry
F
8

Don't be alarmed by the use of ArrayCollections. Notice that is in the Doctrine/Common namespace. It's just a little utility array wrapper with no particular ties to the Doctrine persistence layer. You could easily replace it with another array class.

The manual addresses this issue: https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#collections.

As far as decoupling goes, it is possible to do DDD modeling while limiting yourself to doctrine entities. It is very limiting and generally discouraged. So yep, you will probably need another layer.

It's difficult to justify the overhead of a pure DDD implementation in PHP.

Fortenberry answered 27/8, 2013 at 20:5 Comment(10)
Can you pls advise some concrete examples of what is limiting on Doctrine Entities from DDD modelling perspective and why it is discouraged? Also draft a bit how would you use "the another layer"? Thanks.Locket
No value objects. No nested objects. It's discouraged because you are supposed to design your domain model without worrying about how it will be persisted. The other layer means inserting some sort of service that will transfer your domain model objects into doctrine entities and vice versa. Basically, another mapping process.Fortenberry
This article: williamdurand.fr/2013/08/20/… is a not very successful attempt to deal with some of these problems.Fortenberry
Thanks for the response and the official documentation reference. This doc says : "You could even copy that class over to your project if you want to remove Doctrine from your project and all your domain classes will work the same as before.". It seems to be a good idea, but I'va never seen it in any projects ...Bromley
For DDD and Doctrine, I'm a bit confused, and right now, I would tend to say, as you, that a "pure" DDD implementation seems to be difficult with Doctrine2, which is more CRUD oriented (But some DDD principles can anyway help us better design our code, no? ) There are more blog ressources on the subject, but I haven't found complex doctrine2/symfony2 projects to illustrate implementation, naming and organization of code with DDD.Bromley
Doctrine 2 supports Value objects. I myself tried it on github here: github.com/dermo666/Alfa/blob/master/library/Domain/Invoice/… That is a class with value object MoneyValue. At work we are using Zend_Date for storing dates. The invoice class was just for playing around some basic DDD concepts, but as you can see there is no Doctrine2 specific code except for except for PrePersist and PreUpdate, but that can be done different way too - I was just evaluating that there.Locket
@Bromley - Finding a nice complex business rule that can be reasonably implemented in PHP and is worth the overhead of DDD is my problem as well. But yes, we can certainly apply some of the principles.Fortenberry
@Tomas Dermisek - I probably should have been more specific. D2 does not currently support values objects (except \DateTime) out of the box. I completely agree that you can do some great stuff with listeners. But not everything and it's basically adding another layer.Fortenberry
Value objects as embeddables are now supported since Doctrine ORM 2.5 see: doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/…Burin
Might be more accurate to say the Doctrine 2 ORM has very limited support for value objects. Not trying to knock Doctrine 2. I use it all the time. It's just not designed for DDD.Fortenberry

© 2022 - 2024 — McMap. All rights reserved.