Properties::setProperties()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 1
Bugs 1 Features 1
Metric Value
c 1
b 1
f 1
dl 0
loc 13
ccs 9
cts 9
cp 1
rs 9.4285
cc 3
eloc 8
nc 3
nop 1
crap 3
1
<?php
2
/**
3
 * This file is part of php-simple-request.
4
 *
5
 * php-simple-request is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU Lesser General Public License as published by
7
 * the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * php-simple-request is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with php-simple-request.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18
namespace Mcustiel\SimpleRequest\Validator;
19
20
use Mcustiel\SimpleRequest\Interfaces\ValidatorInterface;
21
use Mcustiel\SimpleRequest\Exception\UnspecifiedValidatorException;
22
23
/**
24
 * Checks that each element of an object or array validates against its corresponding
25
 * validator in a collection, using the name of the property or key.
26
 * <a href="http://spacetelescope.github.io/understanding-json-schema/UnderstandingJSONSchema.pdf">Here</a>
27
 * you can see examples of use for this validator.
28
 *
29
 * @author mcustiel
30
 */
31
class Properties extends AbstractIterableValidator
32
{
33
    const PROPERTIES_INDEX = 'properties';
34
    const PATTERN_PROPERTIES_INDEX = 'patternProperties';
35
    const ADDITIONAL_PROPERTIES_INDEX = 'additionalProperties';
36
37
    /**
38
     * @var \Mcustiel\SimpleRequest\Interfaces\ValidatorInterface[]
39
     */
40
    private $properties = [];
41
42
    /**
43
     * @var bool|\Mcustiel\SimpleRequest\Interfaces\ValidatorInterface
44
     */
45
    private $additionalProperties = true;
46
47
    /**
48
     * @var \Mcustiel\SimpleRequest\Interfaces\ValidatorInterface[]
49
     */
50
    private $patternProperties = [];
51
52
    /**
53
     * {@inheritdoc}
54
     *
55
     * @see \Mcustiel\SimpleRequest\Validator\AbstractIterableValidator::setSpecification()
56
     */
57 107
    public function setSpecification($specification = null)
58
    {
59 107
        $this->checkSpecificationIsArray($specification);
60
61 106
        $this->initProperties($specification);
62 104
        $this->initPatternProperties($specification);
63 104
        $this->initAdditionalProperties($specification);
64 103
    }
65
66
    /**
67
     * @param array $specification
68
     *
69
     * @throws \Mcustiel\SimpleRequest\Exception\UnspecifiedValidatorException
70
     */
71 104
    private function initAdditionalProperties(array $specification)
72
    {
73 104
        if (isset($specification[self::ADDITIONAL_PROPERTIES_INDEX])) {
74 102
            $this->setAdditionalProperties($specification[self::ADDITIONAL_PROPERTIES_INDEX]);
75 101
        }
76 103
    }
77
78
    /**
79
     * @param array $specification
80
     *
81
     * @throws \Mcustiel\SimpleRequest\Exception\UnspecifiedValidatorException
82
     */
83 104
    private function initPatternProperties(array $specification)
84
    {
85 104
        if (isset($specification[self::PATTERN_PROPERTIES_INDEX])) {
86 93
            $this->setPatternProperties($specification[self::PATTERN_PROPERTIES_INDEX]);
87 93
        }
88 104
    }
89
90
    /**
91
     * @param array $specification
92
     *
93
     * @throws \Mcustiel\SimpleRequest\Exception\UnspecifiedValidatorException
94
     */
95 106
    private function initProperties(array $specification)
96
    {
97 106
        if (isset($specification[self::PROPERTIES_INDEX])) {
98 99
            $this->setProperties($specification[self::PROPERTIES_INDEX]);
99 97
        }
100 104
    }
101
102
    /**
103
     * {@inheritdoc}
104
     *
105
     * @see \Mcustiel\SimpleRequest\Validator\AbstractAnnotationSpecifiedValidator::validate()
106
     */
107 105
    public function validate($value)
108
    {
109 105
        if (!(is_array($value) || $value instanceof \stdClass)) {
110 1
            return false;
111
        }
112
113 104
        return $this->executePropertiesValidation($this->convertToArray($value));
114
    }
115
116
    /**
117
     * @param array $value
118
     *
119
     * @return bool
120
     */
121 104
    private function executePropertiesValidation(array $value)
122
    {
123 104
        $rest = $value;
124 104
        return $this->validateByProperty($value, $rest)
125 104
            && $this->validateByPattern($value, $rest)
126 104
            && $this->validateAdditionalProperties($rest);
127
    }
128
129
    /**
130
     * @param array $rest
131
     *
132
     * @return bool|\Mcustiel\SimpleRequest\Interfaces\ValidatorInterface|bool
133
     */
134 97
    private function validateAdditionalProperties(array $rest)
135
    {
136 97
        if ($this->additionalProperties === true) {
137 6
            return true;
138
        }
139 91
        if ($this->additionalProperties === false && !empty($rest)) {
140 3
            return false;
141
        }
142 88
        return $this->validateAgainstAdditionalPropertiesValidator($rest);
143
    }
144
145
    /**
146
     * @param array $rest
147
     *
148
     * @return bool
149
     */
150 88
    private function validateAgainstAdditionalPropertiesValidator(array $rest)
151
    {
152 88
        foreach ($rest as $propertyValue) {
153 4
            if (!$this->additionalProperties->validate($propertyValue)) {
154 2
                return false;
155
            }
156 86
        }
157 86
        return true;
158
    }
159
160
    /**
161
     * @param array $value
162
     * @param array $rest
163
     *
164
     * @return bool
165
     */
166 99
    private function validateByPattern(array $value, array &$rest)
167
    {
168 99
        $valid = true;
169 99
        foreach ($this->patternProperties as $pattern => $propertyValidator) {
170 12
            $valid &= $this->validateByPatternUsingValidator(
171 12
                $value,
172 12
                $rest,
173 12
                $pattern,
174
                $propertyValidator
175 12
            );
176 12
            if (!$valid) {
177 2
                break;
178
            }
179 99
        }
180 99
        return $valid;
181
    }
182
183
    /**
184
     * @param array                                                 $value
185
     * @param array                                                 $rest
186
     * @param string                                                $pattern
187
     * @param \Mcustiel\SimpleRequest\Interfaces\ValidatorInterface $validator
188
     *
189
     * @return bool
190
     */
191 12
    private function validateByPatternUsingValidator(
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
192
        array $value,
193
        array &$rest,
194
        $pattern,
195
        ValidatorInterface $validator
196
    ) {
197 12
        foreach ($value as $propertyName => $propertyValue) {
198 12
            if (preg_match($pattern, $propertyName)) {
199 12
                unset($rest[$propertyName]);
200 12
                if (!$validator->validate($propertyValue)) {
201 2
                    return false;
202
                }
203 12
            }
204 12
        }
205 10
        return true;
206
    }
207
208
    /**
209
     * @param array $value
210
     * @param array $rest
211
     *
212
     * @return bool
213
     */
214 104
    private function validateByProperty(array $value, array &$rest)
215
    {
216 104
        $valid = true;
217 104
        foreach ($this->properties as $propertyName => $propertyValidator) {
218 98
            unset($rest[$propertyName]);
219 98
            $valid &= $propertyValidator->validate(
220 98
                isset($value[$propertyName]) ? $value[$propertyName] : null
221 98
            );
222 98
            if (!$valid) {
223 5
                break;
224
            }
225 104
        }
226 104
        return $valid;
227
    }
228
229
    /**
230
     * @param \stdClass|array $value
231
     *
232
     * @return array
233
     */
234 104
    private function convertToArray($value)
235
    {
236 104
        if (!is_array($value)) {
237 12
            return json_decode(json_encode($value), true);
238
        }
239 92
        return $value;
240
    }
241
242
    /**
243
     * Checks and sets items specification.
244
     *
245
     * @param bool|\Mcustiel\SimpleRequest\Interfaces\ValidatorInterface $specification
246
     *
247
     * @throws \Mcustiel\SimpleRequest\Exception\UnspecifiedValidatorException
248
     */
249 102
    private function setAdditionalProperties($specification)
250
    {
251 102
        if (is_bool($specification)) {
252 97
            $this->additionalProperties = $specification;
253 97
        } else {
254 5
            $this->additionalProperties = $this->checkIfAnnotationAndReturnObject($specification);
255
        }
256 101
    }
257
258
    /**
259
     * Checks and sets pattern properties specification.
260
     *
261
     * @param \Mcustiel\SimpleRequest\Interfaces\ValidatorInterface[] $specification
262
     *
263
     * @throws \Mcustiel\SimpleRequest\Exception\UnspecifiedValidatorException
264
     */
265 99
    private function setProperties($specification)
266
    {
267 99
        if (!is_array($specification)) {
268 1
            throw new UnspecifiedValidatorException(
269
                'The validator Properties is being initialized with an invalid '
270
                . self::PROPERTIES_INDEX
271 1
                . ' parameter'
272 1
            );
273
        }
274 98
        foreach ($specification as $key => $item) {
275 98
            $this->properties[$key] = $this->checkIfAnnotationAndReturnObject($item);
276 97
        }
277 97
    }
278
279
    /**
280
     * Checks and sets pattern properties specification.
281
     *
282
     * @param \Mcustiel\SimpleRequest\Interfaces\ValidatorInterface[] $specification
283
     *
284
     * @throws \Mcustiel\SimpleRequest\Exception\UnspecifiedValidatorException
285
     */
286 93
    private function setPatternProperties($specification)
287
    {
288 93
        if (!is_array($specification)) {
289
            throw new UnspecifiedValidatorException(
290
                'The validator Properties is being initialized with an invalid '
291
                . self::PROPERTIES_INDEX
292
                . ' parameter'
293
            );
294
        }
295 93
        foreach ($specification as $key => $item) {
296 14
            $this->patternProperties[$key] = $this->checkIfAnnotationAndReturnObject($item);
297 93
        }
298 93
    }
299
}
300