Completed
Pull Request — master (#4)
by Mariano
04:20
created

Properties::initPatternProperties()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

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