Publishing a Domain Event from an Entity

Continuing with the example of a new user who has been registered in our application, let's see how the corresponding Domain Event can be published:

class User
{
protected $userId;
protected $email ;
protected $password;

public function __construct(UserId $userId, $email, $password)
{
$this->setUserId($userId);
$this->setEmail($email);
$this->setPassword($password);

DomainEventPublisher::instance()->publish(
new UserRegistered($this->userId)
);
}

// ...
}

As seen in the example, when the User is created, a new UserRegistered Event is published. It's done in the Entity constructor and not outside because, with this approach, it's easier to keep our Domain consistent; any client who creates a new User will publish its corresponding Event. On the other hand, this makes it a bit more complex to use an infrastructure that needs to create a User Entity without using its constructor. For example, Doctrine uses the serialize and unserialize technique that recreates an object without calling its constructor. However, if you have to create your own, this isn't going to be as easy as in Doctrine.

In general, constructing an object from plain data such as an array is called hydration. Let's see an easy approach to building a new User fetched from a database. First of all, let's extract the Domain Event publication to its own method by applying the Factory Method pattern.

According to Wikipedia:

The template method pattern is a behavioral design pattern that defines the program skeleton of an algorithm in an operation, deferring some steps to subclasses:
class User
{
protected $userId;
protected $email ;
protected $password;

public function __construct(UserId $userId, $email, $password)
{
$this->setUserId($userId);
$this->setEmail($email);
$this->setPassword($password);
$this->publishEvent();

}

protected function publishEvent()
{
DomainEventPublisher::instance()->publish(
new UserRegistered($this->userId)
);
}

// ...
}

Now, let's extend our current User with a new infrastructure Entity that will do the job for us. The trick here is make publishEvent do nothing so that the Domain Event isn't published:

class CustomOrmUser extends User
{
protected function publishEvent()
{

}

public static function fromRawData($data)
{
return new self(
new UserId($data['user_id']),
$data['email'],
$data['password']
);
}
}

Remember to be careful with this approach; you might fetch invalid objects from the persistence mechanism, as Domain rules change all the time. Another approach without using the parent constructor could be the following:

class CustomOrmUser extends User
{
public function __construct()
{
}

public static function fromRawData($data)
{
$user = new self();
$user->userId = new UserId($data['user_id']);
$user->email = $data['email'];
$user->password = $data['password'];

return $user;
}
}

With this approach, the parent constructor isn't called and User attributes must be protected. Other alternatives are Reflection, passing flags in the constructor, using a proxy library like Proxy-Manager, or using an ORM like Doctrine.

Other Strategy for Publishing Domain Events
As you can see in the previous example, we're using a static class for publishing our Domain Events. Other people, as an alternative, and especially when using Event Sourcing, will suggest that Entities hold all the fired Events internally within a field. In order to access all the Events, a getter is used in the Aggregate. This is also a valid approach. However, sometimes it's a bit difficult to keep track of which Entities have fired an Event. It can also be difficult to fire Events from places that aren't just Entities, example: Domain Services. On the plus side, testing if an Entity has fired an Event is much easier.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset