Skip to content

Commit 8bf6482

Browse files
committed
[Feature] StimulusBundle Form Extension
1 parent dec3eb3 commit 8bf6482

File tree

1 file changed

+141
-0
lines changed

1 file changed

+141
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Form\Extension;
6+
7+
use Symfony\Component\Form\AbstractTypeExtension;
8+
use Symfony\Component\Form\Extension\Core\Type\FormType;
9+
use Symfony\Component\Form\FormInterface;
10+
use Symfony\Component\Form\FormView;
11+
use Symfony\Component\OptionsResolver\OptionsResolver;
12+
use Symfony\UX\StimulusBundle\Dto\StimulusAttributes;
13+
use Twig\Environment;
14+
use Twig\Loader\ArrayLoader;
15+
16+
use function array_key_exists;
17+
use function array_merge;
18+
use function explode;
19+
use function implode;
20+
use function is_array;
21+
use function is_string;
22+
use function str_contains;
23+
24+
class FormTypeExtension extends AbstractTypeExtension
25+
{
26+
private StimulusAttributes $stimulusAttributes;
27+
28+
/**
29+
* @inheritDoc
30+
*/
31+
public static function getExtendedTypes(): iterable
32+
{
33+
return [FormType::class];
34+
}
35+
36+
/**
37+
* @inheritDoc
38+
*/
39+
public function buildView(FormView $view, FormInterface $form, array $options): void
40+
{
41+
if (
42+
$options['stimulus_controller'] === null
43+
&& $options['stimulus_target'] === null
44+
&& $options['stimulus_action'] === null
45+
) {
46+
return;
47+
}
48+
49+
$this->stimulusAttributes = new StimulusAttributes(new Environment(new ArrayLoader()));
50+
51+
if (array_key_exists('stimulus_controller', $options) === true) {
52+
$this->handleController($options['stimulus_controller']);
53+
}
54+
55+
if (array_key_exists('stimulus_target', $options) === true) {
56+
$this->handleTarget($options['stimulus_target']);
57+
}
58+
59+
if (array_key_exists('stimulus_action', $options) === true) {
60+
$this->handleAction($options['stimulus_action']);
61+
}
62+
63+
$attributes = array_merge($view->vars['attr'], $this->stimulusAttributes->toArray());
64+
65+
$view->vars['attr'] = $attributes;
66+
}
67+
68+
private function handleController(string|array $controllers): void
69+
{
70+
if (is_string($controllers)) {
71+
$controllers = [$controllers];
72+
}
73+
74+
foreach ($controllers as $controllerName => $controller) {
75+
if (is_string($controller)) { //'stimulus_controller' => ['controllerName1', 'controllerName2']
76+
$this->stimulusAttributes->addController($controller);
77+
} elseif (is_array($controller)) { //'stimulus_controller' => ['controllerName' => ['values' => ['key' => 'value'], 'classes' => ['key' => 'value'], 'targets' => ['otherControllerName' => '.targetName']]]
78+
$this->stimulusAttributes->addController((string) $controllerName, $controller['values'] ?? [], $controller['classes'] ?? [], $controller['outlets'] ?? []);
79+
}
80+
}
81+
}
82+
83+
private function handleTarget(array $targets): void
84+
{
85+
foreach ($targets as $controllerName => $target) {
86+
$this->stimulusAttributes->addTarget($controllerName, is_array($target) ? implode(' ', $target) : $target);
87+
}
88+
}
89+
90+
private function handleAction(string|array $actions): void
91+
{
92+
//'stimulus_action' => 'controllerName#actionName'
93+
//'stimulus_action' => 'eventName->controllerName#actionName'
94+
if (is_string($actions) && str_contains($actions, '#')) {
95+
$eventName = null;
96+
97+
if (str_contains($actions, '->')) {
98+
[$eventName, $rest] = explode('->', $actions, 2);
99+
} else {
100+
$rest = $actions;
101+
}
102+
103+
[$controllerName, $actionName] = explode('#', $rest, 2);
104+
105+
$this->stimulusAttributes->addAction($controllerName, $actionName, $eventName);
106+
107+
return;
108+
}
109+
110+
foreach ($actions as $controllerName => $action) {
111+
if (is_string($action)) { //'stimulus_action' => ['controllerName' => 'actionName']
112+
$this->stimulusAttributes->addAction($controllerName, $action);
113+
} elseif (is_array($action)) {
114+
foreach ($action as $eventName => $actionName) {
115+
if (is_string($actionName)) { //'stimulus_action' => ['controllerName' => ['eventName' => 'actionName']]
116+
$this->stimulusAttributes->addAction($controllerName, $actionName, $eventName);
117+
} elseif (is_array($actionName)) { //'stimulus_action' => ['controllerName' => ['eventName' => ['actionName' => ['key' => 'value']]]]
118+
foreach ($actionName as $index => $params) {
119+
$this->stimulusAttributes->addAction($controllerName, $index, $eventName, $params);
120+
}
121+
}
122+
}
123+
}
124+
}
125+
}
126+
127+
public function configureOptions(OptionsResolver $resolver): void
128+
{
129+
parent::configureOptions($resolver);
130+
131+
$resolver->setDefaults([
132+
'stimulus_action' => null,
133+
'stimulus_controller' => null,
134+
'stimulus_target' => null,
135+
]);
136+
137+
$resolver->setAllowedTypes('stimulus_action', ['string', 'array', 'null']);
138+
$resolver->setAllowedTypes('stimulus_controller', ['string', 'array', 'null']);
139+
$resolver->setAllowedTypes('stimulus_target', ['string', 'array', 'null']);
140+
}
141+
}

0 commit comments

Comments
 (0)