Completed
Push — master ( 84505b...5678fc )
by Ivannis Suárez
02:56
created

Projector::projectEvents()   B

Complexity

Conditions 6
Paths 12

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 8.5906
c 0
b 0
f 0
cc 6
eloc 14
nc 12
nop 2
1
<?php
2
3
/**
4
 * This file is part of the Cubiche package.
5
 *
6
 * Copyright (c) Cubiche
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Cubiche\Domain\EventSourcing\Projector;
13
14
use Cubiche\Core\Cqrs\ReadModelInterface;
15
use Cubiche\Core\Cqrs\WriteModelInterface;
16
use Cubiche\Domain\EventPublisher\DomainEventSubscriberInterface;
17
use Cubiche\Domain\EventSourcing\Event\PostPersistEvent;
18
use Cubiche\Domain\Model\IdInterface;
19
use Cubiche\Domain\Repository\QueryRepositoryInterface;
20
21
/**
22
 * Projector class.
23
 *
24
 * @author Ivannis Suárez Jerez <[email protected]>
25
 */
26
abstract class Projector implements DomainEventSubscriberInterface
27
{
28
    /**
29
     * @var QueryRepositoryInterface
30
     */
31
    protected $repository;
32
33
    /**
34
     * Projector constructor.
35
     *
36
     * @param QueryRepositoryInterface $repository
37
     */
38
    public function __construct(QueryRepositoryInterface $repository)
39
    {
40
        $this->repository = $repository;
41
    }
42
43
    /**
44
     * @param PostPersistEvent $event
45
     */
46
    public function onPostPersist(PostPersistEvent $event)
47
    {
48
        // skip if the aggregate is not my write model class
49
        if (is_a($event->aggregate(), $this->writeModelClass())) {
50
            $eventStream = $event->eventStream();
51
52
            // find all read models that exist for a given write model
53
            $readModels = $this->readModelsFromRepository($event->aggregate()->id());
54
            foreach ($readModels as $readModel) {
55
                // create the initial projection
56
                $projection = new Projection($readModel, Action::UPDATE());
57
58
                // project it
59
                $this->projectEvents($projection, $eventStream->events());
60
            }
61
62
            // there is not read models for the given write model?
63
            if (count($readModels) == 0) {
64
                // create all read models of a given write model
65
                $readModels = $this->readModelsFromWriteModel($event->aggregate());
66
                foreach ($readModels as $readModel) {
67
                    // create the initial projection
68
                    $projection = new Projection($readModel, Action::NONE());
69
70
                    // project it
71
                    $this->projectEvents($projection, $eventStream->events());
72
                }
73
            }
74
        }
75
    }
76
77
    /**
78
     * @param Projection $projection
79
     * @param array      $events
80
     */
81
    protected function projectEvents(Projection $projection, array $events)
82
    {
83
        foreach ($events as $event) {
84
            $classParts = explode('\\', get_class($event));
85
            $method = 'project'.end($classParts);
86
87
            if (method_exists($this, $method)) {
88
                $this->$method($projection, $event);
89
            }
90
        }
91
92
        switch ($projection->action()) {
93
            case Action::CREATE():
94
            case Action::UPDATE():
95
                // the read model should be created/updated
96
                $this->persist($projection->readModel());
97
                break;
98
            case Action::REMOVE():
99
                // the read model should be removed
100
                $this->remove($projection->readModel());
101
                break;
102
        }
103
    }
104
105
    /**
106
     * @param ReadModelInterface $readModel
107
     */
108
    protected function persist(ReadModelInterface $readModel)
109
    {
110
        $this->repository->persist($readModel);
111
    }
112
113
    /**
114
     * @param ReadModelInterface $readModel
115
     */
116
    protected function remove(ReadModelInterface $readModel)
117
    {
118
        $this->repository->remove($readModel);
119
    }
120
121
    /**
122
     * @param IdInterface $writeModelId
123
     *
124
     * @return array
125
     */
126
    abstract protected function readModelsFromRepository(IdInterface $writeModelId);
127
128
    /**
129
     * @param WriteModelInterface $writeModel
130
     *
131
     * @return array
132
     */
133
    abstract protected function readModelsFromWriteModel(WriteModelInterface $writeModel);
134
135
    /**
136
     * @return string
137
     */
138
    abstract protected function writeModelClass();
139
140
    /**
141
     * {@inheritdoc}
142
     */
143
    public static function getSubscribedEvents()
144
    {
145
        return array(
146
            PostPersistEvent::class => array('onPostPersist', 250),
147
        );
148
    }
149
}
150