I’m trying to learn about DDD and there’s a thing about the entities and repositories that I’m unable to understand.
From other questions here on SO I realized it is a bad habit to inject Repositories into Entities. But how to avoid injecting repository when I’m composing objects?
Let’s have simple situation – events and events application. This seems simple.
$event->add($application);
$eventRepository->save($event);
I believe the $application is an Entity so I believe there should be some $applicationRepository.
Does it mean, that I should inject $applicationRepository to $eventRepository to save the Event entity? Like
class eventRepository {
...
public function save(Event $event) {
...
foreach ($event->applications as $app) {
$this->applicationRepository->save($app);
}
...
}
}
Another solution that came to my mind is this:
$eventService->addAplication($event, $application);
class $eventService {
...
public function addApplication(Event $event, Application $app) {
// simple example of validation, something like $event->isAplyable()
if ($event->capacity > count($event->applications)) {
$this->applicationRepository->save($app);
$event->addApplication($app);
}
}
}
Is one method better than the other? Or did I completely messed it up?
One way to avoid an explicit call to an application repository is for the event repository to persists application instances that are associated with a given event. This is essentially the first option you propose, however depending on the persistence framework you use, the code could look a little different. For instance, some ORMs support persistence by reachability which means that if you’re persisting an event and the frameworks finds transient application instances reachable from the event, it will persist those too. In this case there is not need for an explicit application repository.
The idea at play here is that of aggregate roots. If an
Eventis an aggregate root and anApplicationis a constituent value object, then the event repository must be able to persist the entire object graph, including the associated application instances. DDD suggests one repository per aggregate root not necessarily per-entity.It may be the case that both
EventandApplicationare aggregate roots (ARs). In that case it is not advised to have direct object references between ARs, but to instead use identity references. In that case, your second example would apply, except in a slightly different form. The event service should be an application service which hosts specific use cases associated with events. One of those is adding an application. The difference is that theaddApplicationmethod should accept an event ID and application ID as arguments which it would then load from the respective repositories. It would also be able to explicitly persist both events and applications using their respective repositories.Take a look at Effective Aggregate Design by Vaughn Vernon for ideas on how to determine ARs in your domain.