Projector::projectEvents()   B
last analyzed

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(Action::UPDATE(), $readModel);
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(Action::NONE(), $readModel);
69
70
                    // project it
71
                    $this->projectEvents($projection, $eventStream->events());
72
                }
73
74
                if (count($readModels) == 0) {
75
                    // create the initial projection
76
                    $projection = new Projection(Action::NONE());
77
78
                    // project it
79
                    $this->projectEvents($projection, $eventStream->events());
80
                }
81
            }
82
        }
83
    }
84
85
    /**
86
     * @param Projection $projection
87
     * @param array      $events
88
     */
89
    protected function projectEvents(Projection $projection, array $events)
90
    {
91
        foreach ($events as $event) {
92
            $classParts = explode('\\', get_class($event));
93
            $method = 'project'.end($classParts);
94
95
            if (method_exists($this, $method)) {
96
                $this->$method($projection, $event);
97
            }
98
        }
99
100
        switch ($projection->action()) {
101
            case Action::CREATE():
102
            case Action::UPDATE():
103
                // the read model should be created/updated
104
                $this->persist($projection->readModel());
105
                break;
106
            case Action::REMOVE():
107
                // the read model should be removed
108
                $this->remove($projection->readModel());
109
                break;
110
        }
111
    }
112
113
    /**
114
     * @param ReadModelInterface $readModel
115
     */
116
    protected function persist(ReadModelInterface $readModel)
117
    {
118
        $this->repository->persist($readModel);
119
    }
120
121
    /**
122
     * @param ReadModelInterface $readModel
123
     */
124
    protected function remove(ReadModelInterface $readModel)
125
    {
126
        $this->repository->remove($readModel);
127
    }
128
129
    /**
130
     * @param IdInterface $writeModelId
131
     *
132
     * @return array
133
     */
134
    abstract protected function readModelsFromRepository(IdInterface $writeModelId);
135
136
    /**
137
     * @param WriteModelInterface $writeModel
138
     *
139
     * @return array
140
     */
141
    abstract protected function readModelsFromWriteModel(WriteModelInterface $writeModel);
142
143
    /**
144
     * @return string
145
     */
146
    abstract protected function writeModelClass();
147
148
    /**
149
     * {@inheritdoc}
150
     */
151
    public static function getSubscribedEvents()
152
    {
153
        return array(
154
            PostPersistEvent::class => array('onPostPersist', 250),
155
        );
156
    }
157
}
158