EntityValidator::buildUpData()   A
last analyzed

Complexity

Conditions 4
Paths 5

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 13
cts 13
cp 1
rs 9.6666
c 0
b 0
f 0
cc 4
nc 5
nop 0
crap 4
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 \Valdi\Validator;
15
16
/**
17
 * Performs validation of the field values of the given Entity.
18
 */
19
class EntityValidator
20
{
21
22
    /**
23
     * The entity to validate.
24
     * @var Entity
25
     */
26
    protected $entity;
27
28
29
    /**
30
     * The entities definition.
31
     * @var EntityDefinition
32
     */
33
    protected $definition;
34
35
36
    /**
37
     * Builds up the validation rules for a single field according to the
38
     * entity definition type.
39
     *
40
     * @param string $field
41
     * the field for the rules
42
     * @param AbstractData $data
43
     * the data instance to use for validation
44
     * @param Validator $validator
45
     * the validator to use
46
     *
47
     * @return array
48
     * the validation rules for the field
49
     */
50 5
    protected function fieldTypeToRules($field, AbstractData $data, Validator $validator)
51
    {
52 5
        $setItems     = $this->definition->getField($field, 'items', []);
53
        $rulesMapping = [
54 5
            'boolean' => ['boolean'],
55
            'float' => ['floating'],
56
            'integer' => ['integer'],
57
            'date' => ['dateTime', 'Y-m-d'],
58 5
            'datetime' => ['or', $validator, [['dateTime', 'Y-m-d H:i']], [['dateTime', 'Y-m-d H:i:s']]],
59 5
            'set' => array_merge(['inSet'], $setItems),
60 5
            'reference' => ['reference', $data, $field],
61 5
            'many' => ['many', $data, $field]
62
        ];
63 5
        $type         = $this->definition->getType($field);
64 5
        $rules        = [];
65 5
        if (array_key_exists($type, $rulesMapping)) {
66 5
            $rules[] = $rulesMapping[$type];
67
        }
68 5
        return $rules;
69
    }
70
71
72
    /**
73
     * Builds up the validation rules for a single field according to the
74
     * entity definition constraints.
75
     *
76
     * @param string $field
77
     * the field for the rules
78
     * @param AbstractData $data
79
     * the data instance to use for validation
80
     *
81
     * @return array
82
     * the validation rules for the field
83
     */
84 5
    protected function fieldConstraintsToRules($field, AbstractData $data)
85
    {
86 5
        $rules = [];
87 5
        if ($this->definition->getField($field, 'required', false)) {
88 5
            $rules[] = ['required'];
89
        }
90 5
        if ($this->definition->getField($field, 'unique', false)) {
91 1
            $rules[] = ['unique', $data, $this->entity, $field];
92
        }
93 5
        return $rules;
94
    }
95
96
97
    /**
98
     * Builds up the validation rules for the entity according to its
99
     * definition.
100
     * @param AbstractData $data
101
     * the data instance to use for validation
102
     * @param Validator $validator
103
     * the validator to use
104
     *
105
     * @return array
106
     * the validation rules for the entity
107
     */
108 5
    protected function buildUpRules(AbstractData $data, Validator $validator)
109
    {
110 5
        $fields = $this->definition->getEditableFieldNames();
111 5
        $rules  = [];
112 5
        foreach ($fields as $field) {
113 5
            $fieldRules = $this->fieldTypeToRules($field, $data, $validator);
114 5
            $fieldRules = array_merge($fieldRules, $this->fieldConstraintsToRules($field, $data));
115 5
            if (!empty($fieldRules)) {
116 5
                $rules[$field] = $fieldRules;
117
            }
118
        }
119 5
        return $rules;
120
    }
121
122
123
    /**
124
     * Builds up the data to validate from the entity.
125
     *
126
     * @return array
127
     * a map field to raw value
128
     */
129 5
    protected function buildUpData()
130
    {
131 5
        $data   = [];
132 5
        $fields = $this->definition->getEditableFieldNames();
133 5
        foreach ($fields as $field) {
134 5
            $value = $this->entity->getRaw($field);
135 5
            $type = $this->definition->getType($field);
136 5
            if ($type === 'reference') {
137 5
                $value = $value['id'];
138
            }
139 5
            $data[$field] = $value;
140 5
            $fixed        = $this->definition->getField($field, 'value');
141 5
            if ($fixed) {
142 1
                $data[$field] = $fixed;
143
            }
144
        }
145 5
        return $data;
146
    }
147
148
149
    /**
150
     * Constructor.
151
     *
152
     * @param Entity $entity
153
     * the entity to validate
154
     */
155 5
    public function __construct(Entity $entity)
156
    {
157 5
        $this->entity     = $entity;
158 5
        $this->definition = $entity->getDefinition();
159 5
    }
160
161
162
    /**
163
     * Validates the entity against the definition.
164
     *
165
     * @param AbstractData $data
166
     * the data access instance used for counting things
167
     * @param integer $expectedVersion
168
     * the version to perform the optimistic locking check on
169
     *
170
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,boolean|array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
171
     * an array with the fields "valid" and "errors"; valid provides a quick
172
     * check whether the given entity passes the validation and errors is an
173
     * array with all errored fields as keys and arrays as values; this field arrays
174
     * contains the actual errors on the field: "boolean", "floating", "integer",
175
     * "dateTime" (for dates and datetime fields), "inSet", "reference", "required",
176
     * "unique", "value" (only for the version field, set if the optimistic locking
177
     * failed).
178
     */
179 5
    public function validate(AbstractData $data, $expectedVersion)
180
    {
181 5
        $validator = new Validator();
182 5
        $validator->addValidator('unique', new UniqueValidator());
183 5
        $validator->addValidator('reference', new ReferenceValidator());
184 5
        $validator->addValidator('many', new ManyValidator());
185 5
        $rules      = $this->buildUpRules($data, $validator);
186 5
        $toValidate = $this->buildUpData();
187 5
        if ($this->definition->hasOptimisticLocking()) {
188 5
            $rules['version']      = [['value', $expectedVersion]];
189 5
            $toValidate['version'] = $this->entity->get('version');
190
        }
191 5
        $validation = $validator->isValid($rules, $toValidate);
192 5
        return $validation;
193
    }
194
195
}
196