Completed
Push — master ( a92c21...c3f20e )
by Klaus
02:41
created

BaseNode::add()   D

Complexity

Conditions 8
Paths 128

Size

Total Lines 41
Code Lines 21

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 41
rs 4.6666
cc 8
eloc 21
nc 128
nop 3
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 bool
38
     */
39
    protected $required = true;
40
41
    /**
42
     * @var mixed
43
     */
44
    protected $default;
45
46
    /**
47
     * @var BaseNode[]
48
     */
49
    protected $children = [];
50
51
    /**
52
     * @var TypeHandler
53
     */
54
    protected $typeHandler;
55
56
    /**
57
     * @var bool
58
     */
59
    protected $allowNull = false;
60
61
    public function setConstraints(array $constraints)
62
    {
63
        $this->constraints = $constraints;
64
    }
65
66
    public function addConstraint(ConstraintInterface $constraint)
67
    {
68
        $this->constraints[] = $constraint;
69
    }
70
71
    public function setTransformer(TransformerInterface $transformer)
72
    {
73
        $this->transformer = $transformer;
74
    }
75
76
    public function setInstantiator(InstantiatorInterface $instantiator)
77
    {
78
        $this->instantiator = $instantiator;
79
    }
80
81
    public function setTypeHandler(TypeHandler $typeHandler)
82
    {
83
        $this->typeHandler = $typeHandler;
84
    }
85
86
    public function setType(string $type)
87
    {
88
        $this->type = $type;
89
    }
90
91
    public function setRequired(bool $required)
92
    {
93
        $this->required = $required;
94
    }
95
96
    public function setDefault($default)
97
    {
98
        $this->default = $default;
99
    }
100
101
    public function setAllowNull(bool $allowNull)
102
    {
103
        $this->allowNull = $allowNull;
104
    }
105
106
    public function getDefault()
107
    {
108
        return $this->default;
109
    }
110
111
    public function hasDefault(): bool
112
    {
113
        return (bool) $this->default;
114
    }
115
116
    public function add(string $key, string $type, array $options = []): BaseNode
117
    {
118
        $child = $this->typeHandler->getType($type);
119
120
        if (isset($options['handler'])) {
121
            /** @var InputHandler $handler */
122
            $handler = $options['handler'];
123
            $handler->setRootType($type);
124
            $handler->define();
125
126
            $child = $handler->getRoot();
127
        }
128
129
        if (isset($options['required'])) {
130
            $child->setRequired($options['required']);
131
        }
132
133
        if (isset($options['default'])) {
134
            $child->setDefault($options['default']);
135
        }
136
137
        if (isset($options['instantiator'])) {
138
            $child->setInstantiator($options['instantiator']);
139
        }
140
141
        if (isset($options['transformer'])) {
142
            $child->setTransformer($options['transformer']);
143
        }
144
145
        if (isset($options['constraints'])) {
146
            $child->setConstraints($options['constraints']);
147
        }
148
149
        if (isset($options['allow_null'])) {
150
            $child->setAllowNull($options['allow_null']);
151
        }
152
153
        $this->children[$key] = $child;
154
155
        return $child;
156
    }
157
158
    public function remove(string $key)
159
    {
160
        unset($this->children[$key]);
161
    }
162
163
    /**
164
     * @return BaseNode[]
165
     */
166
    public function getChildren(): array
167
    {
168
        return $this->children;
169
    }
170
171
    public function hasChildren(): bool
172
    {
173
        return !empty($this->children);
174
    }
175
176
    public function isRequired(): bool
177
    {
178
        if ($this->hasDefault()) {
179
            return false;
180
        }
181
182
        return $this->required;
183
    }
184
185
    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...
186
    {
187
        return $this->allowNull;
188
    }
189
190
    public function getValue(string $field, $value)
191
    {
192
        if ($this->allowNull() && $value === null) {
193
            return $value;
194
        }
195
196
        $this->checkConstraints($field, $value);
197
198
        if ($this->transformer) {
199
            return $this->transformer->transform($value);
200
        }
201
202
        return $value;
203
    }
204
205
    public function walk($input)
206
    {
207
        $result = [];
208
209
        if (!$this->hasChildren()) {
210
            return $input;
211
        }
212
213 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...
214
            if (!array_key_exists($field, $input)) {
215
                if ($config->isRequired()) {
216
                    throw new RequiredFieldException($field);
217
                }
218
219
                if (!$config->hasDefault()) {
220
                    continue;
221
                }
222
223
                $input[$field] = $config->getDefault();
224
            }
225
226
            $result[$field] = $config->getValue($field, $config->walk($input[$field]));
227
        }
228
229
        return $result;
230
    }
231
232
    protected function checkConstraints(string $field, $value)
233
    {
234
        foreach ($this->constraints as $constraint) {
235
            if (!$constraint->validate($value)) {
236
                throw new InvalidConstraintException($constraint->getErrorMessage($field));
237
            }
238
        }
239
    }
240
}
241