-
-
Notifications
You must be signed in to change notification settings - Fork 327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[StimulusBundle] Adds Form Extension #2450
base: 2.x
Are you sure you want to change the base?
[StimulusBundle] Adds Form Extension #2450
Conversation
8bf6482
to
281d55a
Compare
281d55a
to
be4394f
Compare
Continuing here the discussion from the issue #737 (comment)
The main question is "what is the end goal ?" This first draft only handle stimulus_* on the form type, but i'm not sure if this is the expected behaviour. How can i set an attribute on the row and another on the widget ? Right now user can set attributes (classes but also data-**) on |
Maybe simple static method could do most of the needs here? Stimulus::controller(....)
Stimulus::target($controller, $target) or builder-like Stimulus::controller(name)
->value(name, value)
->class(name, value)
->... |
f8b426f
to
2092187
Compare
2092187
to
92e2a5e
Compare
The FormTypeExtension works on forms and widgets, as long as the widget extends the AbstractType.
$builder->add('select', ChoiceType::class, [
'expanded' => true,
'choices' => ['foo' => 'foo', 'bar' => 'bar'],
'row_attr' => [
'class' => 'rowClass',
'stimulus_controller' => ['row/Controller']
],
'choice_attr' => [
'class' => 'choiceClass',
'stimulus_controller' => ['widget/Controller']
],
]);
<div class="rowClass form-group" data-controller="row--Controller">
<label class="control-label">Select</label>
<div id="test_form_select">
<div class="radio">
<label for="test_form_select_placeholder" class="">
<input type="radio" id="test_form_select_placeholder" name="test_form[select]" value="" checked="checked"> None
</label>
</div>
<div class="radio">
<label for="test_form_select_0" class="">
<input type="radio" id="test_form_select_0" name="test_form[select]" value="foo"> foo
</label>
</div>
<div class="radio">
<label for="test_form_select_1" class="">
<input type="radio" id="test_form_select_1" name="test_form[select]" value="bar"> bar
</label>
</div>
</div>
</div> |
In fact, choice_attr works "per choice". Examples from the doc: 'choice_attr' => [
'Apple' => ['data-color' => 'Red'],
'Banana' => ['data-color' => 'Yellow'],
'Durian' => ['data-color' => 'Green'],
], 'choice_attr' => function ($choice, string $key, mixed $value) {
// adds a class like attending_yes, attending_no, etc
return ['class' => 'attending_'.strtolower($key)];
}, And there is a static helper to defer the computation
Yep.. Do we want this is my point :) Or should this be configured / dynamic in any way ? |
@19Gerhard85 This extension is a very good idea, thanks for following up and taking charge of the topic! And let's keep the motivation high, even if it takes a few iterations! We're aiming for solid choices for the future, so let's stay the course—it’ll be worth it! Stimulus logic / objectI don't think we should have the parsing "logic" coded in here.. using a small dedicated object will simplify the code & its maintenance, and allow us to is elsewhere. This really is the occasion. NameLet's rename the extension StimulusFormExtension, ok for you ? (or anything with Stimulus in it :) ) I let some other comments in the code :) |
|
||
class FormTypeExtension extends AbstractTypeExtension | ||
{ | ||
private StimulusAttributes $stimulusAttributes; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is temporary right ?
I think we won't need it and use a new object but if we don't, you can inject the StimulusHelper here
public function buildView(FormView $view, FormInterface $form, array $options): void | ||
{ | ||
if ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this method you repeat two times the same code, this can be reduce a lot i think
$attributes = array_merge($view->vars['attr'], $this->stimulusAttributes->toArray()); | ||
$view->vars['attr'] = $attributes; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$attributes = array_merge($view->vars['attr'], $this->stimulusAttributes->toArray()); | |
$view->vars['attr'] = $attributes; | |
$view->vars['attr'] = [...$view->vars['attr'], ...$this->stimulusAttributes->toArray()]; |
Avoid unnecessary var
if (isset($options['stimulus_controller'])) { | ||
$this->handleController($options['stimulus_controller']); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (isset($options['stimulus_controller'])) { | |
$this->handleController($options['stimulus_controller']); | |
} | |
if ($options['stimulus_controller']) { | |
$this->handleController($options['stimulus_controller']); | |
} | |
// same for the other ones |
if ( | ||
isset($options['stimulus_controller']) | ||
|| !isset($options['stimulus_target']) | ||
|| !isset($options['stimulus_action']) | ||
) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if ( | |
isset($options['stimulus_controller']) | |
|| !isset($options['stimulus_target']) | |
|| !isset($options['stimulus_action']) | |
) { | |
if ($options['stimulus_controller'] || $options['stimulus_target'] || $options['stimulus_action']) { |
private function handleTarget(array $targets): void | ||
{ | ||
foreach ($targets as $controllerName => $target) { | ||
$this->stimulusAttributes->addTarget($controllerName, \is_array($target) ? implode(' ', $target) : $target); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be removed / inline when it is called
private function handleController(string|array $controllers): void | ||
{ | ||
if (\is_string($controllers)) { | ||
$controllers = [$controllers]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be handle outside this method i suppose (will call $this->stimulusAttributes->addController(...) every case)
// 'stimulus_action' => 'controllerName#actionName' | ||
// 'stimulus_action' => 'eventName->controllerName#actionName' | ||
if (\is_string($actions) && str_contains($actions, '#')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason i want another object, we should not have to duplicate this in multiple place. Will open a draft later if i can
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(i cannot 😅 🕐 )
😬 Sorry my fault > RTFM 😅 |
An object is definitely a better choice and easier to maintain. We can also enforce a syntax for the parameters. I have the next weeks off and will work on a nice object in "Builder style".
|
This PR adds a FromTypeExtension and adds the options
stimulus_controller
,stimulus_action
andstimulus_target
.Supported syntax:
stimulus_controller
stimulus_action
stimulus_target
Tests will follow when we finalized the syntax.