Сохранение объекта, являющегося частью агрегата

Допустим, у нас есть объект BankCard, являющийся частью Client Aggregate. Клиент может захотеть аннулировать свою банковскую карту.

class CancellBankCardCommandHandler
{
    public function Execute(CancelBankCardCommand $command)
    {
        $client = $this->_repository->get($command->clienId);
        $bankCard = $client->getBankCard($command->bankCardId);
        $bankCard->clientCancelsBankCard();

        $this->_repository->add($client);
    }
}

class BankCard implements Entity
{    
    // constructor and some other methods ...

    public function clientCancelsBankCard()
    {
        $this->apply(new BankCardWasCancelled($this->id);
    }
}

class Client implements AggregateRoot
{
    protected $_bankCards;

    public function getBankCard($bankCardId)
    {
       if (!array_key_exists($bankCardId, $this->_bankCards) {
           throw new DomainException('Bank card is not found!');
       }

       return $this->_bankCard[$bankCardId]);
    }        
}

Наконец, у нас есть экземпляр репозитория домена, который отвечает за хранение агрегатов.

class ClientRepository implements DomainRepository
{
     // methods omitted

     public function add($clientAggregate)
     {
         // here we somehow need to store BankCardWasCancelled event
         // which is a part of BankCard Entity     
     } 
}

Мой вопрос заключается в том, отвечает ли AggregateRoot за отслеживание событий своих сущностей или нет. Можно ли получить события Сущности, которая является частью Агрегата, из его Агрегата или нет?

Как на самом деле сохранить Клиента со всеми изменениями, внесенными в банковскую карту, сохранив ее целостность?


person Maksim Shcherbo    schedule 08.08.2014    source источник
comment
Я предполагаю, что точно так же, как вы не предоставляете общедоступные свойства и методы непосредственно своим дочерним объектам в совокупности, вы не должны раскрывать события. Я ожидаю, что ваш совокупный корень сможет подписаться на события вашего дочернего объекта, но если он захочет раскрыть эти события, он сделает это, вызвав новые события из совокупного корня.   -  person Adrian Thompson Phillips    schedule 08.08.2014
comment
если бы он хотел раскрыть это событие, он сделал бы это, вызвав новые события из корня агрегата. Правильно ли я понимаю, что в моем случае я должен реализовать метод на клиенте, который меняет банковскую карту? Клиент-›cancellBankCard($cardId); Если это так, то проблема в том, что вместо BankCard может быть очень большая Entity, в которой много бизнес-логики, однако это не может быть еще один AggregateRoot, потому что его граница согласованности полностью зависит от Client.   -  person Maksim Shcherbo    schedule 08.08.2014
comment
Что касается совокупного размера, это звучит так, как будто клиент и банковская карта(ы) должны быть каким-то образом связаны, а не быть частью совокупности клиента.   -  person Adrian Thompson Phillips    schedule 08.08.2014


Ответы (1)


Я бы сказал, что агрегат в целом отвечает за отслеживание произошедших с ним изменений. Механически это может быть «распределено» между совокупным корневым объектом и любыми другими объектами внутри агрегата или совокупного корневого объекта в качестве единственного регистратора или некоторой внешней единицы работы. Ваш выбор, на самом деле. Не зацикливайтесь на механике. Разные языки/парадигмы, разные способы реализации всего этого. Если что-то происходит с дочерней сущностью, просто считайте это изменением части агрегата и записывайте соответствующим образом.

person Yves Reynhout    schedule 18.08.2014