1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the CRUDlex package. |
5
|
|
|
* |
6
|
|
|
* (c) Philip Lehmann-Böhm <[email protected]> |
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 CRUDlex; |
13
|
|
|
|
14
|
|
|
use League\Flysystem\FilesystemInterface; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* The abstract class for reading and writing data. |
18
|
|
|
*/ |
19
|
|
|
abstract class AbstractData |
20
|
|
|
{ |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* Return value on successful deletion. |
24
|
|
|
*/ |
25
|
|
|
const DELETION_SUCCESS = 0; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Return value on failed deletion due to existing references. |
29
|
|
|
*/ |
30
|
|
|
const DELETION_FAILED_STILL_REFERENCED = 1; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* Return value on failed deletion due to a failed before delete event. |
34
|
|
|
*/ |
35
|
|
|
const DELETION_FAILED_EVENT = 2; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* Holds the entity definition. |
39
|
|
|
* @var EntityDefinition |
40
|
|
|
*/ |
41
|
|
|
protected $definition; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Holds the filesystem. |
45
|
|
|
* @var FilesystemInterface |
46
|
|
|
*/ |
47
|
|
|
protected $filesystem; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Holds the events. |
51
|
|
|
* @var EntityEvents |
52
|
|
|
*/ |
53
|
|
|
protected $events; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Performs the actual deletion. |
57
|
|
|
* |
58
|
|
|
* @param Entity $entity |
59
|
|
|
* the id of the entry to delete |
60
|
|
|
* @param boolean $deleteCascade |
61
|
|
|
* whether to delete children and subchildren |
62
|
|
|
* |
63
|
|
|
* @return integer |
64
|
|
|
* true on successful deletion |
65
|
|
|
*/ |
66
|
|
|
abstract protected function doDelete(Entity $entity, $deleteCascade); |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* Creates an Entity from the raw data array with the field name |
70
|
|
|
* as keys and field values as values. |
71
|
|
|
* |
72
|
|
|
* @param array $row |
73
|
|
|
* the array with the raw data |
74
|
|
|
* |
75
|
|
|
* @return Entity |
76
|
|
|
* the entity containing the array data then |
77
|
|
|
*/ |
78
|
33 |
|
protected function hydrate(array $row) |
79
|
|
|
{ |
80
|
33 |
|
$fieldNames = $this->definition->getFieldNames(true); |
81
|
33 |
|
$entity = new Entity($this->definition); |
82
|
33 |
|
foreach ($fieldNames as $fieldName) { |
83
|
33 |
|
$entity->set($fieldName, $row[$fieldName]); |
84
|
|
|
} |
85
|
33 |
|
return $entity; |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* Enriches an entity with metadata: |
90
|
|
|
* id, version, created_at, updated_at |
91
|
|
|
* |
92
|
|
|
* @param mixed $id |
93
|
|
|
* the id of the entity to enrich |
94
|
|
|
* @param Entity $entity |
95
|
|
|
* the entity to enrich |
96
|
|
|
*/ |
97
|
33 |
|
protected function enrichEntityWithMetaData($id, Entity $entity) |
98
|
|
|
{ |
99
|
33 |
|
$entity->set('id', $id); |
100
|
33 |
|
$createdEntity = $this->get($entity->get('id')); |
101
|
33 |
|
$entity->set('version', $createdEntity->get('version')); |
102
|
33 |
|
$entity->set('created_at', $createdEntity->get('created_at')); |
103
|
33 |
|
$entity->set('updated_at', $createdEntity->get('updated_at')); |
104
|
33 |
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* Gets the many-to-many fields. |
108
|
|
|
* |
109
|
|
|
* @return array|\string[] |
110
|
|
|
* the many-to-many fields |
111
|
|
|
*/ |
112
|
34 |
|
protected function getManyFields() |
113
|
|
|
{ |
114
|
34 |
|
$fields = $this->definition->getFieldNames(true); |
115
|
|
|
return array_filter($fields, function($field) { |
116
|
34 |
|
return $this->definition->getType($field) === 'many'; |
117
|
34 |
|
}); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* Gets all form fields including the many-to-many-ones. |
122
|
|
|
* |
123
|
|
|
* @return array |
124
|
|
|
* all form fields |
125
|
|
|
*/ |
126
|
33 |
|
protected function getFormFields() |
127
|
|
|
{ |
128
|
33 |
|
$manyFields = $this->getManyFields(); |
129
|
33 |
|
$formFields = []; |
130
|
33 |
|
foreach ($this->definition->getEditableFieldNames() as $field) { |
131
|
33 |
|
if (!in_array($field, $manyFields)) { |
132
|
33 |
|
$formFields[] = $field; |
133
|
|
|
} |
134
|
|
|
} |
135
|
33 |
|
return $formFields; |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* Performs the cascading children deletion. |
140
|
|
|
* |
141
|
|
|
* @param integer $id |
142
|
|
|
* the current entities id |
143
|
|
|
* @param boolean $deleteCascade |
144
|
|
|
* whether to delete children and sub children |
145
|
|
|
* |
146
|
|
|
* @return integer |
147
|
|
|
* returns one of: |
148
|
|
|
* - AbstractData::DELETION_SUCCESS -> successful deletion |
149
|
|
|
* - AbstractData::DELETION_FAILED_STILL_REFERENCED -> failed deletion due to existing references |
150
|
|
|
* - AbstractData::DELETION_FAILED_EVENT -> failed deletion due to a failed before delete event |
151
|
|
|
*/ |
152
|
3 |
|
protected function deleteChildren($id, $deleteCascade) |
153
|
|
|
{ |
154
|
3 |
|
foreach ($this->definition->getChildren() as $childArray) { |
155
|
3 |
|
$childData = $this->definition->getService()->getData($childArray[2]); |
156
|
3 |
|
$children = $childData->listEntries([$childArray[1] => $id]); |
157
|
3 |
|
foreach ($children as $child) { |
158
|
2 |
|
$result = $childData->events->shouldExecute($child, 'before', 'delete'); |
159
|
2 |
|
if (!$result) { |
160
|
1 |
|
return static::DELETION_FAILED_EVENT; |
161
|
|
|
} |
162
|
2 |
|
$childData->doDelete($child, $deleteCascade); |
163
|
2 |
|
$childData->events->shouldExecute($child, 'after', 'delete'); |
164
|
|
|
} |
165
|
|
|
} |
166
|
3 |
|
return static::DELETION_SUCCESS; |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* Gets an array of reference ids for the given entities. |
171
|
|
|
* |
172
|
|
|
* @param array $entities |
173
|
|
|
* the entities to extract the ids |
174
|
|
|
* @param string $field |
175
|
|
|
* the reference field |
176
|
|
|
* |
177
|
|
|
* @return array |
178
|
|
|
* the extracted ids |
179
|
|
|
*/ |
180
|
23 |
|
protected function getReferenceIds(array $entities, $field) |
181
|
|
|
{ |
182
|
|
|
return array_map(function(Entity $entity) use ($field) { |
183
|
23 |
|
$id = $entity->get($field); |
184
|
23 |
|
return is_array($id) ? $id['id'] : $id; |
185
|
23 |
|
}, $entities); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Performs the persistence of the given entity as new entry in the datasource. |
190
|
|
|
* |
191
|
|
|
* @param Entity $entity |
192
|
|
|
* the entity to persist |
193
|
|
|
* |
194
|
|
|
* @return boolean |
195
|
|
|
* true on successful creation |
196
|
|
|
*/ |
197
|
|
|
abstract protected function doCreate(Entity $entity); |
|
|
|
|
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* Performs the updates of an existing entry in the datasource having the same id. |
201
|
|
|
* |
202
|
|
|
* @param Entity $entity |
203
|
|
|
* the entity with the new data |
204
|
|
|
* |
205
|
|
|
* @return boolean |
206
|
|
|
* true on successful update |
207
|
|
|
*/ |
208
|
|
|
abstract protected function doUpdate(Entity $entity); |
|
|
|
|
209
|
|
|
|
210
|
|
|
/** |
211
|
|
|
* Gets the events instance. |
212
|
|
|
* |
213
|
|
|
* @return EntityEvents |
214
|
|
|
* the events instance |
215
|
|
|
*/ |
216
|
13 |
|
public function getEvents() |
217
|
|
|
{ |
218
|
13 |
|
return $this->events; |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* Gets the entity with the given id. |
223
|
|
|
* |
224
|
|
|
* @param string $id |
225
|
|
|
* the id |
226
|
|
|
* |
227
|
|
|
* @return Entity |
228
|
|
|
* the entity belonging to the id or null if not existant |
229
|
|
|
* |
230
|
|
|
* @return void |
231
|
|
|
*/ |
232
|
|
|
abstract public function get($id); |
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* Gets a list of entities fullfilling the given filter or all if no |
236
|
|
|
* selection was given. |
237
|
|
|
* |
238
|
|
|
* @param array $filter |
239
|
|
|
* the filter all resulting entities must fulfill, the keys as field names |
240
|
|
|
* @param array $filterOperators |
241
|
|
|
* the operators of the filter like "=" defining the full condition of the field |
242
|
|
|
* @param integer|null $skip |
243
|
|
|
* if given and not null, it specifies the amount of rows to skip |
244
|
|
|
* @param integer|null $amount |
245
|
|
|
* if given and not null, it specifies the maximum amount of rows to retrieve |
246
|
|
|
* @param string|null $sortField |
247
|
|
|
* if given and not null, it specifies the field to sort the entries |
248
|
|
|
* @param boolean|null $sortAscending |
249
|
|
|
* if given and not null, it specifies that the sort order is ascending, |
250
|
|
|
* descending else |
251
|
|
|
* |
252
|
|
|
* @return Entity[] |
253
|
|
|
* the entities fulfilling the filter or all if no filter was given |
254
|
|
|
*/ |
255
|
|
|
abstract public function listEntries(array $filter = [], array $filterOperators = [], $skip = null, $amount = null, $sortField = null, $sortAscending = null); |
256
|
|
|
|
257
|
|
|
/** |
258
|
|
|
* Persists the given entity as new entry in the datasource. |
259
|
|
|
* |
260
|
|
|
* @param Entity $entity |
261
|
|
|
* the entity to persist |
262
|
|
|
* |
263
|
|
|
* @return boolean |
264
|
|
|
* true on successful creation |
265
|
|
|
*/ |
266
|
33 |
View Code Duplication |
public function create(Entity $entity) |
|
|
|
|
267
|
|
|
{ |
268
|
33 |
|
$result = $this->events->shouldExecute($entity, 'before', 'create'); |
269
|
33 |
|
if (!$result) { |
270
|
2 |
|
return false; |
271
|
|
|
} |
272
|
33 |
|
$result = $this->doCreate($entity); |
273
|
33 |
|
$this->events->shouldExecute($entity, 'after', 'create'); |
274
|
33 |
|
return $result; |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
/** |
278
|
|
|
* Updates an existing entry in the datasource having the same id. |
279
|
|
|
* |
280
|
|
|
* @param Entity $entity |
281
|
|
|
* the entity with the new data |
282
|
|
|
* |
283
|
|
|
* @return boolean |
284
|
|
|
* true on successful update |
285
|
|
|
*/ |
286
|
13 |
View Code Duplication |
public function update(Entity $entity) |
|
|
|
|
287
|
|
|
{ |
288
|
13 |
|
if (!$this->events->shouldExecute($entity, 'before', 'update')) { |
289
|
2 |
|
return false; |
290
|
|
|
} |
291
|
13 |
|
$result = $this->doUpdate($entity); |
292
|
13 |
|
$this->events->shouldExecute($entity, 'after', 'update'); |
293
|
13 |
|
return $result; |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
/** |
297
|
|
|
* Deletes an entry from the datasource. |
298
|
|
|
* |
299
|
|
|
* @param Entity $entity |
300
|
|
|
* the entity to delete |
301
|
|
|
* |
302
|
|
|
* @return integer |
303
|
|
|
* returns one of: |
304
|
|
|
* - AbstractData::DELETION_SUCCESS -> successful deletion |
305
|
|
|
* - AbstractData::DELETION_FAILED_STILL_REFERENCED -> failed deletion due to existing references |
306
|
|
|
* - AbstractData::DELETION_FAILED_EVENT -> failed deletion due to a failed before delete event |
307
|
|
|
*/ |
308
|
5 |
|
public function delete($entity) |
309
|
|
|
{ |
310
|
5 |
|
$result = $this->events->shouldExecute($entity, 'before', 'delete'); |
311
|
5 |
|
if (!$result) { |
312
|
2 |
|
return static::DELETION_FAILED_EVENT; |
313
|
|
|
} |
314
|
5 |
|
$result = $this->doDelete($entity, $this->definition->isDeleteCascade()); |
315
|
5 |
|
$this->events->shouldExecute($entity, 'after', 'delete'); |
316
|
5 |
|
return $result; |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
/** |
320
|
|
|
* Gets ids and names of a table. Used for building up the dropdown box of |
321
|
|
|
* reference type fields for example. |
322
|
|
|
* |
323
|
|
|
* @param string $entity |
324
|
|
|
* the entity |
325
|
|
|
* @param string $nameField |
326
|
|
|
* the field defining the name of the rows |
327
|
|
|
* |
328
|
|
|
* @return array |
329
|
|
|
* an array with the ids as key and the names as values |
330
|
|
|
*/ |
331
|
|
|
abstract public function getIdToNameMap($entity, $nameField); |
332
|
|
|
|
333
|
|
|
/** |
334
|
|
|
* Retrieves the amount of entities in the datasource fulfilling the given |
335
|
|
|
* parameters. |
336
|
|
|
* |
337
|
|
|
* @param string $table |
338
|
|
|
* the table to count in |
339
|
|
|
* @param array $params |
340
|
|
|
* an array with the field names as keys and field values as values |
341
|
|
|
* @param array $paramsOperators |
342
|
|
|
* the operators of the parameters like "=" defining the full condition of the field |
343
|
|
|
* @param boolean $excludeDeleted |
344
|
|
|
* false, if soft deleted entries in the datasource should be counted, too |
345
|
|
|
* |
346
|
|
|
* @return integer |
347
|
|
|
* the count fulfilling the given parameters |
348
|
|
|
*/ |
349
|
|
|
abstract public function countBy($table, array $params, array $paramsOperators, $excludeDeleted); |
350
|
|
|
|
351
|
|
|
/** |
352
|
|
|
* Checks whether a given set of ids is assigned to any entity exactly |
353
|
|
|
* like it is given (no subset, no superset). |
354
|
|
|
* |
355
|
|
|
* @param string $field |
356
|
|
|
* the many field |
357
|
|
|
* @param array $thatIds |
358
|
|
|
* the id set to check |
359
|
|
|
* @param string|null $excludeId |
360
|
|
|
* one optional own id to exclude from the check |
361
|
|
|
* |
362
|
|
|
* @return boolean |
363
|
|
|
* true if the set of ids exists for an entity |
364
|
|
|
*/ |
365
|
|
|
abstract public function hasManySet($field, array $thatIds, $excludeId = null); |
366
|
|
|
|
367
|
|
|
/** |
368
|
|
|
* Gets the EntityDefinition instance. |
369
|
|
|
* |
370
|
|
|
* @return EntityDefinition |
371
|
|
|
* the definition instance |
372
|
|
|
*/ |
373
|
79 |
|
public function getDefinition() |
374
|
|
|
{ |
375
|
79 |
|
return $this->definition; |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
/** |
379
|
|
|
* Creates a new, empty entity instance having all fields prefilled with |
380
|
|
|
* null or the defined value in case of fixed fields. |
381
|
|
|
* |
382
|
|
|
* @return Entity |
383
|
|
|
* the newly created entity |
384
|
|
|
*/ |
385
|
38 |
|
public function createEmpty() |
386
|
|
|
{ |
387
|
38 |
|
$entity = new Entity($this->definition); |
388
|
38 |
|
$fields = $this->definition->getEditableFieldNames(); |
389
|
38 |
|
foreach ($fields as $field) { |
390
|
38 |
|
$value = null; |
391
|
38 |
|
if ($this->definition->getType($field) == 'fixed') { |
392
|
36 |
|
$value = $this->definition->getField($field, 'value'); |
393
|
|
|
} |
394
|
38 |
|
$entity->set($field, $value); |
395
|
|
|
} |
396
|
38 |
|
$entity->set('id', null); |
397
|
38 |
|
return $entity; |
398
|
|
|
} |
399
|
|
|
|
400
|
|
|
|
401
|
|
|
} |
402
|
|
|
|
This check examines a number of code elements and verifies that they conform to the given naming conventions.
You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.