Child::__construct()   A
last analyzed

Complexity

Conditions 2
Paths 1

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 9
c 1
b 0
f 0
dl 0
loc 11
ccs 10
cts 10
cp 1
rs 9.9666
cc 2
nc 1
nop 9
crap 2

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace Bdf\Form\Child;
4
5
use Bdf\Form\Aggregate\ChildAggregateInterface;
6
use Bdf\Form\Child\Http\ArrayOffsetHttpFields;
7
use Bdf\Form\Child\Http\HttpFieldPath;
8
use Bdf\Form\Child\Http\HttpFieldsInterface;
9
use Bdf\Form\ElementInterface;
10
use Bdf\Form\Error\FormError;
11
use Bdf\Form\Filter\FilterInterface;
12
use Bdf\Form\PropertyAccess\ExtractorInterface;
13
use Bdf\Form\PropertyAccess\HydratorInterface;
14
use Bdf\Form\Transformer\NullTransformer;
15
use Bdf\Form\Transformer\TransformerInterface;
16
use Bdf\Form\Util\HttpValue;
17
use Bdf\Form\View\ElementViewInterface;
18
use WeakReference;
19
20
/**
21
 * Child which extract HTTP field value from a simple array access
22
 */
23
final class Child implements ChildInterface
24
{
25
    /**
26
     * @var ElementInterface
27
     */
28
    private $element;
29
30
    /**
31
     * @var WeakReference<ChildAggregateInterface>
32
     */
33
    private $parent;
34
35
    /**
36
     * @var string
37
     */
38
    private $name;
39
40
    /**
41
     * @var HttpFieldsInterface
42
     */
43
    private $fields;
44
45
    /**
46
     * @var mixed
47
     */
48
    private $defaultValue;
49
50
    /**
51
     * @var FilterInterface[]
52
     */
53
    private $filters;
54
55
    /**
56
     * @var HydratorInterface|null
57
     */
58
    private $hydrator;
59
60
    /**
61
     * @var ExtractorInterface|null
62
     */
63
    private $extractor;
64
65
    /**
66
     * @var string[]
67
     */
68
    private $dependencies;
69
70
    /**
71
     * @var TransformerInterface
72
     */
73
    private $transformer;
74
75
76
    /**
77
     * ArrayOffsetChild constructor.
78
     *
79
     * @param string $name
80
     * @param ElementInterface $element
81
     * @param HttpFieldsInterface|null $fields
82
     * @param FilterInterface[] $filters
83
     * @param mixed $defaultValue
84
     * @param HydratorInterface|null $hydrator
85
     * @param ExtractorInterface|null $extractor
86
     * @param string[] $dependencies
87
     */
88 335
    public function __construct(string $name, ElementInterface $element, ?HttpFieldsInterface $fields = null, array $filters = [], $defaultValue = null, ?HydratorInterface $hydrator = null, ?ExtractorInterface $extractor = null, array $dependencies = [], ?TransformerInterface $transformer = null)
89
    {
90 335
        $this->name = $name;
91 335
        $this->element = $element->setContainer($this);
92 335
        $this->fields = $fields ?: new ArrayOffsetHttpFields($name);
93 335
        $this->defaultValue = $defaultValue;
94 335
        $this->filters = $filters;
95 335
        $this->hydrator = $hydrator;
96 335
        $this->extractor = $extractor;
97 335
        $this->dependencies = $dependencies;
98 335
        $this->transformer = $transformer ?? NullTransformer::instance();
99 335
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104 206
    public function element(): ElementInterface
105
    {
106 206
        return $this->element;
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     *
112
     * @psalm-suppress NullableReturnStatement
113
     * @psalm-suppress InvalidNullableReturnType
114
     */
115 94
    public function parent(): ChildAggregateInterface
116
    {
117 94
        return $this->parent->get();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->parent->get() could return the type null which is incompatible with the type-hinted return Bdf\Form\Aggregate\ChildAggregateInterface. Consider adding an additional type-check to rule them out.
Loading history...
118
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123 286
    public function setParent(ChildAggregateInterface $parent): ChildInterface
124
    {
125 286
        if ($this->parent === null) {
126 286
            $this->parent = WeakReference::create($parent);
127 286
            return $this;
128
        }
129
130 28
        $child = clone $this;
131 28
        $child->parent = WeakReference::create($parent);
132
133 28
        return $child;
134
    }
135
136
    /**
137
     * {@inheritdoc}
138
     */
139 228
    public function name(): string
140
    {
141 228
        return $this->name;
142
    }
143
144
    /**
145
     * {@inheritdoc}
146
     */
147 157
    public function dependencies(): array
148
    {
149 157
        return $this->dependencies;
150
    }
151
152
    /**
153
     * {@inheritdoc}
154
     */
155 40
    public function import($entity): void
156
    {
157 40
        if (!$this->extractor) {
158 2
            return;
159
        }
160
161
        /** @psalm-suppress PossiblyNullReference */
162 39
        $propertyAccessor = $this->parent->get()->root()->getPropertyAccessor();
163
164 39
        $this->extractor->setPropertyAccessor($propertyAccessor);
165 39
        $this->extractor->setFormElement($this);
166
167 39
        $value = $this->extractor->extract($entity);
168 39
        $value = $this->transformer->transformToHttp($value, $this->element);
169 39
        $this->extractor->setFormElement(null);
170
171 39
        $this->element->import($value);
172 39
    }
173
174
    /**
175
     * {@inheritdoc}
176
     */
177 55
    public function fill(&$entity): void
178
    {
179 55
        if (!$this->hydrator) {
180 2
            return;
181
        }
182
183
        /** @psalm-suppress PossiblyNullReference */
184 53
        $propertyAccessor = $this->parent->get()->root()->getPropertyAccessor();
185
186 53
        $this->hydrator->setPropertyAccessor($propertyAccessor);
187 53
        $this->hydrator->setFormElement($this);
188
189 53
        $value = $this->element->value();
190 53
        $value = $this->transformer->transformFromHttp($value, $this->element);
191
192 53
        $this->hydrator->hydrate($entity, $value);
193 53
        $this->hydrator->setFormElement(null);
194 53
    }
195
196
    /**
197
     * {@inheritdoc}
198
     */
199 131
    public function submit($data): bool
200
    {
201 131
        $value = $this->extractValue($data);
202
203 131
        return $this->element->submit($value)->valid();
204
    }
205
206
    /**
207
     * {@inheritdoc}
208
     */
209 12
    public function patch($data): bool
210
    {
211 12
        $value = $data !== null && $this->fields->contains($data)
212 9
            ? $this->extractValue($data)
213 12
            : null
214
        ;
215
216 12
        return $this->element->patch($value)->valid();
217
    }
218
219
    /**
220
     * {@inheritdoc}
221
     */
222 9
    public function httpFields(): array
223
    {
224 9
        return $this->fields->format($this->element->httpValue());
225
    }
226
227
    /**
228
     * {@inheritdoc}
229
     */
230 45
    public function error(?HttpFieldPath $field = null): FormError
231
    {
232 45
        return $this->element->error($this->fields->get($field));
233
    }
234
235
    /**
236
     * {@inheritdoc}
237
     */
238 14
    public function view(?HttpFieldPath $field = null): ElementViewInterface
239
    {
240 14
        return $this->element->view($this->fields->get($field));
241
    }
242
243
    /**
244
     * {@inheritdoc}
245
     */
246 28
    public function __clone()
247
    {
248 28
        $this->element = $this->element->setContainer($this);
249 28
    }
250
251
    /**
252
     * Extract HTTP value and apply filters
253
     *
254
     * @param mixed $httpValue
255
     * @return mixed The filtered value
256
     */
257 139
    private function extractValue($httpValue)
258
    {
259 139
        $value = $this->fields->extract($httpValue);
260 139
        $default = $this->defaultValue;
261
262 139
        foreach ($this->filters as $filter) {
263 90
            $value = $filter->filter($value, $this, $default);
264
        }
265
266 139
        return HttpValue::orDefault($value, $default);
267
    }
268
}
269