Completed
Push — master ( 3300d1...dfaff5 )
by Dmitriy
02:23
created

Repository::triggerDelete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 11
rs 9.4285
cc 1
eloc 7
nc 1
nop 1
1
<?php
2
3
namespace T4webInfrastructure;
4
5
use ArrayObject;
6
use Zend\Db\TableGateway\TableGateway;
7
use Zend\Db\Sql\Select;
8
use Zend\Db\Sql\Expression;
9
use Zend\EventManager\EventManagerInterface;
10
use Zend\EventManager\Event;
11
use T4webDomainInterface\Infrastructure\CriteriaInterface;
12
use T4webDomainInterface\Infrastructure\RepositoryInterface;
13
use T4webDomainInterface\EntityInterface;
14
use T4webDomainInterface\EntityFactoryInterface;
15
use T4webInfrastructure\Event\EntityChangedEvent;
16
17
class Repository implements RepositoryInterface
18
{
19
    /**
20
     * @var string
21
     */
22
    protected $entityName;
23
24
    /**
25
     * @var CriteriaFactory
26
     */
27
    protected $criteriaFactory;
28
29
    /**
30
     * @var TableGateway
31
     */
32
    protected $tableGateway;
33
34
    /**
35
     * @var Mapper
36
     */
37
    protected $mapper;
38
39
    /**
40
     * @var EntityFactoryInterface
41
     */
42
    protected $entityFactory;
43
44
    /**
45
     * @var ArrayObject
46
     */
47
    protected $identityMap;
48
49
    /**
50
     * @var ArrayObject
51
     */
52
    protected $identityMapOriginal;
53
54
    /**
55
     * @var EventManagerInterface
56
     */
57
    protected $eventManager;
58
59
    /**
60
     * @var EntityChangedEvent
61
     */
62
    protected $event;
63
64
    /**
65
     * @var string
66
     */
67
    protected $tablePrimaryKey;
68
69
    /**
70
     * @param string                $entityName
71
     * @param CriteriaFactory       $criteriaFactory
72
     * @param TableGateway          $tableGateway
73
     * @param Mapper                $mapper
74
     * @param EntityFactoryInterface $entityFactory
75
     * @param EventManagerInterface $eventManager
76
     * @param string $tablePrimaryKey
77
     */
78
    public function __construct(
79
        $entityName,
80
        CriteriaFactory $criteriaFactory,
81
        TableGateway $tableGateway,
82
        Mapper $mapper,
83
        EntityFactoryInterface $entityFactory,
84
        EventManagerInterface $eventManager,
85
        $tablePrimaryKey = 'id'
86
    ) {
87
88
        $this->entityName = $entityName;
89
        $this->criteriaFactory = $criteriaFactory;
90
        $this->tableGateway = $tableGateway;
91
        $this->mapper = $mapper;
92
        $this->entityFactory = $entityFactory;
93
        $this->identityMap = new ArrayObject();
94
        $this->identityMapOriginal = new ArrayObject();
95
        $this->eventManager = $eventManager;
96
        $this->tablePrimaryKey = $tablePrimaryKey;
97
    }
98
99
    /**
100
     * @param EntityInterface $entity
101
     * @return EntityInterface|int|null
102
     */
103
    public function add(EntityInterface $entity)
104
    {
105
        $id = $entity->getId();
106
107
        if ($this->identityMap->offsetExists((int)$id)) {
108
            if (!$this->isEntityChanged($entity)) {
109
                return;
110
            }
111
112
            $e = $this->getEvent();
113
            $originalEntity = $this->identityMapOriginal->offsetGet($entity->getId());
114
            $e->setOriginalEntity($originalEntity);
115
            $e->setChangedEntity($entity);
116
117
            $this->triggerPreChanges($e);
118
119
            $result = $this->tableGateway->update($this->mapper->toTableRow($entity), [$this->tablePrimaryKey => $id]);
120
121
            $this->triggerChanges($e);
122
            $this->triggerAttributesChange($e);
123
124
            return $result;
125
        } else {
126
            $this->tableGateway->insert($this->mapper->toTableRow($entity));
127
128
            if (empty($id)) {
129
                $id = $this->tableGateway->getLastInsertValue();
130
                $entity->populate(compact('id'));
131
            }
132
133
            $this->toIdentityMap($entity);
134
135
            $this->triggerCreate($entity);
136
        }
137
138
        return $entity;
139
    }
140
141
    /**
142
     * @param EntityInterface $entity
143
     * @return int|null
144
     */
145
    public function remove(EntityInterface $entity)
146
    {
147
        $id = $entity->getId();
148
149
        if (empty($id)) {
150
            return;
151
        }
152
153
        $result = $this->tableGateway->delete([$this->tablePrimaryKey => $id]);
154
155
        $this->triggerDelete($entity);
156
157
        return $result;
158
    }
159
160
    /**
161
     * @param mixed $criteria
162
     * @return EntityInterface|null
163
     */
164
    public function find($criteria)
165
    {
166
        /** @var Select $select */
167
        $select = $criteria->getQuery();
168
169
        $select->limit(1)->offset(0);
170
        $result = $this->tableGateway->selectWith($select)->toArray();
171
172
        if (!isset($result[0])) {
173
            return;
174
        }
175
176
        $attributesValues = $this->mapper->fromTableRow($result[0]);
177
178
        $entity = $this->entityFactory->create($attributesValues);
179
180
        $this->toIdentityMap($entity);
181
182
        return $entity;
183
    }
184
185
    /**
186
     * @param mixed $id
187
     * @return EntityInterface|null
188
     */
189
    public function findById($id)
190
    {
191
        $criteria = $this->createCriteria();
192
        $criteria->equalTo('id', $id);
193
194
        return $this->find($criteria);
195
    }
196
197
    /**
198
     * @param mixed $criteria
199
     * @return EntityInterface[]
200
     */
201
    public function findMany($criteria)
202
    {
203
        /** @var Select $select */
204
        $select = $criteria->getQuery();
205
206
        $rows = $this->tableGateway->selectWith($select)->toArray();
207
208
        $attributesValues = $this->mapper->fromTableRows($rows);
209
210
        $entities = $this->entityFactory->createCollection($attributesValues);
211
212
        foreach ($entities as $entity) {
213
            $this->toIdentityMap($entity);
214
        }
215
216
        return $entities;
217
    }
218
219
    /**
220
     * @param mixed $criteria
221
     * @return int
222
     */
223
    public function count($criteria)
224
    {
225
        /** @var Select $select */
226
        $select = $criteria->getQuery();
227
        $select->columns(["row_count" => new Expression("COUNT(*)")]);
228
229
        $select->reset('limit');
230
        $select->reset('offset');
231
        $select->reset('order');
232
        $select->reset('group');
233
234
        $result = $this->tableGateway->selectWith($select)->toArray();
235
236
        if (!isset($result[0])) {
237
            return 0;
238
        }
239
240
        return $result[0]['row_count'];
241
    }
242
243
    /**
244
     * @param array $filter
245
     * @return CriteriaInterface
246
     */
247
    public function createCriteria(array $filter = [])
248
    {
249
        return $this->criteriaFactory->build($this->entityName, $filter);
250
    }
251
252
    /**
253
     * @param EntityInterface $entity
254
     */
255
    protected function toIdentityMap(EntityInterface $entity)
256
    {
257
        $this->identityMap->offsetSet($entity->getId(), $entity);
258
        $this->identityMapOriginal->offsetSet($entity->getId(), clone $entity);
259
    }
260
261
    /**
262
     * @param EntityInterface $changedEntity
263
     * @return bool
264
     */
265
    protected function isEntityChanged(EntityInterface $changedEntity)
266
    {
267
        $originalEntity = $this->identityMapOriginal->offsetGet($changedEntity->getId());
268
        return $changedEntity != $originalEntity;
269
    }
270
271
    /**
272
     * @return EntityChangedEvent
273
     */
274
    protected function getEvent()
275
    {
276
        if (null === $this->event) {
277
            $this->event = new EntityChangedEvent();
278
            $this->event->setTarget($this);
279
        }
280
281
        return $this->event;
282
    }
283
284
    /**
285
     * @param EntityInterface $createdEntity
286
     */
287
    protected function triggerCreate(EntityInterface&$createdEntity)
288
    {
289
        $this->eventManager->addIdentifiers(get_class($createdEntity));
290
291
        $event = new Event(
292
            sprintf('entity:%s:created', get_class($createdEntity)),
293
            $this,
294
            ['entity' => $createdEntity]
295
        );
296
        $this->eventManager->trigger($event);
297
298
        if ($event->getParam('entity') && $event->getParam('entity') instanceof EntityInterface) {
299
            $createdEntity = $event->getParam('entity');
300
        }
301
    }
302
303
    /**
304
     * @param EntityInterface $deletedEntity
305
     */
306
    protected function triggerDelete(EntityInterface $deletedEntity)
307
    {
308
        $this->eventManager->addIdentifiers(get_class($deletedEntity));
309
310
        $event = new Event(
311
            sprintf('entity:%s:deleted', get_class($deletedEntity)),
312
            $this,
313
            ['entity' => $deletedEntity]
314
        );
315
        $this->eventManager->trigger($event);
316
    }
317
318
    /**
319
     * @param EntityChangedEvent $e
320
     */
321
    protected function triggerChanges(EntityChangedEvent $e)
322
    {
323
        $changedEntity = $e->getChangedEntity();
324
        $this->eventManager->trigger($this->getEntityChangeEventName($changedEntity), $this, $e);
325
    }
326
327
    /**
328
     * @param EntityChangedEvent $e
329
     */
330
    protected function triggerPreChanges(EntityChangedEvent $e)
331
    {
332
        $changedEntity = $e->getChangedEntity();
333
        $this->eventManager->trigger($this->getEntityChangeEventName($changedEntity).':pre', $this, $e);
334
    }
335
336
    /**
337
     * @param EntityChangedEvent $e
338
     */
339
    protected function triggerAttributesChange(EntityChangedEvent $e)
340
    {
341
        $changedEntity = $e->getChangedEntity();
342
343
        $originalAttrs = $e->getOriginalEntity()->extract();
344
        $changedAttrs = $changedEntity->extract();
345
346
        foreach (array_keys(array_diff_assoc($originalAttrs, $changedAttrs)) as $attribute) {
347
            $this->eventManager->trigger($this->getAttributeChangeEventName($changedEntity, $attribute), $this, $e);
348
        }
349
    }
350
351
    /**
352
     * @param EntityInterface $changedEntity
353
     * @return string
354
     */
355
    protected function getEntityChangeEventName(EntityInterface $changedEntity)
356
    {
357
        return sprintf('entity:%s:changed', get_class($changedEntity));
358
    }
359
360
    /**
361
     * @param EntityInterface $changedEntity
362
     * @param $attributeName
363
     * @return string
364
     */
365
    protected function getAttributeChangeEventName(EntityInterface $changedEntity, $attributeName)
366
    {
367
        return sprintf('attribute:%s:%s:changed', get_class($changedEntity), $attributeName);
368
    }
369
}
370