Passed
Push — master ( ea4e6c...05ab19 )
by Vincent
02:14 queued 34s
created

CustomForm::offsetSet()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 0
cts 2
cp 0
rs 10
cc 1
nc 1
nop 2
crap 2
1
<?php
2
3
namespace Bdf\Form\Custom;
4
5
use Bdf\Form\Aggregate\FormBuilder;
6
use Bdf\Form\Aggregate\FormBuilderInterface;
7
use Bdf\Form\Aggregate\FormInterface;
8
use Bdf\Form\Aggregate\View\FormView;
9
use Bdf\Form\Child\ChildInterface;
10
use Bdf\Form\Child\Http\HttpFieldPath;
11
use Bdf\Form\ElementInterface;
12
use Bdf\Form\Error\FormError;
13
use Bdf\Form\RootElementInterface;
14
use Bdf\Form\View\ElementViewInterface;
15
use Iterator;
16
17
/**
18
 * Utility class for simply create a custom form element
19
 *
20
 * <code>
21
 * // Declaration
22
 * class MyForm extends CustomForm
23
 * {
24
 *     public function configure(FormBuilderInterface $builder)
25
 *     {
26
 *         $builder->generates(MyEntity::class);
27
 *         $builder->string('foo')->setter();
28
 *     }
29
 * }
30
 *
31
 * // Usage
32
 * $form = new MyForm(); // Directly instantiate the form
33
 * $form = $this->registry->elementBuilder(MyForm::class)->buildElement(); // Use registry and builder
34
 *
35
 * if (!$form->submit($request->post())->valid()) {
36
 *     return new JsonResponse($form->error()->print(new FormErrorFormat()), 400);
37
 * }
38
 *
39
 * $entity = $form->value();
40
 * $this->service->handle($entity);
41
 *
42
 * return new Response('OK', 200);
43
 * </code>
44
 *
45
 * @todo implements root form interface ?
46
 * @template T
47
 * @implements FormInterface<T>
48
 */
49
abstract class CustomForm implements FormInterface
50
{
51
    /**
52
     * @var FormBuilderInterface
53
     */
54
    private $builder;
55
56
    /**
57
     * The inner form
58
     *
59
     * @var FormInterface<T>|null
60
     */
61
    private $form;
62
63
    /**
64
     * @var list<callable(static, FormBuilderInterface): void>
0 ignored issues
show
Bug introduced by
The type Bdf\Form\Custom\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
65
     */
66
    private $preConfigureHooks = [];
67
68
    /**
69
     * @var list<callable(static, FormInterface<T>): void>
70
     */
71
    private $postConfigureHooks = [];
72
73
    /**
74
     * CustomForm constructor.
75
     *
76
     * @param FormBuilderInterface|null $builder
77
     */
78 42
    public function __construct(?FormBuilderInterface $builder = null)
79
    {
80 42
        $this->builder = $builder ?? new FormBuilder();
81 42
    }
82
83
    /**
84
     * {@inheritdoc}
85
     */
86 18
    public function offsetGet($offset): ChildInterface
87
    {
88 18
        return $this->form()[$offset];
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94 10
    public function offsetExists($offset): bool
95
    {
96 10
        return isset($this->form()[$offset]);
97
    }
98
99
    /**
100
     * {@inheritdoc}
101
     */
102
    public function offsetSet($offset, $value): void
103
    {
104
        $this->form()[$offset] = $value;
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110
    public function offsetUnset($offset): void
111
    {
112
        unset($this->form()[$offset]);
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118 1
    public function getIterator(): Iterator
119
    {
120 1
        return $this->form()->getIterator();
121
    }
122
123
    /**
124
     * {@inheritdoc}
125
     */
126 25
    public function submit($data): ElementInterface
127
    {
128 25
        $this->submitTarget()->submit($data);
129
130 25
        return $this;
131
    }
132
133
    /**
134
     * {@inheritdoc}
135
     */
136 2
    public function patch($data): ElementInterface
137
    {
138 2
        $this->submitTarget()->patch($data);
139
140 2
        return $this;
141
    }
142
143
    /**
144
     * {@inheritdoc}
145
     */
146 2
    public function import($entity): ElementInterface
147
    {
148 2
        $this->form()->import($entity);
149
150 2
        return $this;
151
    }
152
153
    /**
154
     * {@inheritdoc}
155
     */
156 12
    public function value()
157
    {
158 12
        return $this->form()->value();
159
    }
160
161
    /**
162
     * {@inheritdoc}
163
     */
164 1
    public function httpValue()
165
    {
166 1
        return $this->form()->httpValue();
167
    }
168
169
    /**
170
     * {@inheritdoc}
171
     */
172 18
    public function valid(): bool
173
    {
174 18
        return $this->form()->valid();
175
    }
176
177
    /**
178
     * {@inheritdoc}
179
     */
180 4
    public function error(?HttpFieldPath $field = null): FormError
181
    {
182 4
        return $this->form()->error($field);
183
    }
184
185
    /**
186
     * {@inheritdoc}
187
     */
188 3
    public function container(): ?ChildInterface
189
    {
190 3
        return $this->form()->container();
191
    }
192
193
    /**
194
     * {@inheritdoc}
195
     */
196 6
    public function setContainer(ChildInterface $container): ElementInterface
197
    {
198 6
        $form = clone $this;
199 6
        $form->form = $this->form()->setContainer($container);
200
201 6
        return $form;
202
    }
203
204
    /**
205
     * {@inheritdoc}
206
     */
207 3
    public function root(): RootElementInterface
208
    {
209
        // @todo bad root form ?
210 3
        return $this->form()->root();
211
    }
212
213
    /**
214
     * {@inheritdoc}
215
     */
216 1
    public function attach($entity): FormInterface
217
    {
218 1
        $this->form()->attach($entity);
219
220 1
        return $this;
221
    }
222
223
    /**
224
     * {@inheritdoc}
225
     */
226 4
    public function view(?HttpFieldPath $field = null): ElementViewInterface
227
    {
228 4
        $form = $this->form();
229
        /** @var FormView $view */
230 4
        $view = $form->container() === null
231 4
            ? $form->root()->view($field)
232 4
            : $form->view($field)
233
        ;
234
235 4
        $view->setType(static::class);
236
237 4
        return $view;
238
    }
239
240
    /**
241
     * Configure the form using the builder
242
     *
243
     * @param FormBuilder $builder
244
     */
245
    abstract protected function configure(FormBuilderInterface $builder): void;
246
247
    /**
248
     * Override this method to hook the inner form build
249
     *
250
     * <code>
251
     * class MyForm extends CustomForm
252
     * {
253
     *     public $foo;
254
     *     public function configure(FormBuilderInterface $builder): void
255
     *     {
256
     *         $builder->string('foo');
257
     *     }
258
     *
259
     *     public function postConfigure(FormInterface $form): void
260
     *     {
261
     *         // Get the "foo" children
262
     *         $this->foo = $form['foo'];
263
     *     }
264
     * }
265
     * </code>
266
     *
267
     * @param FormInterface $form The inner form built instance
268
     */
269 40
    public function postConfigure(FormInterface $form): void
0 ignored issues
show
Unused Code introduced by
The parameter $form is not used and could be removed. ( Ignorable by Annotation )

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

269
    public function postConfigure(/** @scrutinizer ignore-unused */ FormInterface $form): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
270
    {
271
        // to overrides
272 40
    }
273
274
    /**
275
     * Define hooks called before the form is built
276
     * @param list<callable(static, FormBuilderInterface):void> $hooks
277
     * @return void
278
     * @internal This method should be called by the {@see CustomFormBuilder}
279
     */
280 15
    final public function setPreConfigureHooks(array $hooks): void
281
    {
282 15
        $this->preConfigureHooks = $hooks;
0 ignored issues
show
Documentation Bug introduced by
It seems like $hooks of type array is incompatible with the declared type Bdf\Form\Custom\list of property $preConfigureHooks.

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...
283 15
    }
284
285
    /**
286
     * Define hooks hook called after the form is built
287
     * @param list<callable(static, FormInterface<T>):void> $hooks
288
     * @return void
289
     * @internal This method should be called by the {@see CustomFormBuilder}
290
     */
291 15
    final public function setPostConfigureHooks(array $hooks): void
292
    {
293 15
        $this->postConfigureHooks = $hooks;
0 ignored issues
show
Documentation Bug introduced by
It seems like $hooks of type array is incompatible with the declared type Bdf\Form\Custom\list of property $postConfigureHooks.

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...
294 15
    }
295
296
    /**
297
     * Get (or build) the inner form
298
     *
299
     * @return FormInterface<T>
300
     */
301 41
    final protected function form(): FormInterface
302
    {
303 41
        if ($this->form) {
304 37
            return $this->form;
305
        }
306
307
        /** @var static $this Psalm cannot infer this type */
308
309 41
        foreach ($this->preConfigureHooks as $hook) {
310 1
            $hook($this, $this->builder);
311
        }
312
313
        /** @psalm-suppress ArgumentTypeCoercion */
314 41
        $this->configure($this->builder);
315
316 41
        $form = $this->form = $this->builder->buildElement();
317 41
        $this->postConfigure($form);
318
319 41
        foreach ($this->postConfigureHooks as $hook) {
320 1
            $hook($this, $form);
321
        }
322
323 41
        return $form;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $form returns the type Bdf\Form\ElementInterface which includes types incompatible with the type-hinted return Bdf\Form\Aggregate\FormInterface.
Loading history...
324
    }
325
326
    /**
327
     * Get the submit target element
328
     * This element must be used for all submit or patch call
329
     * Handle submit button if the current form is the root element
330
     *
331
     * @return ElementInterface
332
     */
333 27
    final protected function submitTarget(): ElementInterface
334
    {
335 27
        $form = $this->form();
336
337
        // The form is the root form
338 27
        if ($form->container() === null) {
339 25
            return $form->root();
340
        }
341
342 4
        return $form;
343
    }
344
}
345