Skip to content

Commit

Permalink
[Feature] StimulusBundle Form Extension
Browse files Browse the repository at this point in the history
  • Loading branch information
19Gerhard85 committed Dec 18, 2024
1 parent dec3eb3 commit 3553f62
Showing 1 changed file with 141 additions and 0 deletions.
141 changes: 141 additions & 0 deletions src/StimulusBundle/src/Form/Extension/FormTypeExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?php

declare(strict_types=1);

namespace App\Form\Extension;

use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\UX\StimulusBundle\Dto\StimulusAttributes;
use Twig\Environment;
use Twig\Loader\ArrayLoader;

use function array_key_exists;
use function array_merge;
use function explode;
use function implode;
use function is_array;
use function is_string;
use function str_contains;

class FormTypeExtension extends AbstractTypeExtension
{
private StimulusAttributes $stimulusAttributes;

/**
* @inheritDoc
*/
public static function getExtendedTypes(): iterable
{
return [FormType::class];
}

/**
* @inheritDoc
*/
public function buildView(FormView $view, FormInterface $form, array $options): void
{
if (
$options['stimulus_controller'] === null
&& $options['stimulus_target'] === null
&& $options['stimulus_action'] === null
) {
return;
}

$this->stimulusAttributes = new StimulusAttributes(new Environment(new ArrayLoader()));

if (array_key_exists('stimulus_controller', $options) === true) {
$this->handleController($options['stimulus_controller']);
}

if (array_key_exists('stimulus_target', $options) === true) {
$this->handleTarget($options['stimulus_target']);
}

if (array_key_exists('stimulus_action', $options) === true) {
$this->handleAction($options['stimulus_action']);
}

$attributes = array_merge($view->vars['attr'], $this->stimulusAttributes->toArray());

$view->vars['attr'] = $attributes;
}

private function handleController(string|array $controllers): void
{
if (is_string($controllers)) {
$controllers = [$controllers];
}

foreach ($controllers as $controllerName => $controller) {
if (is_string($controller)) { //'stimulus_controller' => ['foo', 'bar']
$this->stimulusAttributes->addController($controller);
} elseif (is_array($controller)) { //'stimulus_controller' => ['controllerName' => ['values' => ['param1' => 'value1'], 'classes' => ['loading' => 'spinner'], 'targets' => ['other' => '.target']]]
$this->stimulusAttributes->addController((string) $controllerName, $controller['values'] ?? [], $controller['classes'] ?? [], $controller['outlets'] ?? []);
}
}
}

private function handleTarget(array $targets): void
{
foreach ($targets as $controllerName => $target) {
$this->stimulusAttributes->addTarget($controllerName, is_array($target) ? implode(' ', $target) : $target);
}
}

private function handleAction(string|array $actions): void
{
//'stimulus_action' => 'clipboard#copy'
//'stimulus_action' => 'click->clipboard#copy'
if (is_string($actions) && str_contains($actions, '#')) {
$eventName = null;

if (str_contains($actions, '->')) {
[$eventName, $rest] = explode('->', $actions, 2);
} else {
$rest = $actions;
}

[$controllerName, $actionName] = explode('#', $rest, 2);

$this->stimulusAttributes->addAction($controllerName, $actionName, $eventName);

return;
}

foreach ($actions as $controllerName => $action) {
if (is_string($action)) { //'stimulus_action' => ['controllerName' => 'actionName']
$this->stimulusAttributes->addAction($controllerName, $action);
} elseif (is_array($action)) {
foreach ($action as $eventName => $actionName) {
if (is_string($actionName)) { //'stimulus_action' => ['controllerName' => ['eventName' => 'actionName']]
$this->stimulusAttributes->addAction($controllerName, $actionName, $eventName);
} elseif (is_array($actionName)) { //'stimulus_action' => ['controllerName' => ['eventName' => ['actionName' => ['param1' => 'value1']]]]
foreach ($actionName as $index => $params) {
$this->stimulusAttributes->addAction($controllerName, $index, $eventName, $params);
}
}
}
}
}
}

public function configureOptions(OptionsResolver $resolver): void
{
parent::configureOptions($resolver);

$resolver->setDefaults([
'stimulus_action' => null,
'stimulus_controller' => null,
'stimulus_target' => null,
]);

$resolver->setAllowedTypes('stimulus_action', ['string', 'array', 'null']);
$resolver->setAllowedTypes('stimulus_controller', ['string', 'array', 'null']);
$resolver->setAllowedTypes('stimulus_target', ['string', 'array', 'null']);
}
}

0 comments on commit 3553f62

Please sign in to comment.