Skip to content

Commit 65eaaa6

Browse files
committed
AttributeBuilder
1 parent 92e2a5e commit 65eaaa6

File tree

3 files changed

+204
-162
lines changed

3 files changed

+204
-162
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\UX\StimulusBundle\Builder;
13+
14+
use Symfony\UX\StimulusBundle\Helper\StimulusSyntaxHelper;
15+
16+
class StimulusAttributeBuilder
17+
{
18+
private string $controllerName;
19+
private array $actions = [];
20+
private array $values = [];
21+
private array $classes = [];
22+
private array $targets = [];
23+
private array $outlets = [];
24+
private array $attributes = [];
25+
26+
public static function controller(string $controllerName): self
27+
{
28+
$builder = new self();
29+
$builder->controllerName = $controllerName;
30+
31+
return $builder;
32+
}
33+
34+
public function action(string $actionName, ?string $eventName = null, array $parameters = []): self
35+
{
36+
$this->actions[] = [
37+
'actionName' => $actionName,
38+
'eventName' => $eventName,
39+
'parameters' => $parameters,
40+
];
41+
42+
return $this;
43+
}
44+
45+
public function value(string $key, mixed $value): self
46+
{
47+
$this->values[$key] = $value;
48+
49+
return $this;
50+
}
51+
52+
public function class(string $key, mixed $value): self
53+
{
54+
$this->classes[$key] = $value;
55+
56+
return $this;
57+
}
58+
59+
public function target(string $key, mixed $value): self
60+
{
61+
$this->targets[$key] = $value;
62+
63+
return $this;
64+
}
65+
66+
public function outlet(string $identifier, string $outlet, mixed $selector): self
67+
{
68+
$this->outlets[] = [
69+
'identifier' => $identifier,
70+
'outlet' => $outlet,
71+
'selector' => $selector,
72+
];
73+
74+
return $this;
75+
}
76+
77+
public function build(): array
78+
{
79+
$syntaxHelper = new StimulusSyntaxHelper();
80+
$controllerName = $syntaxHelper->normalizeControllerName($this->controllerName);
81+
82+
$this->attributes['data-controller'] = $controllerName;
83+
84+
// Actions
85+
$this->attributes = array_merge(
86+
$this->attributes,
87+
...array_map(function (array $actionData) use ($controllerName): array {
88+
$actionName = htmlspecialchars($actionData['actionName']);
89+
$eventName = $actionData['eventName'];
90+
91+
$action = \sprintf('%s#%s', $controllerName, $actionName);
92+
if (null !== $eventName) {
93+
$action = \sprintf('%s->%s', htmlspecialchars($eventName), $action);
94+
}
95+
96+
return ['data-action' => $action];
97+
}, $this->actions)
98+
);
99+
100+
// Action Parameters
101+
$this->attributes = array_merge(
102+
$this->attributes,
103+
...array_map(
104+
function (array $actionData) use ($controllerName, $syntaxHelper): array {
105+
$parameters = [];
106+
107+
foreach ($actionData['parameters'] as $name => $value) {
108+
$key = $syntaxHelper->normalizeKeyName($name);
109+
$value = $syntaxHelper->getFormattedValue($value);
110+
111+
$parameters[\sprintf(
112+
'data-%s-%s-param',
113+
$controllerName,
114+
$key
115+
)] = htmlspecialchars($value);
116+
}
117+
118+
return $parameters;
119+
},
120+
$this->actions
121+
)
122+
);
123+
124+
// Values
125+
foreach ($this->values as $key => $value) {
126+
if (null === $value) {
127+
continue;
128+
}
129+
130+
$key = $syntaxHelper->normalizeKeyName($key);
131+
$value = $syntaxHelper->getFormattedValue($value);
132+
133+
$this->attributes[\sprintf('data-%s-%s-value', $controllerName, $key)] = $value;
134+
}
135+
136+
// Classes
137+
foreach ($this->classes as $key => $class) {
138+
$key = $syntaxHelper->normalizeKeyName($key);
139+
140+
$this->attributes[\sprintf('data-%s-%s-class', $controllerName, $key)] = $class;
141+
}
142+
143+
// Outlets
144+
foreach ($this->outlets as $outletItem) {
145+
$identifier = $syntaxHelper->normalizeControllerName($outletItem['identifier']);
146+
$outlet = $syntaxHelper->normalizeKeyName($outletItem['outlet']);
147+
148+
$this->attributes[\sprintf('data-%s-%s-outlet', $identifier, $outlet)] = htmlspecialchars(
149+
$outletItem['selector']
150+
);
151+
}
152+
153+
// Targets
154+
foreach ($this->targets as $key => $target) {
155+
$key = $syntaxHelper->normalizeKeyName($key);
156+
157+
$this->attributes[\sprintf('data-%s-target', $key)] = htmlspecialchars($target);
158+
}
159+
160+
return $this->attributes;
161+
}
162+
}

src/StimulusBundle/src/Form/Extension/FormTypeExtension.php

-162
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\UX\StimulusBundle\Helper;
13+
14+
class StimulusSyntaxHelper
15+
{
16+
public function normalizeControllerName(string $controllerName): string
17+
{
18+
return preg_replace('/^@/', '', str_replace('_', '-', str_replace('/', '--', $controllerName)));
19+
}
20+
21+
public function normalizeKeyName(string $str): string
22+
{
23+
// Adapted from ByteString::camel
24+
$str = ucfirst(str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $str))));
25+
26+
// Adapted from ByteString::snake
27+
return strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'], '\1-\2', $str));
28+
}
29+
30+
public function getFormattedValue(mixed $value): string
31+
{
32+
if ($value instanceof \Stringable || (\is_object($value) && \is_callable([$value, '__toString']))) {
33+
$value = (string) $value;
34+
} elseif (!\is_scalar($value)) {
35+
$value = json_encode($value);
36+
} elseif (\is_bool($value)) {
37+
$value = $value ? 'true' : 'false';
38+
}
39+
40+
return (string) $value;
41+
}
42+
}

0 commit comments

Comments
 (0)