Completed
Push — master ( fb3e68...baf824 )
by Philip
02:33
created

CRUDEntity::populateViaRequest()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 13
rs 9.2
cc 4
eloc 9
nc 4
nop 1
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
16
use CRUDlex\CRUDEntityDefinition;
17
use CRUDlex\CRUDData;
18
19
/**
20
 * Represents a single set of data in field value pairs like the row in a
21
 * database. Depends of course on the {@see CRUDData} implementation being used.
22
 * With this objects, the data is passed arround and validated.
23
 */
24
class CRUDEntity {
25
26
    /**
27
     * The {@see CRUDEntityDefinition} defining how this entity looks like.
28
     */
29
    protected $definition;
30
31
    /**
32
     * Holds the key value data of the entity.
33
     */
34
    protected $entity = array();
35
36
    /**
37
     * Validates the given field for the required constraint.
38
     *
39
     * @param string $field the field to validate
40
     * @param array &$errors the error collecting array
41
     * @param boolean &$valid the validation flag
42
     */
43
    private function validateRequired($field, &$errors, &$valid) {
44
        if ($this->definition->isRequired($field) && !$this->definition->getFixedValue($field) &&
45
            (!array_key_exists($field, $this->entity)
46
            || $this->entity[$field] === null
47
            || $this->entity[$field] === '')) {
48
            $errors[$field]['required'] = true;
49
            $valid = false;
50
        }
51
    }
52
53
    /**
54
     * Validates the given field for the unique constraint.
55
     *
56
     * @param string $field the field to validate
57
     * @param CRUDData $data the data instance to work with
58
     * @param array &$errors the error collecting array
59
     * @param boolean &$valid the validation flag
60
     */
61
    private function validateUnique($field, CRUDData $data, &$errors, &$valid) {
62
        if ($this->definition->isUnique($field) && array_key_exists($field, $this->entity) && $this->entity[$field]) {
63
            $params = array($field => $this->entity[$field]);
64
            $paramsOperators = array($field => '=');
65
            if ($this->entity['id'] !== null) {
66
                $params['id'] = $this->entity['id'];
67
                $paramsOperators['id'] = '!=';
68
            }
69
            $amount = intval($data->countBy($this->definition->getTable(), $params, $paramsOperators, true));
70
            if ($amount > 0) {
71
                $errors[$field]['unique'] = true;
72
                $valid = false;
73
            }
74
        }
75
    }
76
77
    /**
78
     * Validates the given field for the set type.
79
     *
80
     * @param string $field the field to validate
81
     * @param array &$errors the error collecting array
82
     * @param boolean &$valid the validation flag
83
     */
84
    private function validateSet($field, &$errors, &$valid) {
85
        $type = $this->definition->getType($field);
86
        if ($type == 'set' && $this->entity[$field]) {
87
            $setItems = $this->definition->getSetItems($field);
88
            if (!in_array($this->entity[$field], $setItems)) {
89
                $errors[$field]['input'] = true;
90
                $valid = false;
91
            }
92
        }
93
    }
94
95
    /**
96
     * Validates the given field for the int type.
97
     *
98
     * @param string $field the field to validate
99
     * @param array &$errors the error collecting array
100
     * @param boolean &$valid the validation flag
101
     */
102 View Code Duplication
    private function validateInt($field, &$errors, &$valid) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
103
        $type = $this->definition->getType($field);
104
        if ($type == 'int' && $this->entity[$field] !== '' && $this->entity[$field] !== null && (string)(int)$this->entity[$field] != $this->entity[$field]) {
105
            $errors[$field]['input'] = true;
106
            $valid = false;
107
        }
108
    }
109
110
    /**
111
     * Validates the given field for the float type.
112
     *
113
     * @param string $field the field to validate
114
     * @param array &$errors the error collecting array
115
     * @param boolean &$valid the validation flag
116
     */
117 View Code Duplication
    private function validateFloat($field, &$errors, &$valid) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
118
        $type = $this->definition->getType($field);
119
        if ($type == 'float' && $this->entity[$field] !== '' && $this->entity[$field] !== null && (string)(float)$this->entity[$field] != $this->entity[$field]) {
120
            $errors[$field]['input'] = true;
121
            $valid = false;
122
        }
123
    }
124
125
    /**
126
     * Validates the given field for the date type.
127
     *
128
     * @param string $field the field to validate
129
     * @param array &$errors the error collecting array
130
     * @param boolean &$valid the validation flag
131
     */
132
    private function validateDate($field, &$errors, &$valid) {
133
        $type = $this->definition->getType($field);
134
        if ($type == 'date' && $this->entity[$field] && \DateTime::createFromFormat('Y-m-d', $this->entity[$field]) === false) {
135
            $errors[$field]['input'] = true;
136
            $valid = false;
137
        }
138
    }
139
140
    /**
141
     * Validates the given field for the datetime type.
142
     *
143
     * @param string $field the field to validate
144
     * @param array &$errors the error collecting array
145
     * @param boolean &$valid the validation flag
146
     */
147
    private function validateDateTime($field, &$errors, &$valid) {
148
        $type = $this->definition->getType($field);
149
        if ($type == 'datetime' && $this->entity[$field] &&
150
            \DateTime::createFromFormat('Y-m-d H:i', $this->entity[$field]) === false &&
151
            \DateTime::createFromFormat('Y-m-d H:i:s', $this->entity[$field]) === false) {
152
            $errors[$field]['input'] = true;
153
            $valid = false;
154
        }
155
    }
156
157
    /**
158
     * Validates the given field for the reference type.
159
     *
160
     * @param string $field the field to validate
161
     * @param CRUDData $data the data instance to work with
162
     * @param array &$errors the error collecting array
163
     * @param boolean &$valid the validation flag
164
     */
165
    private function validateReference($field, CRUDData $data, &$errors, &$valid) {
166
        $type = $this->definition->getType($field);
167
        if ($type == 'reference' && $this->entity[$field] !== '' && $this->entity[$field] !== null) {
168
            $params = array('id' => $this->entity[$field]);
169
            $paramsOperators = array('id' => '=');
170
            $amount = $data->countBy($this->definition->getReferenceTable($field), $params, $paramsOperators, false);
171
            if ($amount == 0) {
172
                $errors[$field]['input'] = true;
173
                $valid = false;
174
            }
175
        }
176
    }
177
178
    /**
179
     * Constructor.
180
     *
181
     * @param CRUDEntityDefinition $definition
182
     * the definition how this entity looks
183
     */
184
    public function __construct(CRUDEntityDefinition $definition) {
185
        $this->definition = $definition;
186
    }
187
188
    /**
189
     * Sets a field value pair of this entity.
190
     *
191
     * @param string $field
192
     * the field
193
     * @param mixed $value
194
     * the value
195
     */
196
    public function set($field, $value) {
197
        $this->entity[$field] = $value;
198
    }
199
200
    /**
201
     * Gets the value of a field.
202
     *
203
     * @param string $field
204
     * the field
205
     *
206
     * @return mixed
207
     * null on invalid field, an int if the definition says that the
208
     * type of the field is an int, a boolean if the field is a bool or
209
     * else the raw value
210
     */
211
    public function get($field) {
212
213
        if ($this->definition->getFixedValue($field) !== null) {
214
            return $this->definition->getFixedValue($field);
215
        }
216
217
        if (!array_key_exists($field, $this->entity)) {
218
            return null;
219
        }
220
        $value = $this->entity[$field];
221
222
        switch ($this->definition->getType($field)) {
223
            case 'int':
224
                $value = $value !== '' && $value !== null ? intval($value) : null;
225
                break;
226
            case 'float':
227
                $value = $value !== '' && $value !== null ? floatval($value) : null;
228
                break;
229
            case 'bool':
230
                $value = $value && $value !== '0';
231
                break;
232
        }
233
        return $value;
234
    }
235
236
    /**
237
     * Gets the entity definition.
238
     *
239
     * @return CRUDEntityDefinition
240
     * the definition
241
     */
242
    public function getDefinition() {
243
        return $this->definition;
244
    }
245
246
    /**
247
     * Validates the entity against the definition.
248
     *
249
     * @param CRUDData $data
250
     * the data access instance used for counting things
251
     *
252
     * @return array
253
     * an array with the fields "valid" and "errors"; valid provides a quick
254
     * check whether the given entity passes the validation and errors is an
255
     * array with all fields as keys and arrays as values; this field arrays
256
     * contain three keys: required, unique and input; each of them represents
257
     * with a boolean whether the input is ok in that way; if "required" is
258
     * true, the field wasn't set, unique means the uniqueness of the field in
259
     * the datasource and input is used to indicate whether the form of the
260
     * value is correct (a valid int, date, depending on the type in the
261
     * definition)
262
     */
263
    public function validate(CRUDData $data) {
264
265
        $fields = $this->definition->getEditableFieldNames();
266
        $errors = array();
267
        $valid = true;
268
        foreach ($fields as $field) {
269
            $errors[$field] = array('required' => false, 'unique' => false, 'input' => false);
270
271
            $this->validateRequired($field, $errors, $valid);
272
            $this->validateUnique($field, $data, $errors, $valid);
273
274
            $this->validateSet($field, $errors, $valid);
275
            $this->validateInt($field, $errors, $valid);
276
            $this->validateFloat($field, $errors, $valid);
277
            $this->validateDate($field, $errors, $valid);
278
            $this->validateDateTime($field, $errors, $valid);
279
            $this->validateReference($field, $data, $errors, $valid);
280
281
        }
282
        return array('valid' => $valid, 'errors' => $errors);
283
    }
284
285
    /**
286
     * Populates the entities fields from the requests parameters.
287
     *
288
     * @param Request $request the request to take the field data from
289
     */
290
    public function populateViaRequest(Request $request) {
291
        $fields = $this->definition->getEditableFieldNames();
292
        foreach ($fields as $field) {
293
            if ($this->definition->getType($field) == 'file') {
294
                $file = $request->files->get($field);
295
                if ($file) {
296
                    $this->set($field, $file->getClientOriginalName());
297
                }
298
            } else {
299
                $this->set($field, $request->get($field));
300
            }
301
        }
302
    }
303
304
}
305