1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace T4webInfrastructure; |
4
|
|
|
|
5
|
|
|
use ArrayObject; |
6
|
|
|
use Zend\Db\TableGateway\TableGateway; |
7
|
|
|
use Zend\Db\Sql\Select; |
8
|
|
|
use T4webDomainInterface\Infrastructure\RepositoryInterface; |
9
|
|
|
use T4webDomainInterface\Infrastructure\CriteriaInterface; |
10
|
|
|
use T4webDomainInterface\EntityInterface; |
11
|
|
|
use T4webDomainInterface\EntityFactoryInterface; |
12
|
|
|
|
13
|
|
|
class FinderAggregateRepository implements RepositoryInterface |
14
|
|
|
{ |
15
|
|
|
/** |
16
|
|
|
* @var TableGateway |
17
|
|
|
*/ |
18
|
|
|
private $tableGateway; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* @var Mapper |
22
|
|
|
*/ |
23
|
|
|
private $mapper; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @var EntityFactoryInterface |
27
|
|
|
*/ |
28
|
|
|
private $entityFactory; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* @var RepositoryInterface |
32
|
|
|
*/ |
33
|
|
|
private $entityRepository; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* @var RepositoryInterface[] |
37
|
|
|
*/ |
38
|
|
|
private $relatedRepository; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* @var array |
42
|
|
|
*/ |
43
|
|
|
private $relationsConfig; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* @var ArrayObject[] |
47
|
|
|
*/ |
48
|
|
|
private $with; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* FinderAggregateRepository constructor. |
52
|
|
|
* @param TableGateway $tableGateway |
53
|
|
|
* @param Mapper $mapper |
54
|
|
|
* @param EntityFactoryInterface $entityFactory |
55
|
|
|
* @param RepositoryInterface $entityRepository |
56
|
|
|
* @param RepositoryInterface[] $relatedRepository |
57
|
|
|
* @param array $relationsConfig |
58
|
|
|
*/ |
59
|
|
|
public function __construct( |
60
|
|
|
TableGateway $tableGateway, |
61
|
|
|
Mapper $mapper, |
62
|
|
|
EntityFactoryInterface $entityFactory, |
63
|
|
|
RepositoryInterface $entityRepository, |
64
|
|
|
array $relatedRepository, |
65
|
|
|
array $relationsConfig) |
66
|
|
|
{ |
67
|
|
|
$this->tableGateway = $tableGateway; |
68
|
|
|
$this->mapper = $mapper; |
69
|
|
|
$this->entityFactory = $entityFactory; |
70
|
|
|
$this->entityRepository = $entityRepository; |
71
|
|
|
$this->relatedRepository = $relatedRepository; |
72
|
|
|
$this->relationsConfig = $relationsConfig; |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
public function findWith($entityName) |
76
|
|
|
{ |
77
|
|
|
if (!isset($this->relatedRepository[$entityName])) { |
78
|
|
|
throw new \RuntimeException(get_class($this) . ": related $entityName repository not exists"); |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
$this->with[$entityName] = new ArrayObject(); |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* @param mixed $criteria |
86
|
|
|
* @return EntityInterface|null |
87
|
|
|
*/ |
88
|
|
|
public function find($criteria) |
89
|
|
|
{ |
90
|
|
|
if (empty($this->with)) { |
91
|
|
|
return $this->entityRepository->find($criteria); |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** @var Select $select */ |
95
|
|
|
$select = $criteria->getQuery(); |
96
|
|
|
|
97
|
|
|
$select->limit(1)->offset(0); |
98
|
|
|
$result = $this->tableGateway->selectWith($select)->toArray(); |
99
|
|
|
|
100
|
|
|
if (!isset($result[0])) { |
101
|
|
|
return; |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
$row = $result[0]; |
105
|
|
|
|
106
|
|
View Code Duplication |
foreach ($this->with as $relatedEntityName => $relatedEntityIds) { |
|
|
|
|
107
|
|
|
$relatedField = $this->getRelatedField($relatedEntityName); |
108
|
|
|
|
109
|
|
|
if (!isset($row[$relatedField])) { |
110
|
|
|
throw new \RuntimeException(get_class($this) . ": relation field $relatedEntityName not fetched"); |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
if (!in_array($row[$relatedField], (array)$relatedEntityIds)) { |
114
|
|
|
$relatedEntityIds->append($row[$relatedField]); |
115
|
|
|
} |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
$relatedEntities = []; |
119
|
|
View Code Duplication |
foreach ($this->with as $relatedEntityName => $relatedEntityIds) { |
|
|
|
|
120
|
|
|
$criteria = $this->relatedRepository[$relatedEntityName]->createCriteria(['id.in' => (array)$relatedEntityIds]); |
121
|
|
|
$relatedEntities[$relatedEntityName] = $this->relatedRepository[$relatedEntityName]->findMany($criteria); |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
$relatedField = $this->getRelatedField($relatedEntityName); |
|
|
|
|
125
|
|
|
|
126
|
|
|
$entityArgs = [ |
127
|
|
|
'data' => $this->mapper->fromTableRow($row) |
128
|
|
|
]; |
129
|
|
|
|
130
|
|
View Code Duplication |
foreach ($this->relationsConfig as $entityName => $joinRule) { |
|
|
|
|
131
|
|
|
if (isset($relatedEntities[$entityName])) { |
132
|
|
|
if (isset($relatedEntities[$entityName][$row[$relatedField]])) { |
133
|
|
|
$entityArgs['aggregateItems'][] = $relatedEntities[$entityName][$row[$relatedField]]; |
134
|
|
|
} else { |
135
|
|
|
$entityArgs['aggregateItems'][] = null; |
136
|
|
|
} |
137
|
|
|
} else { |
138
|
|
|
$entityArgs['aggregateItems'][] = null; |
139
|
|
|
} |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
$entity = $this->entityFactory->create($entityArgs); |
143
|
|
|
|
144
|
|
|
$this->with = null; |
|
|
|
|
145
|
|
|
|
146
|
|
|
return $entity; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* @param mixed $criteria |
151
|
|
|
* @return EntityInterface[] |
152
|
|
|
*/ |
153
|
|
|
public function findMany($criteria) |
154
|
|
|
{ |
155
|
|
|
if (empty($this->with)) { |
156
|
|
|
return $this->entityRepository->findMany($criteria); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/** @var Select $select */ |
160
|
|
|
$select = $criteria->getQuery(); |
161
|
|
|
|
162
|
|
|
$rows = $this->tableGateway->selectWith($select)->toArray(); |
163
|
|
|
|
164
|
|
View Code Duplication |
foreach ($rows as $row) { |
|
|
|
|
165
|
|
|
foreach ($this->with as $relatedEntityName => $relatedEntityIds) { |
166
|
|
|
$relatedField = $this->getRelatedField($relatedEntityName); |
167
|
|
|
|
168
|
|
|
if (!isset($row[$relatedField])) { |
169
|
|
|
throw new \RuntimeException(get_class($this) . ": relation field $relatedEntityName not fetched"); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
if (!in_array($row[$relatedField], (array)$relatedEntityIds)) { |
173
|
|
|
$relatedEntityIds->append($row[$relatedField]); |
174
|
|
|
} |
175
|
|
|
} |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
$relatedEntities = []; |
179
|
|
View Code Duplication |
foreach ($this->with as $relatedEntityName => $relatedEntityIds) { |
|
|
|
|
180
|
|
|
$criteria = $this->relatedRepository[$relatedEntityName]->createCriteria(['id.in' => (array)$relatedEntityIds]); |
181
|
|
|
$relatedEntities[$relatedEntityName] = $this->relatedRepository[$relatedEntityName]->findMany($criteria); |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
$entitiesArgs = []; |
185
|
|
|
foreach ($rows as &$row) { |
186
|
|
|
$relatedField = $this->getRelatedField($relatedEntityName); |
|
|
|
|
187
|
|
|
|
188
|
|
|
$entityArgs = [ |
189
|
|
|
'data' => $this->mapper->fromTableRow($row) |
190
|
|
|
]; |
191
|
|
|
|
192
|
|
View Code Duplication |
foreach ($this->relationsConfig as $entityName => $joinRule) { |
|
|
|
|
193
|
|
|
if (isset($relatedEntities[$entityName])) { |
194
|
|
|
if (isset($relatedEntities[$entityName][$row[$relatedField]])) { |
195
|
|
|
$entityArgs['aggregateItems'][] = $relatedEntities[$entityName][$row[$relatedField]]; |
196
|
|
|
} else { |
197
|
|
|
$entityArgs['aggregateItems'][] = null; |
198
|
|
|
} |
199
|
|
|
} else { |
200
|
|
|
$entityArgs['aggregateItems'][] = null; |
201
|
|
|
} |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
$entitiesArgs[] = $entityArgs; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
$entities = $this->entityFactory->createCollection($entitiesArgs); |
208
|
|
|
|
209
|
|
|
$this->with = null; |
|
|
|
|
210
|
|
|
|
211
|
|
|
return $entities; |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* @param mixed $id |
216
|
|
|
* @return EntityInterface|null |
217
|
|
|
*/ |
218
|
|
|
public function findById($id) |
219
|
|
|
{ |
220
|
|
|
$criteria = $this->createCriteria(); |
221
|
|
|
$criteria->equalTo('id', $id); |
222
|
|
|
|
223
|
|
|
return $this->find($criteria); |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
private function getRelatedField($entityName) |
227
|
|
|
{ |
228
|
|
|
if (!isset($this->relationsConfig[$entityName])) { |
229
|
|
|
throw new \RuntimeException(get_class($this) . ": relation $entityName not exists"); |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
list($table, $field) = explode('.', $this->relationsConfig[$entityName][0]); |
|
|
|
|
233
|
|
|
|
234
|
|
|
return $field; |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
/** |
238
|
|
|
* @param mixed $criteria |
239
|
|
|
* @return int |
240
|
|
|
*/ |
241
|
|
|
public function count($criteria) |
242
|
|
|
{ |
243
|
|
|
return $this->entityRepository->count($criteria); |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* @param array $filter |
248
|
|
|
* @return CriteriaInterface |
249
|
|
|
*/ |
250
|
|
|
public function createCriteria(array $filter = []) |
251
|
|
|
{ |
252
|
|
|
return $this->entityRepository->createCriteria($filter); |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
/** |
256
|
|
|
* @param EntityInterface $entity |
257
|
|
|
* @return EntityInterface|int|null |
258
|
|
|
*/ |
259
|
|
|
public function add(EntityInterface $entity) |
260
|
|
|
{ |
261
|
|
|
throw new \RuntimeException(get_class($this) . ' cannot adding'); |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
/** |
265
|
|
|
* @param EntityInterface $entity |
266
|
|
|
* @return void |
267
|
|
|
*/ |
268
|
|
|
public function remove(EntityInterface $entity) |
269
|
|
|
{ |
270
|
|
|
throw new \RuntimeException(get_class($this) . ' cannot removing'); |
271
|
|
|
} |
272
|
|
|
} |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.