diff --git a/src/TwigComponent/CHANGELOG.md b/src/TwigComponent/CHANGELOG.md
index f3cc7362483..76fdcda6f96 100644
--- a/src/TwigComponent/CHANGELOG.md
+++ b/src/TwigComponent/CHANGELOG.md
@@ -1,5 +1,10 @@
# CHANGELOG
+## 2.16.0
+
+- Add default value to `ComponentAttributes::render()` #1531
+- Add `ComponentAttributes::append()/prepend()` #1531
+
## 2.15.0
- Add the ability to render specific attributes from the `attributes` variable #1442
diff --git a/src/TwigComponent/doc/index.rst b/src/TwigComponent/doc/index.rst
index 72e93491acb..6fde2f2a3d6 100644
--- a/src/TwigComponent/doc/index.rst
+++ b/src/TwigComponent/doc/index.rst
@@ -952,14 +952,21 @@ Render
The ability to *render* attributes was added in TwigComponents 2.15.
+.. versionadded:: 2.16
+
+ The ability to *render* attributes with a default, *prepend*, and *append* were
+ added in TwigComponents 2.16.
+
You can take full control over the attributes that are rendered by using the
-``render()`` method.
+``render()``, ``prepend()``, and ``append()`` methods.
.. code-block:: html+twig
{# templates/components/MyComponent.html.twig #}
My Component!
@@ -969,15 +976,15 @@ You can take full control over the attributes that are rendered by using the
{{ component('MyComponent', { style: 'color:red;' }) }}
{# renders as: #}
-
+
My Component!
.. caution::
- There are a few important things to know about using ``render()``:
+ There are a few important things to know about using ``render()``/``prepend()``/``append()``:
- 1. You need to be sure to call your ``render()`` methods before calling ``{{ attributes }}`` or some
+ 1. You need to be sure to call these methods before calling ``{{ attributes }}`` or some
attributes could be rendered twice. For instance:
.. code-block:: html+twig
@@ -998,7 +1005,7 @@ You can take full control over the attributes that are rendered by using the
My Component!
- 2. If you add an attribute without calling ``render()``, it will be rendered twice. For instance:
+ 2. If you add an attribute without calling these methods, it will be rendered twice. For instance:
.. code-block:: html+twig
diff --git a/src/TwigComponent/src/ComponentAttributes.php b/src/TwigComponent/src/ComponentAttributes.php
index 8b7d10a0601..f3144505d2b 100644
--- a/src/TwigComponent/src/ComponentAttributes.php
+++ b/src/TwigComponent/src/ComponentAttributes.php
@@ -65,10 +65,10 @@ public function __clone(): void
$this->rendered = [];
}
- public function render(string $attribute): ?string
+ public function render(string $attribute, ?string $default = null): ?string
{
if (null === $value = $this->attributes[$attribute] ?? null) {
- return null;
+ return $default;
}
if (!\is_string($value)) {
@@ -80,6 +80,16 @@ public function render(string $attribute): ?string
return $value;
}
+ public function prepend(string $attribute, string $value, string $separator = ' '): string
+ {
+ return trim(sprintf('%s%s%s', $value, $separator, $this->render($attribute)));
+ }
+
+ public function append(string $attribute, string $value, string $separator = ' '): string
+ {
+ return trim(sprintf('%s%s%s', $this->render($attribute), $separator, $value));
+ }
+
/**
* @return array
*/
diff --git a/src/TwigComponent/tests/Fixtures/templates/components/RenderAttributes.html.twig b/src/TwigComponent/tests/Fixtures/templates/components/RenderAttributes.html.twig
index 59f132689cb..a77b7f5d42c 100644
--- a/src/TwigComponent/tests/Fixtures/templates/components/RenderAttributes.html.twig
+++ b/src/TwigComponent/tests/Fixtures/templates/components/RenderAttributes.html.twig
@@ -1,7 +1,10 @@
diff --git a/src/TwigComponent/tests/Integration/ComponentExtensionTest.php b/src/TwigComponent/tests/Integration/ComponentExtensionTest.php
index ff891610c50..4eb772f91be 100644
--- a/src/TwigComponent/tests/Integration/ComponentExtensionTest.php
+++ b/src/TwigComponent/tests/Integration/ComponentExtensionTest.php
@@ -14,7 +14,6 @@
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\UX\TwigComponent\Tests\Fixtures\User;
use Twig\Environment;
-use Twig\Error\RuntimeError;
/**
* @author Kevin Bond
@@ -228,10 +227,13 @@ public static function renderingAttributesManuallyProvider(): iterable
['class' => 'block'],
<<
HTML,
@@ -240,17 +242,23 @@ class="block"
yield [
[
'class' => 'block',
- 'foo' => 'value',
- 'bar' => 'value',
- 'baz' => 'value',
- 'qux' => 'value',
+ 'attr1' => 'value1',
+ 'attr2' => 'value2',
+ 'attr3' => 'value3',
+ 'attr4' => 'value4',
+ 'attr5' => 'value5',
+ 'attr6' => 'value6',
+ 'attr7' => 'value7',
],
<<
HTML,
diff --git a/src/TwigComponent/tests/Unit/ComponentAttributesTest.php b/src/TwigComponent/tests/Unit/ComponentAttributesTest.php
index 7cad387a28c..e1cf676b0a4 100644
--- a/src/TwigComponent/tests/Unit/ComponentAttributesTest.php
+++ b/src/TwigComponent/tests/Unit/ComponentAttributesTest.php
@@ -200,20 +200,21 @@ public function testIsTraversableAndCountable(): void
$this->assertCount(1, $attributes);
}
- public function testRenderSingleAttribute(): void
+ public function testRenderAttributes(): void
{
- $attributes = new ComponentAttributes(['attr1' => 'value1', 'attr2' => 'value2']);
-
- $this->assertSame('value1', $attributes->render('attr1'));
- $this->assertNull($attributes->render('attr3'));
- }
-
- public function testRenderingSingleAttributeExcludesFromString(): void
- {
- $attributes = new ComponentAttributes(['attr1' => 'value1', 'attr2' => 'value2']);
+ $attributes = new ComponentAttributes([
+ 'attr1' => 'value1',
+ 'attr2' => 'value2',
+ 'attr3' => 'value3',
+ 'attr4' => 'value4',
+ ]);
$this->assertSame('value1', $attributes->render('attr1'));
- $this->assertSame(' attr2="value2"', (string) $attributes);
+ $this->assertSame('default value2', $attributes->prepend('attr2', 'default'));
+ $this->assertSame('value3 default', $attributes->append('attr3', 'default'));
+ $this->assertNull($attributes->render('attr5'));
+ $this->assertSame('default', $attributes->render('attr5', 'default'));
+ $this->assertSame(' attr4="value4"', (string) $attributes);
}
public function testCannotRenderNonStringAttribute(): void