Passed
Push — master ( acf3f9...98cfe3 )
by Derek Stephen
03:04
created

AbstractForm::getFieldValues()   A

Complexity

Conditions 6
Paths 7

Size

Total Lines 30
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 16
c 1
b 0
f 0
dl 0
loc 30
ccs 17
cts 17
cp 1
rs 9.1111
cc 6
nc 7
nop 3
crap 6
1
<?php
2
3
namespace Del\Form;
4
5
use Del\Form\Collection\FieldCollection;
6
use Del\Form\Field\CheckBox;
7
use Del\Form\Field\FieldInterface;
8
use Del\Form\Field\FileUpload;
9
use Del\Form\Renderer\FormRenderer;
10
use Del\Form\Renderer\FormRendererInterface;
11
use Del\Form\Traits\HasAttributesTrait;
12
13
abstract class AbstractForm implements FormInterface
14
{
15
    const ENC_TYPE_MULTIPART_FORM_DATA = 'multipart/form-data';
16
    const ENC_TYPE_URL_ENCODED = 'application/x-www-form-urlencoded';
17
    const ENC_TYPE_TEXT_PLAIN = 'text/plain';
18
19
    const METHOD_POST = 'post';
20
    const METHOD_GET = 'get';
21
22
    /** @var FieldCollection $fieldCollection */
23
    private $fieldCollection;
24
25
    /** @var FormRendererInterface  */
26
    private $formRenderer;
27
28
    /** @var array $errorMessages */
29
    private $errorMessages;
30
31
    /** @var bool $displayErrors */
32
    private $displayErrors;
33
34
    use HasAttributesTrait;
35
36
    /**
37
     * AbstractForm constructor.
38
     * @param $name
39
     */
40 66
    public function __construct(string $name)
41
    {
42 66
        $this->fieldCollection = new FieldCollection();
43 66
        $this->formRenderer = new FormRenderer();
44 66
        $this->attributes = [
45 66
            'name' => $name,
46 66
            'method' => self::METHOD_POST,
47
        ];
48 66
        $this->displayErrors = false;
49 66
        $this->init();
50 66
    }
51
52
    abstract public function init();
53
54
    /**
55
     * @return bool
56
     * @throws \Exception
57
     */
58 15
    public function isValid(): bool
59
    {
60 15
        $this->errorMessages = [];
61 15
        $fields = $this->fieldCollection;
62 15
        $this->validateFields($fields);
63 15
        $count = count($this->errorMessages);
64 15
        $valid = ($count == 0);
65 15
        if ($valid) {
66 9
            $this->moveUploadedFiles();
67
        }
68 14
        return $valid;
69
    }
70
71 3
    public function getErrorMessages(): array
72
    {
73 3
        return $this->errorMessages;
74
    }
75
76
    /**
77
     * @param FieldCollection $fields
78
     * @throws \Exception
79
     */
80 15
    private function validateFields(FieldCollection $fields): void
81
    {
82 15
        $fields->rewind();
83 15
        while ($fields->valid()) {
84 15
            $this->checkFieldForErrors($fields->current());
85 15
            $this->checkDynamicFormsForErrors($fields->current());
86 15
            $fields->next();
87
        }
88 15
        $fields->rewind();
89 15
    }
90
91
    /**
92
     * @param FieldInterface $field
93
     * @throws \Exception
94
     */
95 15
    private function checkFieldForErrors(FieldInterface $field): void
96
    {
97 15
        if (!$field->isValid()) {
98 12
            $this->errorMessages[$field->getName()] = $field->getMessages();
99
        }
100 15
    }
101
102
    /**
103
     * @param FieldInterface $field
104
     */
105 15
    public function checkDynamicFormsForErrors(FieldInterface $field): void
106
    {
107 15
        if ($field->hasDynamicForms()) {
108 1
            $forms = $field->getDynamicForms();
109 1
            $value = $field->getValue();
110 1
            if (isset($forms[$value])) {
111 1
                $form = $forms[$value];
112 1
                $fields = $form->getFields();
113 1
                $this->validateFields($fields);
114
            }
115
        }
116 15
    }
117
118
    /**
119
     * @param bool $transform
120
     * @return array
121
     */
122 8
    public function getValues(bool $transform = false): array
123
    {
124 8
        $values = [];
125 8
        $fields = $this->fieldCollection;
126 8
        $values = $this->getFieldValues($fields, $values, $transform);
127
        
128 8
        return $values;
129
    }
130
131
    /**
132
     * @param FieldCollection $fields
133
     * @param array $values
134
     * @param bool $transform
135
     * @return array
136
     */
137 8
    private function getFieldValues(FieldCollection $fields, array $values, bool $transform): array
138
    {
139 8
        $fields->rewind();
140
141 8
        while ($fields->valid()) {
142
            /** @var FieldInterface $field */
143 8
            $field = $fields->current();
144 8
            $value = $field->getValue();
145
146 8
            if ($transform && $field->hasTransformer()) {
147 2
                $value = $field->getTransformer()->output($value);
148
            }
149
150 8
            $values[$field->getName()] = $value;
151
152 8
            if ($field->hasDynamicForms()) {
153 1
                $forms = $field->getDynamicForms();
154 1
                if (isset($forms[$value])) {
155 1
                    $form = $forms[$value];
156 1
                    $dynamicFormFields = $form->getFields();
157 1
                    $values = $this->getFieldValues($dynamicFormFields, $values, $transform);
158
                }
159
            }
160
161 8
            $fields->next();
162
        }
163
164 8
        $fields->rewind();
165
166 8
        return $values;
167
    }
168
169
    /**
170
     * @param array $data
171
     */
172 16
    public function populate(array $data): void
173
    {
174 16
        $fields = $this->fieldCollection;
175 16
        $this->populateFields($fields, $data);
176 16
        $this->displayErrors = true;
177 16
    }
178
179
    /**
180
     * @param array $dynamicForms
181
     * @param array $data
182
     */
183 2
    private function populateDynamicForms(array $dynamicForms, array $data): void
184
    {
185
        /** @var FormInterface $form **/
186 2
        foreach ($dynamicForms as $form) {
187 2
            $fields = $form->getFields();
188 2
            $this->populateFields($fields, $data);
189
        }
190 2
    }
191
192
    /**
193
     * @param FieldCollection $fields
194
     * @param array $data
195
     */
196 16
    private function populateFields(FieldCollection $fields, array $data): void
197
    {
198 16
        $fields->rewind();
199 16
        while ($fields->valid()) {
200 16
            $field = $fields->current();
201 16
            $this->populateField($field, $data);
202 16
            $fields->next();
203
        }
204 16
        $fields->rewind();
205 16
    }
206
207
    /**
208
     * @param FieldInterface $field
209
     * @param array $data
210
     */
211 16
    private function populateField(FieldInterface $field, array $data): void
212
    {
213 16
        $name = $field->getName();
214
215 16
        if (isset($data[$name]) && $field->hasTransformer()) {
216 2
            $value = $field->getTransformer()->input($data[$name]);
217 2
            $field->setValue($value);
218 14
        } elseif (isset($data[$name])) {
219 10
            $field->setValue($data[$name]);
220 9
        } elseif ($field instanceof CheckBox) {
221 1
            $field->setValue(false);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type string expected by parameter $value of Del\Form\Field\FieldAbstract::setValue(). ( Ignorable by Annotation )

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

221
            $field->setValue(/** @scrutinizer ignore-type */ false);
Loading history...
222
        }
223
224 16
        if ($field->hasDynamicForms()) {
225 2
            $forms = $field->getDynamicForms();
226 2
            $this->populateDynamicForms($forms, $data);
227
        }
228 16
    }
229
230
    /**
231
     * @param string $name
232
     * @return FieldInterface|null
233
     */
234 2
    public function getField(string $name): ?FieldInterface
235
    {
236 2
        return $this->fieldCollection->findByName($name);
237
    }
238
239
    /**
240
     * @return FieldCollection
241
     */
242 41
    public function getFields(): FieldCollection
243
    {
244 41
        return $this->fieldCollection;
245
    }
246
247
    /**
248
     * @param FieldInterface $field
249
     */
250 57
    public function addField(FieldInterface $field): void
251
    {
252 57
        $this->fieldCollection->append($field);
253 57
    }
254
255
    /**
256
     * @return string
257
     */
258 36
    public function render(): string
259
    {
260 36
        return $this->formRenderer->render($this, $this->isDisplayErrors());
261
    }
262
263
    /**
264
     * @param $url
265
     */
266 2
    public function setAction(string $url): void
267
    {
268 2
        $this->setAttribute('action', $url);
269 2
    }
270
271
    /**
272
     * @return string
273
     */
274 2
    public function getAction(): string
275
    {
276 2
        return $this->getAttribute('action');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getAttribute('action') could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
277
    }
278
279
    /**
280
     * @return string
281
     */
282 37
    public function getId(): ?string
283
    {
284 37
        return $this->getAttribute('id');
285
    }
286
287
    /**
288
     * @param string $id
289
     */
290 2
    public function setId(string $id): void
291
    {
292 2
        $this->setAttribute('id', $id);
293 2
    }
294
295
    /**
296
     * @param $encType
297
     */
298 2
    public function setEncType(string $encType): void
299
    {
300 2
        $this->setAttribute('enctype', $encType);
301 2
    }
302
303
    /**
304
     * @return string
305
     */
306 1
    public function getEncType(): string
307
    {
308 1
        return $this->getAttribute('enctype');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getAttribute('enctype') could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
309
    }
310
311
    /**
312
     * @param string $method
313
     * @return FormInterface
314
     */
315 2
    public function setMethod(string $method): void
316
    {
317 2
        $this->setAttribute('method', $method);
318 2
    }
319
320
    /**
321
     * @return string
322
     */
323 37
    public function getMethod(): string
324
    {
325 37
        return $this->getAttribute('method');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getAttribute('method') could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
326
    }
327
328
    /**
329
     * @param $class
330
     */
331 2
    public function setClass(string $class): void
332
    {
333 2
        $this->setAttribute('class', $class);
334 2
    }
335
336
    /**
337
     * @return string
338
     */
339 2
    public function getClass(): string
340
    {
341 2
        return $this->getAttribute('class');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getAttribute('class') could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
342
    }
343
344
    /**
345
     * @return boolean
346
     */
347 37
    public function isDisplayErrors(): bool
348
    {
349 37
        return $this->displayErrors;
350
    }
351
352
    /**
353
     * @param boolean $displayError
354
     */
355 3
    public function setDisplayErrors(bool $displayErrors): void
356
    {
357 3
        $this->displayErrors = $displayErrors;
358 3
    }
359
360
    /**
361
     * @param FormRendererInterface $renderer
362
     * @return AbstractForm
363
     */
364 5
    public function setFormRenderer(FormRendererInterface $renderer): AbstractForm
365
    {
366 5
        $this->formRenderer = $renderer;
367
368 5
        return $this;
369
    }
370
371 9
    public function moveUploadedFiles(): void
372
    {
373 9
        $this->fieldCollection->rewind();
374 9
        while ($this->fieldCollection->valid()) {
375 9
            $current = $this->fieldCollection->current();
376 9
            $this->moveFileIfUploadField($current);
377 8
            $this->fieldCollection->next();
378
        }
379 8
    }
380
381
    /**
382
     * @param FieldInterface $field
383
     * @return bool
384
     */
385 9
    public function moveFileIfUploadField(FieldInterface $field): bool
386
    {
387 9
        if ($field instanceof FileUpload) {
388 2
            $field->moveUploadToDestination();
389 1
            return true;
390
        }
391 7
        return false;
392
    }
393
}