Completed
Push — master ( 92fe32...b0dd29 )
by Philip
06:20
created

EntityValidator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 0
cts 5
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
crap 2
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
    protected function fieldTypeToRules($field, AbstractData $data, Validator $validator)
51
    {
52
        $setItems     = $this->definition->getField($field, 'items', []);
53
        $rulesMapping = [
54
            'boolean' => ['boolean'],
55
            'float' => ['floating'],
56
            'integer' => ['integer'],
57
            'date' => ['dateTime', 'Y-m-d'],
58
            'datetime' => ['or', $validator, ['dateTime', 'Y-m-d H:i'], ['dateTime', 'Y-m-d H:i:s']],
59
            'set' => array_merge(['inSet'], $setItems),
60
            'reference' => ['reference', $data, $field],
61
            'many' => ['many', $data, $field]
62
        ];
63
        $type         = $this->definition->getType($field);
64
        $rules        = [];
65
        if (array_key_exists($type, $rulesMapping)) {
66
            $rules[] = $rulesMapping[$type];
67
        }
68
        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
    protected function fieldConstraintsToRules($field, AbstractData $data)
85
    {
86
        $rules = [];
87
        if ($this->definition->getField($field, 'required', false)) {
88
            $rules[] = ['required'];
89
        }
90
        if ($this->definition->getField($field, 'unique', false)) {
91
            $rules[] = ['unique', $data, $this->entity, $field];
92
        }
93
        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
    protected function buildUpRules(AbstractData $data, Validator $validator)
109
    {
110
        $fields = $this->definition->getEditableFieldNames();
111
        $rules  = [];
112
        foreach ($fields as $field) {
113
            $fieldRules = $this->fieldTypeToRules($field, $data, $validator);
114
            $fieldRules = array_merge($fieldRules, $this->fieldConstraintsToRules($field, $data));
115
            if (!empty($fieldRules)) {
116
                $rules[$field] = $fieldRules;
117
            }
118
        }
119
        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
    protected function buildUpData()
130
    {
131
        $data   = [];
132
        $fields = $this->definition->getEditableFieldNames();
133
        foreach ($fields as $field) {
134
            $data[$field] = $this->entity->getRaw($field);
135
            $fixed        = $this->definition->getField($field, 'value');
136
            if ($fixed) {
137
                $data[$field] = $fixed;
138
            }
139
        }
140
        return $data;
141
    }
142
143
144
    /**
145
     * Constructor.
146
     *
147
     * @param Entity $entity
148
     * the entity to validate
149
     */
150
    public function __construct(Entity $entity)
151
    {
152
        $this->entity     = $entity;
153
        $this->definition = $entity->getDefinition();
154
    }
155
156
157
    /**
158
     * Validates the entity against the definition.
159
     *
160
     * @param AbstractData $data
161
     * the data access instance used for counting things
162
     * @param integer $expectedVersion
163
     * the version to perform the optimistic locking check on
164
     *
165
     * @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...
166
     * an array with the fields "valid" and "errors"; valid provides a quick
167
     * check whether the given entity passes the validation and errors is an
168
     * array with all errored fields as keys and arrays as values; this field arrays
169
     * contains the actual errors on the field: "boolean", "floating", "integer",
170
     * "dateTime" (for dates and datetime fields), "inSet", "reference", "required",
171
     * "unique", "value" (only for the version field, set if the optimistic locking
172
     * failed).
173
     */
174
    public function validate(AbstractData $data, $expectedVersion)
175
    {
176
        $validator = new Validator();
177
        $validator->addValidator('unique', new UniqueValidator());
178
        $validator->addValidator('reference', new ReferenceValidator());
179
        $validator->addValidator('many', new ManyValidator());
180
        $rules      = $this->buildUpRules($data, $validator);
181
        $toValidate = $this->buildUpData();
182
        if ($this->definition->hasOptimisticLocking()) {
183
            $rules['version']      = [['value', $expectedVersion]];
184
            $toValidate['version'] = $this->entity->get('version');
185
        }
186
        $validation = $validator->isValid($rules, $toValidate);
187
        return $validation;
188
    }
189
190
}
191