Completed
Push — master ( 7d5501...c81d83 )
by Philip
02:27
created

CRUDData::performOnFiles()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 3
eloc 5
nc 3
nop 3
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 Symfony\Component\HttpFoundation\Request;
15
use Symfony\Component\HttpFoundation\Response;
16
17
use CRUDlex\CRUDEntityDefinition;
18
use CRUDlex\CRUDEntity;
19
20
/**
21
 * The abstract class for reading and writing data.
22
 */
23
abstract class CRUDData {
24
25
    /**
26
     * Return value on successful deletion.
27
     */
28
    const DELETION_SUCCESS = 0;
29
30
    /**
31
     * Return value on failed deletion due to existing references.
32
     */
33
    const DELETION_FAILED_STILL_REFERENCED = 1;
34
35
    /**
36
     * Return value on failed deletion due to a failed before delete event.
37
     */
38
    const DELETION_FAILED_EVENT = 2;
39
40
    /**
41
     * Holds the {@see CRUDEntityDefinition} entity definition.
42
     */
43
    protected $definition;
44
45
    /**
46
     * Holds the {@see CRUDFileProcessorInterface} file processor.
47
     */
48
    protected $fileProcessor;
49
50
    /**
51
     * Holds the events.
52
     */
53
    protected $events;
54
55
    /**
56
     * Performs the actual deletion.
57
     *
58
     * @param CRUDEntity $entity
59
     * the id of the entry to delete
60
     *
61
     * @param boolean $deleteCascade
62
     * whether to delete children and subchildren
63
     *
64
     * @return integer
65
     * true on successful deletion
66
     */
67
    /**
68
     * {@inheritdoc}
69
     */
70
    abstract protected function doDelete(CRUDEntity $entity, $deleteCascade);
71
72
    /**
73
     * Creates an {@see CRUDEntity} from the raw data array with the field name
74
     * as keys and field values as values.
75
     *
76
     * @param array $row
77
     * the array with the raw data
78
     *
79
     * @return CRUDEntity
80
     * the entity containing the array data then
81
     */
82
    protected function hydrate(array $row) {
83
        $fieldNames = $this->definition->getFieldNames();
84
        $entity = new CRUDEntity($this->definition);
85
        foreach ($fieldNames as $fieldName) {
86
            $entity->set($fieldName, $row[$fieldName]);
87
        }
88
        return $entity;
89
    }
90
91
    /**
92
     * Executes the event chain of an entity.
93
     *
94
     * @param CRUDEntity $entity
95
     * the entity having the event chain to execute
96
     * @param string $moment
97
     * the "moment" of the event, can be either "before" or "after"
98
     * @param string $action
99
     * the "action" of the event, can be either "create", "update" or "delete"
100
     *
101
     * @return boolean
102
     * true on successful execution of the full chain or false if it broke at
103
     * any point (and stopped the execution)
104
     */
105
    protected function executeEvents(CRUDEntity $entity, $moment, $action) {
106
        if ($this->events !== null && array_key_exists($moment.'.'.$action, $this->events)) {
107
            foreach ($this->events[$moment.'.'.$action] as $event) {
108
                $result = $event($entity);
109
                if (!$result) {
110
                    return false;
111
                }
112
            }
113
        }
114
        return true;
115
    }
116
117
    /**
118
     * Executes a function for each file field of this entity.
119
     *
120
     * @param CRUDEntity $entity
121
     * the just created entity
122
     * @param string $entityName
123
     * the name of the entity as this class here is not aware of it
124
     * @param function $function
125
     * the function to perform, takes $entity, $entityName and $field as parameter
126
     */
127
    protected function performOnFiles(CRUDEntity $entity, $entityName, $function) {
128
        $fields = $this->definition->getEditableFieldNames();
129
        foreach ($fields as $field) {
130
            if ($this->definition->getType($field) == 'file') {
131
                $function($entity, $entityName, $field);
132
            }
133
        }
134
    }
135
136
    /**
137
     * Adds an event to fire for the given parameters. The event function must
138
     * have this signature:
139
     * function (CRUDEntity $entity)
140
     * and has to return true or false.
141
     * The events are executed one after another in the added order as long as
142
     * they return "true". The first event returning "false" will stop the
143
     * process.
144
     *
145
     * @param string $moment
146
     * the "moment" of the event, can be either "before" or "after"
147
     * @param string $action
148
     * the "action" of the event, can be either "create", "update" or "delete"
149
     * @param anonymous function $function
150
     * the event function to be called if set
151
     */
152
    public function pushEvent($moment, $action, $function) {
153
        $events = isset($this->events[$moment.'.'.$action]) ? $this->events[$moment.'.'.$action] : array();
154
        $events[] = $function;
155
        $this->events[$moment.'.'.$action] = $events;
156
    }
157
158
159
    /**
160
     * Removes and returns the latest event for the given parameters.
161
     *
162
     * @param string $moment
163
     * the "moment" of the event, can be either "before" or "after"
164
     * @param string $action
165
     * the "action" of the event, can be either "create", "update" or "delete"
166
     *
167
     * @return anonymous function
168
     * the popped event or null if no event was available.
169
     */
170
    public function popEvent($moment, $action) {
171
        if (array_key_exists($moment.'.'.$action, $this->events)) {
172
            return array_pop($this->events[$moment.'.'.$action]);
173
        }
174
        return null;
175
    }
176
177
178
    /**
179
     * Gets the entity with the given id.
180
     *
181
     * @param string $id
182
     * the id
183
     *
184
     * @return CRUDEntity
185
     * the entity belonging to the id or null if not existant
186
     */
187
    abstract public function get($id);
188
189
    /**
190
     * Gets a list of entities fullfilling the given filter or all if no
191
     * selection was given.
192
     *
193
     * @param array $filter
194
     * the filter all resulting entities must fulfill, the keys as field names
195
     * @param array $filterOperators
196
     * the operators of the filter like "=" defining the full condition of the field
197
     * @param integer $skip
198
     * if given and not null, it specifies the amount of rows to skip
199
     * @param integer $amount
200
     * if given and not null, it specifies the maximum amount of rows to retrieve
201
     * @param string $sortField
202
     * if given and not null, it specifies the field to sort the entries
203
     * @param boolean $sortAscending
204
     * if given and not null, it specifies that the sort order is ascending,
205
     * descending else
206
     *
207
     * @return array
208
     * the entities fulfilling the filter or all if no filter was given
209
     */
210
    abstract public function listEntries(array $filter = array(), array $filterOperators = array(), $skip = null, $amount = null, $sortField = null, $sortAscending = null);
211
212
    /**
213
     * Persists the given entity as new entry in the datasource.
214
     *
215
     * @param CRUDEntity $entity
216
     * the entity to persist
217
     *
218
     * @return boolean
219
     * true on successful creation
220
     */
221
    abstract public function create(CRUDEntity $entity);
222
223
    /**
224
     * Updates an existing entry in the datasource having the same id.
225
     *
226
     * @param CRUDEntity $entity
227
     * the entity with the new data
228
     */
229
    abstract public function update(CRUDEntity $entity);
230
231
    /**
232
     * Deletes an entry from the datasource having the given id.
233
     *
234
     * @param CRUDEntity $entity
235
     * the id of the entry to delete
236
     *
237
     * @return integer
238
     * returns one of:
239
     * - CRUDData::DELETION_SUCCESS -> successful deletion
240
     * - CRUDData::DELETION_FAILED_STILL_REFERENCED -> failed deletion due to existing references
241
     * - CRUDData::DELETION_FAILED_EVENT -> failed deletion due to a failed before delete event
242
     */
243
    public function delete($entity) {
244
        return $this->doDelete($entity, $this->definition->isDeleteCascade());
245
    }
246
247
    /**
248
     * Gets ids and names of a table. Used for building up the dropdown box of
249
     * reference type fields.
250
     *
251
     * @param string $table
252
     * the table
253
     * @param string nameField
254
     * the field defining the name of the rows
255
     *
256
     * @return array
257
     * an array with the ids as key and the names as values
258
     */
259
    abstract public function getReferences($table, $nameField);
260
261
    /**
262
     * Retrieves the amount of entities in the datasource fulfilling the given
263
     * parameters.
264
     *
265
     * @param string $table
266
     * the table to count in
267
     * @param array $params
268
     * an array with the field names as keys and field values as values
269
     * @param array $paramsOperators
270
     * the operators of the parameters like "=" defining the full condition of the field
271
     * @param bool $excludeDeleted
272
     * false, if soft deleted entries in the datasource should be counted, too
273
     *
274
     * @return int
275
     * the count fulfilling the given parameters
276
     */
277
    abstract public function countBy($table, array $params, array $paramsOperators, $excludeDeleted);
278
279
    /**
280
     * Adds the id and name of referenced entities to the given entities. Each
281
     * reference field is before the raw id of the referenced entity and after
282
     * the fetch, it's an array with the keys id and name.
283
     *
284
     * @param array $entities
285
     * the entities to fetch the references for
286
     */
287
    abstract public function fetchReferences(array &$entities = null);
288
289
    /**
290
     * Gets the {@see CRUDEntityDefinition} instance.
291
     *
292
     * @return CRUDEntityDefinition
293
     * the definition instance
294
     */
295
    public function getDefinition() {
296
        return $this->definition;
297
    }
298
299
    /**
300
     * Creates a new, empty entity instance having all fields prefilled with
301
     * null or the defined value in case of fixed fields.
302
     *
303
     * @return CRUDEntity
304
     * the newly created entity
305
     */
306
    public function createEmpty() {
307
        $entity = new CRUDEntity($this->definition);
308
        $fields = $this->definition->getEditableFieldNames();
309
        foreach ($fields as $field) {
310
            $value = null;
311
            if ($this->definition->getType($field) == 'fixed') {
312
                $value = $this->definition->getFixedValue($field);
313
            }
314
            $entity->set($field, $value);
315
        }
316
        $entity->set('id', null);
317
        return $entity;
318
    }
319
320
    /**
321
     * Creates the uploaded files of a newly created entity.
322
     *
323
     * @param Request $request
324
     * the HTTP request containing the file data
325
     * @param CRUDEntity $entity
326
     * the just created entity
327
     * @param string $entityName
328
     * the name of the entity as this class here is not aware of it
329
     */
330
    public function createFiles(Request $request, CRUDEntity $entity, $entityName) {
331
        $fileProcessor = $this->fileProcessor;
332
        $this->performOnFiles($entity, $entityName, function($entity, $entityName, $field) use ($fileProcessor, $request) {
0 ignored issues
show
Documentation introduced by
function ($entity, $enti...$entityName, $field); } is of type object<Closure>, but the function expects a object<CRUDlex\function>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
333
            $fileProcessor->createFile($request, $entity, $entityName, $field);
334
        });
335
    }
336
337
    /**
338
     * Updates the uploaded files of an updated entity.
339
     *
340
     * @param Request $request
341
     * the HTTP request containing the file data
342
     * @param CRUDEntity $entity
343
     * the updated entity
344
     * @param string $entityName
345
     * the name of the entity as this class here is not aware of it
346
     */
347
    public function updateFiles(Request $request, CRUDEntity $entity, $entityName) {
348
        $fileProcessor = $this->fileProcessor;
349
        $this->performOnFiles($entity, $entityName, function($entity, $entityName, $field) use ($fileProcessor, $request) {
0 ignored issues
show
Documentation introduced by
function ($entity, $enti...$entityName, $field); } is of type object<Closure>, but the function expects a object<CRUDlex\function>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
350
            $fileProcessor->updateFile($request, $entity, $entityName, $field);
351
        });
352
    }
353
354
    /**
355
     * Deletes a specific file from an existing entity.
356
     *
357
     * @param CRUDEntity $entity
358
     * the entity to delete the file from
359
     * @param string $entityName
360
     * the name of the entity as this class here is not aware of it
361
     * @param string $field
362
     * the field of the entity containing the file to be deleted
363
     */
364
    public function deleteFile(CRUDEntity $entity, $entityName, $field) {
365
        $this->fileProcessor->deleteFile($entity, $entityName, $field);
366
    }
367
368
    /**
369
     * Deletes all files of an existing entity.
370
     *
371
     * @param CRUDEntity $entity
372
     * the entity to delete the files from
373
     * @param string $entityName
374
     * the name of the entity as this class here is not aware of it
375
     */
376
    public function deleteFiles(CRUDEntity $entity, $entityName) {
377
        $fileProcessor = $this->fileProcessor;
378
        $this->performOnFiles($entity, $entityName, function($entity, $entityName, $field) use ($fileProcessor) {
0 ignored issues
show
Documentation introduced by
function ($entity, $enti...$entityName, $field); } is of type object<Closure>, but the function expects a object<CRUDlex\function>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
379
            $fileProcessor->deleteFile($entity, $entityName, $field);
380
        });
381
    }
382
383
    /**
384
     * Renders (outputs) a file of an entity. This includes setting headers
385
     * like the file size, mimetype and name, too.
386
     *
387
     * @param CRUDEntity $entity
388
     * the entity to render the file from
389
     * @param string $entityName
390
     * the name of the entity as this class here is not aware of it
391
     * @param string $field
392
     * the field of the entity containing the file to be rendered
393
     *
394
     * @return Response
395
     * the HTTP response, likely to be a streamed one
396
     */
397
    public function renderFile(CRUDEntity $entity, $entityName, $field) {
398
        return $this->fileProcessor->renderFile($entity, $entityName, $field);
399
    }
400
401
}
402