Issues (8)

src/ArrayValidator.php (1 issue)

Labels
Severity
1
<?php
2
/**
3
 * This file is part of graze/config-validation.
4
 *
5
 * Copyright (c) 2017 Nature Delivered Ltd. <https://www.graze.com>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license https://github.com/graze/config-validation/blob/master/LICENSE.md
11
 * @link    https://github.com/graze/config-validation
12
 */
13
14
namespace Graze\ConfigValidation;
15
16
use Exception;
17
use Graze\ConfigValidation\Exceptions\ConfigValidationFailedException;
18
use Respect\Validation\Rules\Key;
19
use Respect\Validation\Rules\KeySet;
20
use Respect\Validation\Validatable;
21
use Respect\Validation\Validator as v;
22
23
/**
24
 * ArrayValidator takes an input array and validates it against a defined schema
25
 */
26
class ArrayValidator implements ConfigValidatorInterface
27
{
28
    use ValidatorBuilderTrait;
29
30
    const SEPARATOR = '.';
31
32
    /**
33
     * @var bool
34
     */
35
    protected $allowUnspecified = true;
36
37
    /**
38
     * @param bool $allowUnspecified Allow unspecified params (turning this off will fail if an attribute exists that
39
     *                               it is not expecting)
40
     */
41 18
    public function __construct($allowUnspecified = true)
42
    {
43 18
        $this->allowUnspecified = $allowUnspecified;
44 18
        $this->separator = static::SEPARATOR;
45 18
    }
46
47
    /**
48
     * @param array  $definition
49
     * @param string $namePrefix
50
     *
51
     * @return Validatable
52
     */
53 13
    private function buildValidator(array $definition, $namePrefix = '')
54
    {
55 13
        $validators = [];
56 13
        foreach ($definition as $key => $node) {
57 13
            if (isset($node['required'])) {
58 13
                $validators[] = (new Key(
59 13
                    $key,
60 13
                    (isset($node['validator']) ? $node['validator'] : null),
61 13
                    $node['required']
62 13
                ))->setName($namePrefix . $this->separator . $key);
63
            } else {
64 10
                $validators[] = (new Key(
65 10
                    $key,
66 10
                    $this->buildValidator($node, $namePrefix . $this->separator . $key),
67 13
                    $this->hasMandatoryItem($node)
68
                ));
69
            }
70
        }
71 13
        if ($this->allowUnspecified) {
72 11
            return v::allOf(v::arrayType(), ...$validators)->setName($namePrefix);
73
        } else {
74 2
            return (new KeySet(...$validators))->setName($namePrefix);
75
        }
76
    }
77
78
    /**
79
     * @param mixed $item
80
     *
81
     * @return mixed
82
     */
83 3
    public function populate($item)
84
    {
85 3
        return $this->populateItems($item, $this->validators);
86
    }
87
88
    /**
89
     * @param array $array
90
     * @param array $definition
91
     *
92
     * @return array
93
     */
94 3
    private function populateItems(array $array, array $definition)
95
    {
96 3
        $output = $array;
97 3
        foreach ($definition as $key => $node) {
98 3
            if (isset($node['required'])) {
99 3
                if ((!$node['required']) && (!isset($output[$key]))) {
100 3
                    $output[$key] = $node['default'];
101
                }
102
            } else {
103 3
                if (!isset($output[$key])) {
104 2
                    $output[$key] = [];
105
                }
106 3
                $output[$key] = $this->populateItems($output[$key], $node);
107
            }
108
        }
109 3
        return $output;
110
    }
111
112
    /**
113
     * @param mixed $item
114
     *
115
     * @return mixed
116
     * @throws ConfigValidationFailedException
117
     */
118 10
    public function validate($item)
119
    {
120 10
        if (!$item) {
121 1
            $item = [];
122
        }
123 10
        $validator = $this->getValidator();
124
125
        try {
126 10
            $validator->assert($item);
127 3
            return $this->populate($item);
128 7
        } catch (Exception $e) {
129 7
            throw new ConfigValidationFailedException(get_class($this), '', $e);
0 ignored issues
show
'' of type string is incompatible with the type integer expected by parameter $message of Graze\ConfigValidation\E...xception::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

129
            throw new ConfigValidationFailedException(get_class($this), /** @scrutinizer ignore-type */ '', $e);
Loading history...
130
        }
131
    }
132
133
    /**
134
     * Determine if the provided item is valid or not
135
     *
136
     * @param mixed $item
137
     *
138
     * @return bool
139
     */
140 11
    public function isValid($item)
141
    {
142 11
        if (!$item) {
143 2
            $item = [];
144
        }
145 11
        $validator = $this->getValidator();
146
147 11
        return $validator->validate($item);
148
    }
149
150
    /**
151
     * @param bool $allowUnspecified
152
     *
153
     * @return $this
154
     */
155 1
    public function setAllowUnspecified($allowUnspecified)
156
    {
157 1
        $this->allowUnspecified = $allowUnspecified;
158 1
        return $this;
159
    }
160
161
    /**
162
     * @return bool
163
     */
164 5
    public function isAllowUnspecified()
165
    {
166 5
        return $this->allowUnspecified;
167
    }
168
}
169