2
votes

In Symfony 3, how would you differentiate the following based on Domain Driven Design (DDD)?

  • Service (the one that is defined in config service file)
  • Doctrine Repository (\Doctrine\ORM\EntityRepository)
  • Entity (a class in entity folder)

I'm aware that doctrine is decoupled from Symfony (i.e. it can be completely omitted). But then which one is the repository in a Symfony project without Doctrine? Or perhaps Symfony (without Doctrine) is actually not really following DDD ?

Edit

I try to mock up a scenario below to make my question clearer

A controller has a function to return all available managers for a project

class ManagementController
    public function getAvailableManagers(Array $project)
    {
        ...
    }
}    

Available managers means that they have no projects on their hand and the project falls within their specialised domain (e.g. customer service, business relations, logistics, etc)

However due to poor design, the speciality domain is not stored in the database but instead needs to be called to a separate HR system via API call. Later on it will be integrated to the database

I would have thought (feel free to correct me) that the Manager should be a repository class because it currently get its information from 2 different sources. The question is ... should I use Doctrine Repository for this? Or maybe it should be just a normal entity or a perhaps a service?

class ReplacementInstructionRepository extends \Doctrine\ORM\EntityRepository
{
    private $id;
    private $name;
    private $speciality;
    private $projects;
}

I need a guide on how to split this. Thank you

Cheers,

2
What make you think that Symfony with Doctrine is following DDD? Most Symfony apps are crud apps. When applicable, you can follow some of the DDD principles using Symfony. Your question as written makes no sense to me. - Cerad
Thanks for the feedback,I have updated the question with sample scenario. Hopefully it will clear the confusion :) - Don Djoe

2 Answers

5
votes

Although I don't understand well the question, here you have some examples of projects applying DDD principles with Symfony.

https://github.com/PhpFriendsOfDdd/state-of-the-union/blob/master/README.md

EDIT

After your last description I think I can give a better answer :-).

I would say that the Specification Pattern fits well in your scenario. Specification Pattern allows you to keep business rules in your Domain layer. In this case you mentioned an important business rule:

Available managers means that they have no projects on their hand and the project falls within their specialised domain (e.g. customer service, business relations, logistics, etc)

In this case, you mentioned a poor design we need to deal with. In a greenfield project I would save the manager's specialised domain within the manager, so everything would live within the same Aggregate Root, the Manager.

In your case, I would integrate the external party (HR system) via Repository like you can see below:

nampespace xxx\infrastructure\persistence
class ManagersRepository
{
    public function __construct(HrApiClient $apiClient)
    {
        $this->apliClient = $apiClient;
    }

    public function findWithoutProjects()
    {
        $sqlQuery = //find all managers without project
        $managers = $this->execute($sqlQuery);
        foreach ($managers as $manager) {
            $projects = $this->apliClient->findProjectsOfManagerId($manager->id());
            $manager->specialisedIn($projects); //This should be done with reflection
        }

        return $managers;
    }

    public function selectSatisfying(Specification $specification)
    {
        return $specification->satisfyingElementsFrom($this);
    }
}

namespace xxx\Domain
class ManagersAvailableSpecification implements Specification
{
    public function __construct($aNewProject)
    {
        $this->aNewProject = $aNewProject;
    }

    public function isSatisfiedBy($manager)
    {
        // business rules here...
        if ($manager->isSpecialisedIn($this->aNewProject)) {
            return true;
        }

        return false;
    }

    public function satisfyingElementsFrom(ManagersRepository $managersRepository)
    {
        $managers = $managersRepository->findWithoutProjects();

        return array_filter(
            $managers,
            function (Manager $manager) {
                return $this->isSatisfiedBy($manager);
            }
        );
    }
}

Notice that the first class, as it is an concrete implementation of the repository (using MySql, Postgre, etc), lives in the infrastructure layer. While the second one, as it depends just on interfaces it lives in the Domain along with the business rules that defines an available manager.

Now you can have a Service like:

class FindAvailableManagersService
{
    private $managersRepository;

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

    public function execute(FindAvailableManagersRequest $request)
    {
        $managersAvailable = $this->managersRepository->selectSatisfying(
            new ManagersAvailableSpecification($request->project())
        );

        return $managersAvailable;
    }
}

Notice also that if in the future you migrate the specialized domains from the third party to your own database, you just need to modify one class but nothing else gets touched :-)

3
votes

The question is ... should I use Doctrine Repository for this?

I think this is the most classic misunderstanding related to DDD. The ORM respository and entity is completely different than the DDD repository and entity. They just have the same name but that's all, you should not confuse them.

The DDD entity lives in the domain and does not depend on classes outside of the domain. The DDD repository interface is defined in the domain and the implementation is in the infrastructure and can depend on other parts of the infrastructure. So to implement the DDD repository interface you can use an ORM repository if you want, but you can use completely different data storage solutions than relational databases, for example noSQL databases.