Completed
Push — master ( a7034a...f61a89 )
by Mariano
04:17
created

Properties::validateAdditionalProperties()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4

Importance

Changes 2
Bugs 1 Features 1
Metric Value
c 2
b 1
f 1
dl 0
loc 10
ccs 6
cts 6
cp 1
rs 9.2
cc 4
eloc 6
nc 3
nop 1
crap 4
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
     * @return boolean
148
     */
149 88
    private function validateAgainstAdditionalPropertiesValidator(array $rest)
150
    {
151 88
        foreach ($rest as $propertyValue) {
152 4
            if (!$this->additionalProperties->validate($propertyValue)) {
153 2
                return false;
154
            }
155 86
        }
156 86
        return true;
157
    }
158
159
    /**
160
     * @param array $value
161
     * @param array $rest
162
     *
163
     * @return bool
164
     */
165 99
    private function validateByPattern(array $value, array &$rest)
166
    {
167 99
        $valid = true;
168 99
        foreach ($this->patternProperties as $pattern => $propertyValidator) {
169 12
            $valid &= $this->validateByPatternUsingValidator(
170 12
                $value,
171 12
                $rest,
172 12
                $pattern,
173
                $propertyValidator
174 12
            );
175 12
            if (!$valid) {
176 2
                break;
177
            }
178 99
        }
179 99
        return $valid;
180
    }
181
182
    /**
183
     * @param array                                                 $value
184
     * @param array                                                 $rest
185
     * @param string                                                $pattern
186
     * @param \Mcustiel\SimpleRequest\Interfaces\ValidatorInterface $validator
187
     *
188
     * @return bool
189
     */
190 12
    private function validateByPatternUsingValidator(
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
191
        array $value,
192
        array &$rest,
193
        $pattern,
194
        ValidatorInterface $validator
195
    ) {
196 12
        foreach ($value as $propertyName => $propertyValue) {
197 12
            if (preg_match($pattern, $propertyName)) {
198 12
                unset($rest[$propertyName]);
199 12
                if (!$validator->validate($propertyValue)) {
200 2
                    return false;
201
                }
202 12
            }
203 12
        }
204 10
        return true;
205
    }
206
207
    /**
208
     * @param array $value
209
     * @param array $rest
210
     *
211
     * @return bool
212
     */
213 104
    private function validateByProperty(array $value, array &$rest)
214
    {
215 104
        $valid = true;
216 104
        foreach ($this->properties as $propertyName => $propertyValidator) {
217 98
            unset($rest[$propertyName]);
218 98
            $valid &= $propertyValidator->validate(
219 98
                isset($value[$propertyName]) ? $value[$propertyName] : null
220 98
            );
221 98
            if (!$valid) {
222 5
                break;
223
            }
224 104
        }
225 104
        return $valid;
226
    }
227
228
    /**
229
     * @param \stdClass|array $value
230
     *
231
     * @return array
232
     */
233 104
    private function convertToArray($value)
234
    {
235 104
        if (!is_array($value)) {
236 12
            return json_decode(json_encode($value), true);
237
        }
238 92
        return $value;
239
    }
240
241
    /**
242
     * Checks and sets items specification.
243
     *
244
     * @param bool|\Mcustiel\SimpleRequest\Interfaces\ValidatorInterface $specification
245
     *
246
     * @throws \Mcustiel\SimpleRequest\Exception\UnspecifiedValidatorException
247
     */
248 102
    private function setAdditionalProperties($specification)
249
    {
250 102
        if (is_bool($specification)) {
251 97
            $this->additionalProperties = $specification;
252 97
        } else {
253 5
            $this->additionalProperties = $this->checkIfAnnotationAndReturnObject($specification);
254
        }
255 101
    }
256
257
    /**
258
     * Checks and sets pattern properties specification.
259
     *
260
     * @param \Mcustiel\SimpleRequest\Interfaces\ValidatorInterface[] $specification
261
     *
262
     * @throws \Mcustiel\SimpleRequest\Exception\UnspecifiedValidatorException
263
     */
264 99
    private function setProperties($specification)
265
    {
266 99
        if (!is_array($specification)) {
267 1
            throw new UnspecifiedValidatorException(
268
                'The validator Properties is being initialized with an invalid '
269
                . self::PROPERTIES_INDEX
270 1
                . ' parameter'
271 1
            );
272
        }
273 98
        foreach ($specification as $key => $item) {
274 98
            $this->properties[$key] = $this->checkIfAnnotationAndReturnObject($item);
275 97
        }
276 97
    }
277
278
    /**
279
     * Checks and sets pattern properties specification.
280
     *
281
     * @param \Mcustiel\SimpleRequest\Interfaces\ValidatorInterface[] $specification
282
     *
283
     * @throws \Mcustiel\SimpleRequest\Exception\UnspecifiedValidatorException
284
     */
285 93
    private function setPatternProperties($specification)
286
    {
287 93
        if (!is_array($specification)) {
288
            throw new UnspecifiedValidatorException(
289
                'The validator Properties is being initialized with an invalid '
290
                . self::PROPERTIES_INDEX
291
                . ' parameter'
292
            );
293
        }
294 93
        foreach ($specification as $key => $item) {
295 14
            $this->patternProperties[$key] = $this->checkIfAnnotationAndReturnObject($item);
296 93
        }
297 93
    }
298
}
299