Completed
Pull Request — master (#22)
by Harrison
03:01
created

BaseNode::addConstraints()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Linio\Component\Input\Node;
5
6
use Linio\Component\Input\Constraint\ConstraintInterface;
7
use Linio\Component\Input\Exception\InvalidConstraintException;
8
use Linio\Component\Input\Exception\RequiredFieldException;
9
use Linio\Component\Input\InputHandler;
10
use Linio\Component\Input\Instantiator\InstantiatorInterface;
11
use Linio\Component\Input\Transformer\TransformerInterface;
12
use Linio\Component\Input\TypeHandler;
13
14
class BaseNode
15
{
16
    /**
17
     * @var ConstraintInterface[]
18
     */
19
    protected $constraints = [];
20
21
    /**
22
     * @var TransformerInterface
23
     */
24
    protected $transformer;
25
26
    /**
27
     * @var InstantiatorInterface
28
     */
29
    protected $instantiator;
30
31
    /**
32
     * @var string
33
     */
34
    protected $type = 'array';
35
36
    /**
37
     * @var string
38
     */
39
    protected $typeAlias = 'array';
40
41
    /**
42
     * @var bool
43
     */
44
    protected $required = true;
45
46
    /**
47
     * @var mixed
48
     */
49
    protected $default;
50
51
    /**
52
     * @var BaseNode[]
53
     */
54
    protected $children = [];
55
56
    /**
57
     * @var TypeHandler
58
     */
59
    protected $typeHandler;
60
61
    /**
62
     * @var bool
63
     */
64
    protected $allowNull = false;
65
66
    public function setConstraints(array $constraints)
67
    {
68
        $this->constraints = $constraints;
69
    }
70
71
    public function addConstraint(ConstraintInterface $constraint)
72
    {
73
        $this->constraints[] = $constraint;
74
    }
75
76
    public function addConstraints(array $constraints)
77
    {
78
        $this->constraints = array_merge($this->constraints, $constraints);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge($this->constraints, $constraints) of type array is incompatible with the declared type array<integer,object<Lin...t\ConstraintInterface>> of property $constraints.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
79
    }
80
81
    public function setTransformer(TransformerInterface $transformer)
82
    {
83
        $this->transformer = $transformer;
84
    }
85
86
    public function setInstantiator(InstantiatorInterface $instantiator)
87
    {
88
        $this->instantiator = $instantiator;
89
    }
90
91
    public function setTypeHandler(TypeHandler $typeHandler)
92
    {
93
        $this->typeHandler = $typeHandler;
94
    }
95
96
    public function setType(string $type)
97
    {
98
        $this->type = $type;
99
    }
100
101
    public function setTypeAlias(string $typeAlias)
102
    {
103
        $this->typeAlias = $typeAlias;
104
    }
105
106
    public function getTypeAlias(): string
107
    {
108
        return $this->typeAlias;
109
    }
110
111
    public function setRequired(bool $required)
112
    {
113
        $this->required = $required;
114
    }
115
116
    public function setDefault($default)
117
    {
118
        $this->default = $default;
119
    }
120
121
    public function setAllowNull(bool $allowNull)
122
    {
123
        $this->allowNull = $allowNull;
124
    }
125
126
    public function getDefault()
127
    {
128
        return $this->default;
129
    }
130
131
    public function hasDefault(): bool
132
    {
133
        return (bool) $this->default;
134
    }
135
136
    public function add(string $key, string $type, array $options = []): BaseNode
137
    {
138
        $child = $this->typeHandler->getType($type);
139
140
        if (isset($options['handler'])) {
141
            /** @var InputHandler $handler */
142
            $handler = $options['handler'];
143
            $handler->setRootType($type);
144
            $handler->define();
145
146
            $child = $handler->getRoot();
147
        }
148
149
        if (isset($options['required'])) {
150
            $child->setRequired($options['required']);
151
        }
152
153
        if (isset($options['default'])) {
154
            $child->setDefault($options['default']);
155
        }
156
157
        if (isset($options['instantiator'])) {
158
            $child->setInstantiator($options['instantiator']);
159
        }
160
161
        if (isset($options['transformer'])) {
162
            $child->setTransformer($options['transformer']);
163
        }
164
165
        if (isset($options['constraints'])) {
166
            $child->addConstraints($options['constraints']);
167
        }
168
169
        if (isset($options['allow_null'])) {
170
            $child->setAllowNull($options['allow_null']);
171
        }
172
173
        $this->children[$key] = $child;
174
175
        return $child;
176
    }
177
178
    public function remove(string $key)
179
    {
180
        unset($this->children[$key]);
181
    }
182
183
    /**
184
     * @return BaseNode[]
185
     */
186
    public function getChildren(): array
187
    {
188
        return $this->children;
189
    }
190
191
    public function hasChildren(): bool
192
    {
193
        return !empty($this->children);
194
    }
195
196
    public function isRequired(): bool
197
    {
198
        if ($this->hasDefault()) {
199
            return false;
200
        }
201
202
        return $this->required;
203
    }
204
205
    public function allowNull(): bool
0 ignored issues
show
Coding Style introduced by
function allowNull() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
206
    {
207
        return $this->allowNull;
208
    }
209
210
    public function getValue(string $field, $value)
211
    {
212
        if ($this->allowNull() && $value === null) {
213
            return $value;
214
        }
215
216
        $this->checkConstraints($field, $value);
217
218
        if ($this->transformer) {
219
            return $this->transformer->transform($value);
220
        }
221
222
        return $value;
223
    }
224
225
    public function walk($input)
226
    {
227
        $result = [];
228
229
        if (!$this->hasChildren()) {
230
            return $input;
231
        }
232
233 View Code Duplication
        foreach ($this->getChildren() as $field => $config) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
234
            if (!array_key_exists($field, $input)) {
235
                if ($config->isRequired()) {
236
                    throw new RequiredFieldException($field);
237
                }
238
239
                if (!$config->hasDefault()) {
240
                    continue;
241
                }
242
243
                $input[$field] = $config->getDefault();
244
            }
245
246
            $result[$field] = $config->getValue($field, $config->walk($input[$field]));
247
        }
248
249
        return $result;
250
    }
251
252
    protected function checkConstraints(string $field, $value)
253
    {
254
        foreach ($this->constraints as $constraint) {
255
            if (!$constraint->validate($value)) {
256
                throw new InvalidConstraintException($constraint->getErrorMessage($field));
257
            }
258
        }
259
    }
260
}
261