Issues (8)

src/ObjectValidator.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 Graze\ConfigValidation\Rules\AttributeSet;
19
use Respect\Validation\Rules\Attribute;
20
use Respect\Validation\Validatable;
21
use Respect\Validation\Validator as v;
22
use stdClass;
23
use Throwable;
24
25
class ObjectValidator implements ConfigValidatorInterface
26
{
27
    use ValidatorBuilderTrait;
28
29
    const SEPARATOR = '->';
30
31
    /**
32
     * @var bool
33
     */
34
    protected $allowUnspecified = true;
35
36
    /**
37
     * @param bool $allowUnspecified Allow unspecified params (turning this off will fail if an attribute exists that
38
     *                               it is not expecting)
39
     */
40 16
    public function __construct($allowUnspecified = true)
41
    {
42 16
        $this->allowUnspecified = $allowUnspecified;
43 16
        $this->separator = static::SEPARATOR;
44 16
    }
45
46
    /**
47
     * @param array  $definition
48
     * @param string $namePrefix
49
     *
50
     * @return Validatable
51
     */
52 11
    private function buildValidator(array $definition, $namePrefix = '')
53
    {
54 11
        $validators = [];
55 11
        foreach ($definition as $key => $node) {
56 11
            if (isset($node['required'])) {
57 11
                $validators[] = (new Attribute(
58 11
                    $key,
59 11
                    (isset($node['validator']) ? $node['validator'] : null),
60 11
                    $node['required']
61 11
                ))->setName($namePrefix . $this->separator. $key);
62
            } else {
63 9
                $validators[] = (new Attribute(
64 9
                    $key,
65 9
                    $this->buildValidator($node, $namePrefix . $this->separator . $key),
66 11
                    $this->hasMandatoryItem($node)
67
                ));
68
            }
69
        }
70 11
        if ($this->allowUnspecified) {
71 9
            return v::allOf(v::objectType(), ...$validators)->setName($namePrefix);
72
        } else {
73 2
            return (new AttributeSet(...$validators))->setName($namePrefix);
74
        }
75
    }
76
77
    /**
78
     * @param mixed $item
79
     *
80
     * @return mixed
81
     */
82 3
    public function populate($item)
83
    {
84 3
        return $this->populateObjectItems($item, $this->validators);
85
    }
86
87
    /**
88
     * @param object $object
89
     * @param array  $definition
90
     *
91
     * @return object
92
     */
93 3
    private function populateObjectItems($object, array $definition)
94
    {
95 3
        $output = clone $object;
96 3
        foreach ($definition as $key => $node) {
97 3
            if (isset($node['required'])) {
98 3
                if ((!$node['required']) && (!isset($output->{$key}))) {
99 3
                    $output->{$key} = $node['default'];
100
                }
101
            } else {
102 3
                if (!isset($output->{$key})) {
103 2
                    $output->{$key} = new stdClass();
104
                }
105 3
                $output->{$key} = $this->populateObjectItems($output->{$key}, $node);
106
            }
107
        }
108 3
        return $output;
109
    }
110
111
    /**
112
     * @param mixed $item
113
     *
114
     * @return mixed
115
     * @throws ConfigValidationFailedException
116
     */
117 10
    public function validate($item)
118
    {
119 10
        if (!$item) {
120 1
            $item = new \stdClass();
121
        }
122 10
        $validator = $this->getValidator();
123
124
        try {
125 10
            $validator->assert($item);
126 3
            return $this->populate($item);
127 7
        } catch (Exception $e) {
128 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

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