AddElements::populateInputs()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 14
cts 14
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 11
nc 3
nop 2
crap 3
1
<?php
2
3
/**
4
 * This file is part of slick/form package
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace Slick\Form\Parser\Worker;
11
12
use Slick\Filter\StaticFilter;
13
use Slick\Form\Element\Button;
14
use Slick\Form\Element\ChoiceAwareElementInterface;
15
use Slick\Form\Element\ContainerInterface;
16
use Slick\Form\Element\FieldSet;
17
use Slick\Form\Element\Label;
18
use Slick\Form\Element\Reset;
19
use Slick\Form\Element\Submit;
20
use Slick\Form\ElementInterface;
21
use Slick\Form\Exception\InvalidArgumentException;
22
use Slick\Form\Input\Checkbox;
23
use Slick\Form\Input\File;
24
use Slick\Form\Input\Filter\Boolean;
25
use Slick\Form\Input\Hidden;
26
use Slick\Form\Input\Password;
27
use Slick\Form\Input\Select;
28
use Slick\Form\Input\Text;
29
use Slick\Form\Input\TextArea;
30
use Slick\Form\InputInterface;
31
use Slick\Form\Parser\WorkerInterface;
32
33
/**
34
 * Add Elements to the form
35
 *
36
 * @package Slick\Form\Parser\Worker
37
 * @author  Filipe Silva <[email protected]>
38
 */
39
class AddElements implements WorkerInterface
40
{
41
    /**
42
     * @var array Available form elements
43
     */
44
    public static $elements = [
45
        'button'   => Button::class,
46
        'fieldset' => FieldSet::class,
47
        'label'    => Label::class,
48
        'reset'    => Reset::class,
49
        'submit'   => Submit::class,
50
        'checkbox' => Checkbox::class,
51
        'hidden'   => Hidden::class,
52
        'password' => Password::class,
53
        'select'   => Select::class,
54
        'text'     => Text::class,
55
        'textarea' => TextArea::class,
56
        'file'     => File::class
57
    ];
58
59
    /**
60
     * @var array List of validators that adds required attribute to input
61
     */
62
    public static $triggerRequired = [
63
        'notEmpty', 'email', 'url'
64
    ];
65
    
66
    private static $form;
67
68
    /**
69
     * Adds or changes a specific aspect of provided from
70
     *
71
     * @param ContainerInterface $form
72
     * @param array $data
73
     *
74
     * @return void
75
     */
76 36
    public static function execute(ContainerInterface $form, array $data)
77
    {
78 36
        self::$form = $form;
79 36
        $hasElements = isset($data['elements']) && is_array($data['elements']);
80 36
        if (!$hasElements) {
81 2
            return;
82
        }
83
84 36
        foreach ($data['elements'] as $name => $element) {
85 36
            $input = self::create($element);
86 36
            self::setSettings($input, $element);
87 36
            $input->setName($name);
88 36
            self::populateInputs($input, $element);
89 36
            $form->add($input);
90 36
        }
91 36
    }
92
93
    /**
94
     * Recursively creates the elements to add to the form
95
     *
96
     * @param array $element
97
     *
98
     * @return ElementInterface
99
     */
100 36
    protected static function create(array $element)
101
    {
102 36
        $class = self::getClassName($element['type']);
103 36
        $object = new $class;
104 36
        if ($object instanceof ContainerInterface) {
105 30
            static::execute($object, $element);
106 30
        }
107 36
        return $object;
108
    }
109
110
    /**
111
     * Sets the properties and dependencies for input elements
112
     *
113
     * @param ElementInterface $input
114
     * @param array $data
115
     */
116 36
    protected static function populateInputs(
117
        ElementInterface $input, array $data
118
    ) {
119 36
        if ($input instanceof InputInterface) {
120 36
            self::addLabel($input, $data);
121 36
            self::addValidators($input, $data);
122 36
            self::setFilters($input, $data);
123 36
            self::addOptions($input, $data);
124 36
            if (isset($data['required'])) {
125 30
                $input->setRequired(
126 30
                    StaticFilter::filter(Boolean::class, $data['required'])
127 30
                );
128 30
            }
129 36
        }
130
131 36
        self::populateElement($input, $data);
132 36
    }
133
134
    /**
135
     * Sets the properties and dependencies for HTML elements
136
     *
137
     * @param ElementInterface $elm
138
     * @param array $data
139
     */
140 36
    protected static function populateElement(ElementInterface $elm, array $data)
141
    {
142 36
        self::setValue($elm, $data);
143
144 36
        $hasAttributes = isset($data['attributes'])
145 36
            && is_array($data['attributes']);
146 36
        if (! $hasAttributes) {
147 30
            return;
148
        }
149
150 36
        foreach ($data['attributes'] as $attribute => $value) {
151 36
            $elm->setAttribute($attribute, $value);
152 36
        }
153 36
    }
154
155
    /**
156
     * Adds the value to the element
157
     *
158
     * @param ElementInterface $elm
159
     * @param array $data
160
     */
161 36
    protected static function setValue(ElementInterface $elm, $data)
162
    {
163 36
        if (isset($data['value'])) {
164 30
            $elm->setValue($data['value']);
165 30
        }
166 36
    }
167
168
    /**
169
     * Check the element alias or FQ class name
170
     *
171
     * @param string $type
172
     *
173
     * @return string The Element class name
174
     */
175 36
    protected static function getClassName($type)
176
    {
177 36
        if (in_array($type, array_keys(self::$elements))) {
178 36
            $type = self::$elements[$type];
179 36
        }
180
181 36
        if (!class_exists($type)) {
182 2
            throw new InvalidArgumentException(
183 2
                "Input class '{$type}' does not exists."
184 2
            );
185
        }
186
187 36
        if (! is_subclass_of($type, ElementInterface::class)) {
188 2
            throw new InvalidArgumentException(
189 2
                "The class '{$type}' does not implement the " .
190
                "Slick\\Form\\ElementInterface interface."
191 2
            );
192
        }
193
194 36
        return $type;
195
    }
196
197
    /**
198
     * Add filter to the input filter chain
199
     *
200
     * @param InputInterface $input
201
     * @param array $data
202
     */
203 36
    protected static function setFilters(InputInterface $input, array $data)
204
    {
205 36
        $hasFilters = isset($data['filters']) && is_array($data['filters']);
206 36
        if (!$hasFilters) {
207 36
            return;
208
        }
209
210 30
        foreach ($data['filters'] as $filter) {
211 30
            $input->addFilter($filter);
212 30
        }
213 30
    }
214
215
    /**
216
     * Add validators to the input validator chain
217
     *
218
     * @param InputInterface $input
219
     * @param array $data
220
     */
221 36
    protected static function addValidators(InputInterface $input, array $data)
222
    {
223 36
        $hasValidators = isset($data['validates']) && is_array($data['validates']);
224 36
        if (! $hasValidators) {
225 36
            return;
226
        }
227
228 30
        foreach ($data['validates'] as $validator => $message) {
229 30
            self::checkIfRequired($validator, $input);
230 30
            if (!is_array($message)) {
231 30
                $message = ['message' => $message];
232 30
            }
233 30
            $message['form'] = self::$form;
234 30
            $input->addValidator($validator, $message);
0 ignored issues
show
Documentation introduced by
$message is of type array<string,object<Slic...\ContainerInterface>"}>, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
235 30
        }
236 30
    }
237
238
    /**
239
     * Adds the html Label element to input
240
     *
241
     * @param InputInterface $input
242
     * @param array $data
243
     */
244 36
    protected static function addLabel(InputInterface $input, array $data)
245
    {
246 36
        if (!isset($data['label'])) {
247 2
            return;
248
        }
249 36
        if (is_string($data['label'])) {
250 36
            $input->setLabel($data['label']);
251 36
            return;
252
        }
253
254 30
        $label = new Label('', $data['label']['value']);
255 30
        self::populateElement($label, $data['label']);
256 30
        $input->setLabel($label);
257 30
    }
258
259
    /**
260
     * Check if validator triggers the required attribute
261
     *
262
     * @param string $name Validator name
263
     * @param InputInterface $input
264
     */
265 30
    protected static function checkIfRequired($name, InputInterface $input)
266
    {
267 30
        if (in_array($name, self::$triggerRequired)) {
268 30
            $input->setAttribute('required');
269 30
        }
270 30
    }
271
272
    /**
273
     * Set options for ChoiceAwareElementInterface input types like Select
274
     *
275
     * @param InputInterface $input
276
     * @param $data
277
     */
278 36
    protected static function addOptions(InputInterface $input, $data)
279
    {
280
        if (
281 36
            ! $input instanceof ChoiceAwareElementInterface ||
282 30
            ! isset($data['options'])
283 36
        ) {
284 36
            return;
285
        }
286
287 30
        $input->setOptions($data['options']);
288 30
    }
289
    
290 36
    protected static function setSettings(ElementInterface $input, $data)
291
    {
292 36
        if (isset($data['settings'])) {
293
            $input->setSettings($data['settings']);
294
        }
295 36
    }
296
297
}