Skip to content

Commit 01f565f

Browse files
committed
[Twig] ComponentAttributes::append()/prepend()
1 parent 2265069 commit 01f565f

File tree

5 files changed

+65
-35
lines changed

5 files changed

+65
-35
lines changed

src/TwigComponent/doc/index.rst

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -952,14 +952,21 @@ Render
952952

953953
The ability to *render* attributes was added in TwigComponents 2.15.
954954

955+
.. versionadded:: 2.15
956+
957+
The ability to *render* attributes with a default, *prepend*, and *append* were
958+
added in TwigComponents 2.15.
959+
955960
You can take full control over the attributes that are rendered by using the
956-
``render()`` method.
961+
``render()``, ``prepend()``, and ``append()`` methods.
957962

958963
.. code-block:: html+twig
959964

960965
{# templates/components/MyComponent.html.twig #}
961966
<div
962-
style="{{ attributes.render('style') }} display:block;"
967+
class="{{ attributes.render('class', 'default') }}" {# second parameter is the default value #}
968+
style="{{ attributes.append('style', 'display:block;') }}" {# second parameter value to append #}
969+
data-controller="{{ attributes.append('data-controller', 'hello-controller') }}" {# second parameter value to prepend #}
963970
{{ attributes }} {# be sure to always render the remaining attributes! #}
964971
>
965972
My Component!
@@ -969,15 +976,15 @@ You can take full control over the attributes that are rendered by using the
969976
{{ component('MyComponent', { style: 'color:red;' }) }}
970977

971978
{# renders as: #}
972-
<div style="color:red; display:block;">
979+
<div class="default" style="color:red; display:block;" data-controller="hello-controller">
973980
My Component!
974981
</div>
975982

976983
.. caution::
977984

978-
There are a few important things to know about using ``render()``:
985+
There are a few important things to know about using ``render()``/``prepend()``/``append()``:
979986

980-
1. You need to be sure to call your ``render()`` methods before calling ``{{ attributes }}`` or some
987+
1. You need to be sure to call these methods before calling ``{{ attributes }}`` or some
981988
attributes could be rendered twice. For instance:
982989

983990
.. code-block:: html+twig
@@ -998,7 +1005,7 @@ You can take full control over the attributes that are rendered by using the
9981005
My Component!
9991006
</div>
10001007

1001-
2. If you add an attribute without calling ``render()``, it will be rendered twice. For instance:
1008+
2. If you add an attribute without calling these methods, it will be rendered twice. For instance:
10021009

10031010
.. code-block:: html+twig
10041011

src/TwigComponent/src/ComponentAttributes.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ public function __clone(): void
6565
$this->rendered = [];
6666
}
6767

68-
public function render(string $attribute): ?string
68+
public function render(string $attribute, ?string $default = null): ?string
6969
{
7070
if (null === $value = $this->attributes[$attribute] ?? null) {
71-
return null;
71+
return $default;
7272
}
7373

7474
if (!\is_string($value)) {
@@ -80,6 +80,16 @@ public function render(string $attribute): ?string
8080
return $value;
8181
}
8282

83+
public function prepend(string $attribute, string $value, string $separator = ' '): string
84+
{
85+
return trim(sprintf('%s%s%s', $value, $separator, $this->render($attribute)));
86+
}
87+
88+
public function append(string $attribute, string $value, string $separator = ' '): string
89+
{
90+
return trim(sprintf('%s%s%s', $this->render($attribute), $separator, $value));
91+
}
92+
8393
/**
8494
* @return array<string, string|bool>
8595
*/
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
<div
2-
foo="{{ attributes.render('foo') }}"
3-
bar="{{ attributes.render('bar')|default('default') }}"
4-
baz="default {{ attributes.render('baz') }}"
5-
qux="{{ attributes.render('qux') }} default"
2+
attr1="{{ attributes.render('attr1') }}"
3+
attr2="{{ attributes.render('attr2')|default('default') }}"
4+
attr3="default {{ attributes.render('attr3') }}"
5+
attr4="{{ attributes.render('attr4') }} default"
6+
attr5="{{ attributes.render('attr5', 'default') }}"
7+
attr6="{{ attributes.prepend('attr6', 'default') }}"
8+
attr7="{{ attributes.append('attr7', 'default') }}"
69
{{ attributes }}
710
/>

src/TwigComponent/tests/Integration/ComponentExtensionTest.php

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -228,10 +228,13 @@ public static function renderingAttributesManuallyProvider(): iterable
228228
['class' => 'block'],
229229
<<<HTML
230230
<div
231-
foo=""
232-
bar="default"
233-
baz="default "
234-
qux=" default"
231+
attr1=""
232+
attr2="default"
233+
attr3="default "
234+
attr4=" default"
235+
attr5="default"
236+
attr6="default"
237+
attr7="default"
235238
class="block"
236239
/>
237240
HTML,
@@ -240,17 +243,23 @@ class="block"
240243
yield [
241244
[
242245
'class' => 'block',
243-
'foo' => 'value',
244-
'bar' => 'value',
245-
'baz' => 'value',
246-
'qux' => 'value',
246+
'attr1' => 'value1',
247+
'attr2' => 'value2',
248+
'attr3' => 'value3',
249+
'attr4' => 'value4',
250+
'attr5' => 'value5',
251+
'attr6' => 'value6',
252+
'attr7' => 'value7',
247253
],
248254
<<<HTML
249255
<div
250-
foo="value"
251-
bar="value"
252-
baz="default value"
253-
qux="value default"
256+
attr1="value1"
257+
attr2="value2"
258+
attr3="default value3"
259+
attr4="value4 default"
260+
attr5="value5"
261+
attr6="default value6"
262+
attr7="value7 default"
254263
class="block"
255264
/>
256265
HTML,

src/TwigComponent/tests/Unit/ComponentAttributesTest.php

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -200,20 +200,21 @@ public function testIsTraversableAndCountable(): void
200200
$this->assertCount(1, $attributes);
201201
}
202202

203-
public function testRenderSingleAttribute(): void
203+
public function testRenderAttributes(): void
204204
{
205-
$attributes = new ComponentAttributes(['attr1' => 'value1', 'attr2' => 'value2']);
206-
207-
$this->assertSame('value1', $attributes->render('attr1'));
208-
$this->assertNull($attributes->render('attr3'));
209-
}
210-
211-
public function testRenderingSingleAttributeExcludesFromString(): void
212-
{
213-
$attributes = new ComponentAttributes(['attr1' => 'value1', 'attr2' => 'value2']);
205+
$attributes = new ComponentAttributes([
206+
'attr1' => 'value1',
207+
'attr2' => 'value2',
208+
'attr3' => 'value3',
209+
'attr4' => 'value4',
210+
]);
214211

215212
$this->assertSame('value1', $attributes->render('attr1'));
216-
$this->assertSame(' attr2="value2"', (string) $attributes);
213+
$this->assertSame('default value2', $attributes->prepend('attr2', 'default'));
214+
$this->assertSame('value3 default', $attributes->append('attr3', 'default'));
215+
$this->assertNull($attributes->render('attr5'));
216+
$this->assertSame('default', $attributes->render('attr5', 'default'));
217+
$this->assertSame(' attr4="value4"', (string) $attributes);
217218
}
218219

219220
public function testCannotRenderNonStringAttribute(): void

0 commit comments

Comments
 (0)