I'm trying to implement DDD in php. I have an entity called message that has related fromFieldId. I want to validate that this fromField exists in database when it is set on message, I do not want to burden caller with this validation as it happens in many places in my code. However from what I understand in DDD entity should not call repositories? How would I handle this in DDD?
I want something like this:
class MessageEntity{
public function setFromFieldId($fromFieldId){
if(!$this->fromFieldRepository->isExists($fromFieldId)){
// throw some exception
}
$this->fromFieldId = $fromFieldId;
}
}
I think what you need is a DomainService
in terms of DDD.
From Eric Evans Domain-Driven Design:
When a significant process or transformation in the domain is not a natural responsibility of an ENTITY or VALUE OBJECT, add an operation to the model as standalone interface declared as a SERVICE. Define the interface in terms of the language of the model and make sure the operation name is part of the UBIQUITOUS LANGUAGE. Make the SERVICE stateless.
In your case, if setting a field only once is a proper concept in your ubiquitous language, then an approach could be:
class SettingFieldOnceService
{
private $repository;
public function __construct(Repository $repository)
{
$this->repository = $repository;
}
public function setFieldInEntity($field, $entity)
{
if ($anotherEntity = $this->repository->findByField($field)) {
throw new DomainException("...");
}
$entity->setField($field);
}
}
You could simply load the FromField AR from a repository and pass the entire instance to the Message AR, but only hold onto the id.
Pseudo-code:
MessageApplicationService {
setFromFieldId(messageId, fromFieldId) {
fromField = fromFieldRepository.findById(fromFieldId);
//You could have a null check for fromField here
//or call a method that throws automatically
//e.g. findExistingById(). You could also prevent
//null from being passed in message.setFromField
message = messageRepository.findById(messageId);
message.setFromField(fromField); //only holds onto the id
}
}