Passed
Branch master (3daac1)
by Vincent
07:53
created

RootForm::offsetExists()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Bdf\Form\Aggregate;
4
5
use BadMethodCallException;
6
use Bdf\Form\Button\ButtonInterface;
7
use Bdf\Form\Child\ChildInterface;
8
use Bdf\Form\Child\Http\HttpFieldPath;
9
use Bdf\Form\ElementInterface;
10
use Bdf\Form\Error\FormError;
11
use Bdf\Form\RootElementInterface;
12
use Bdf\Form\View\ElementViewInterface;
13
use Symfony\Component\PropertyAccess\PropertyAccess;
14
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
15
use Symfony\Component\Validator\Constraint;
16
use Symfony\Component\Validator\Validator\ValidatorInterface;
17
use Symfony\Component\Validator\ValidatorBuilder;
18
19
/**
20
 * Adapt a form element as root element
21
 * The root form handle constraint group, validator and property accessor instances, and submit button
22
 *
23
 * The root form should be used instead of the form element for `submit()`
24
 *
25
 * <code>
26
 * $form = new MyForm();
27
 *
28
 * $root = $form->root();
29
 * if (!$root->submit($request->post())->valid()) {
30
 *     throw new MyError();
31
 * }
32
 *
33
 * $entity = $root->value();
34
 *
35
 * switch ($btn = $root->submitButton() ? $btn->name() : null) {
36
 *     case 'save':
37
 *         return $this->save($entity);
38
 *
39
 *     case 'delete':
40
 *         return $this->delete($entity);
41
 *
42
 *     default:
43
 *         throw new InvalidAction();
44
 * }
45
 * </code>
46
 *
47
 * @todo delegation trait
48
 */
49
final class RootForm implements RootElementInterface, ChildAggregateInterface
50
{
51
    /**
52
     * @var Form
53
     */
54
    private $form;
55
56
    /**
57
     * @var ButtonInterface[]
58
     */
59
    private $buttons;
60
61
    /**
62
     * @var ButtonInterface|null
63
     */
64
    private $submitButton;
65
66
    /**
67
     * @var PropertyAccessorInterface|null
68
     */
69
    private $propertyAccessor;
70
71
    /**
72
     * @var ValidatorInterface|null
73
     */
74
    private $validator;
75
76
77
    /**
78
     * RootForm constructor.
79
     *
80
     * @param Form $form
81
     * @param ButtonInterface[] $buttons
82
     * @param PropertyAccessorInterface|null $propertyAccessor
83
     * @param ValidatorInterface|null $validator
84
     */
85 111
    public function __construct(Form $form, array $buttons = [], ?PropertyAccessorInterface $propertyAccessor = null, ?ValidatorInterface $validator = null)
86
    {
87 111
        $this->form = $form;
88 111
        $this->buttons = $buttons;
89 111
        $this->propertyAccessor = $propertyAccessor;
90 111
        $this->validator = $validator;
91 111
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96 25
    public function submit($data): ElementInterface
97
    {
98 25
        $this->submitToButtons($data);
99 25
        $this->form->submit($data);
100
101 25
        return $this;
102
    }
103
104
    /**
105
     * {@inheritdoc}
106
     */
107 3
    public function patch($data): ElementInterface
108
    {
109 3
        $this->submitToButtons($data);
110 3
        $this->form->patch($data);
111
112 3
        return $this;
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118 2
    public function import($entity): ElementInterface
119
    {
120 2
        $this->form->import($entity);
121
122 2
        return $this;
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128 1
    public function value()
129
    {
130 1
        return $this->form->value();
131
    }
132
133
    /**
134
     * {@inheritdoc}
135
     */
136 1
    public function httpValue()
137
    {
138 1
        return $this->form->httpValue();
139
    }
140
141
    /**
142
     * {@inheritdoc}
143
     */
144 1
    public function valid(): bool
145
    {
146 1
        return $this->form->valid();
147
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152 1
    public function error(): FormError
153
    {
154 1
        return $this->form->error();
155
    }
156
157
    /**
158
     * {@inheritdoc}
159
     */
160 1
    public function container(): ?ChildInterface
161
    {
162 1
        return null; // root cannot have a container
163
    }
164
165
    /**
166
     * {@inheritdoc}
167
     */
168
    public function setContainer(ChildInterface $container): ElementInterface
169
    {
170
        throw new BadMethodCallException('Cannot wrap a root element into a container');
171
    }
172
173
    /**
174
     * {@inheritdoc}
175
     */
176 1
    public function root(): RootElementInterface
177
    {
178 1
        return $this;
179
    }
180
181
    /**
182
     * {@inheritdoc}
183
     */
184 4
    public function view(?HttpFieldPath $field = null): ElementViewInterface
185
    {
186 4
        $buttons = [];
187
188 4
        foreach ($this->buttons as $button) {
189 2
            $buttons[$button->name()] = $button->view($field);
190
        }
191
192 4
        $view = $this->form->view($field);
193 4
        $view->setButtons($buttons);
194
195 4
        return $view;
196
    }
197
198
    /**
199
     * {@inheritdoc}
200
     */
201 4
    public function submitButton(): ?ButtonInterface
202
    {
203 4
        return $this->submitButton;
204
    }
205
206
    /**
207
     * {@inheritdoc}
208
     */
209 53
    public function getValidator(): ValidatorInterface
210
    {
211 53
        if ($this->validator === null) {
212 52
            $this->validator = (new ValidatorBuilder())->getValidator();
213
        }
214
215 53
        return $this->validator;
216
    }
217
218
    /**
219
     * {@inheritdoc}
220
     */
221 51
    public function getPropertyAccessor(): PropertyAccessorInterface
222
    {
223 51
        if ($this->propertyAccessor === null) {
224 50
            $this->propertyAccessor = PropertyAccess::createPropertyAccessor();
225
        }
226
227 51
        return $this->propertyAccessor;
228
    }
229
230
    /**
231
     * {@inheritdoc}
232
     */
233 52
    public function constraintGroups(): array
234
    {
235 52
        if (!$button = $this->submitButton) {
236 51
            return [Constraint::DEFAULT_GROUP];
237
        }
238
239 2
        return $button->constraintGroups() ?: [Constraint::DEFAULT_GROUP];
240
    }
241
242
    /**
243
     * {@inheritdoc}
244
     */
245 6
    public function offsetGet($offset): ChildInterface
246
    {
247 6
        return $this->form[$offset];
248
    }
249
250
    /**
251
     * {@inheritdoc}
252
     */
253 4
    public function offsetExists($offset): bool
254
    {
255 4
        return isset($this->form[$offset]);
256
    }
257
258
    /**
259
     * {@inheritdoc}
260
     */
261
    public function offsetSet($offset, $value)
262
    {
263
        $this->form[$offset] = $value;
264
    }
265
266
    /**
267
     * {@inheritdoc}
268
     */
269
    public function offsetUnset($offset)
270
    {
271
        unset($this->form[$offset]);
272
    }
273
274
    /**
275
     * {@inheritdoc}
276
     */
277
    public function getIterator()
278
    {
279
        return $this->form->getIterator();
280
    }
281
282
    /**
283
     * Submit HTTP fields to buttons
284
     *
285
     * @param mixed $data The HTTP value
286
     */
287 26
    private function submitToButtons($data): void
288
    {
289 26
        $this->submitButton = null;
290
291 26
        foreach ($this->buttons as $button) {
292 4
            if ($button->submit($data) && $this->submitButton === null) {
293 4
                $this->submitButton = $button;
294
            }
295
        }
296 26
    }
297
}
298