diff --git a/CHANGELOG.md b/CHANGELOG.md
index 796b512c..7f7339c8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
## 4.1.1 under development
+- New #277: Add `beforeCheckbox()` and `afterCheckbox()` methods to `CheckboxList`, and `beforeRadio()` and
+ `afterRadio()` methods to `RadioList` (@vjik)
- New #276: Add `beforeInput()` and `afterInput()` methods to abstract `BooleanInputTag`, extended by `Radio`
and `Checkbox` (@vjik)
diff --git a/src/Widget/CheckboxList/CheckboxList.php b/src/Widget/CheckboxList/CheckboxList.php
index 87a198f8..262dc6dc 100644
--- a/src/Widget/CheckboxList/CheckboxList.php
+++ b/src/Widget/CheckboxList/CheckboxList.php
@@ -28,6 +28,8 @@ final class CheckboxList implements NoEncodeStringableInterface
private array $checkboxAttributes = [];
private array $checkboxLabelAttributes = [];
private bool $checkboxLabelWrap = true;
+ private string|Stringable $beforeCheckbox = '';
+ private string|Stringable $afterCheckbox = '';
/**
* @var array[]
@@ -164,6 +166,26 @@ public function checkboxLabelWrap(bool $wrap): self
return $new;
}
+ /**
+ * @param string|Stringable $content Content to be rendered before each checkbox input.
+ */
+ public function beforeCheckbox(string|Stringable $content): self
+ {
+ $new = clone $this;
+ $new->beforeCheckbox = $content;
+ return $new;
+ }
+
+ /**
+ * @param string|Stringable $content Content to be rendered after each checkbox input.
+ */
+ public function afterCheckbox(string|Stringable $content): self
+ {
+ $new = clone $this;
+ $new->afterCheckbox = $content;
+ return $new;
+ }
+
/**
* @param array[] $attributes
*/
@@ -365,7 +387,9 @@ private function formatItem(CheckboxItem $item): string
$checkbox = Html::checkbox($item->name, $item->value, $item->checkboxAttributes)
->checked($item->checked)
->label($item->label, $item->labelAttributes, $item->labelWrap)
- ->labelEncode($item->encodeLabel);
+ ->labelEncode($item->encodeLabel)
+ ->beforeInput($this->beforeCheckbox)
+ ->afterInput($this->afterCheckbox);
return $checkbox->render();
}
diff --git a/src/Widget/RadioList/RadioList.php b/src/Widget/RadioList/RadioList.php
index 6d5c6103..e091ab74 100644
--- a/src/Widget/RadioList/RadioList.php
+++ b/src/Widget/RadioList/RadioList.php
@@ -25,6 +25,8 @@ final class RadioList implements NoEncodeStringableInterface
private array $radioAttributes = [];
private array $radioLabelAttributes = [];
private bool $radioLabelWrap = true;
+ private string|Stringable $beforeRadio = '';
+ private string|Stringable $afterRadio = '';
/**
* @var array[]
@@ -155,6 +157,26 @@ public function radioLabelWrap(bool $wrap): self
return $new;
}
+ /**
+ * @param string|Stringable $content Content to be rendered before each radio input.
+ */
+ public function beforeRadio(string|Stringable $content): self
+ {
+ $new = clone $this;
+ $new->beforeRadio = $content;
+ return $new;
+ }
+
+ /**
+ * @param string|Stringable $content Content to be rendered after each radio input.
+ */
+ public function afterRadio(string|Stringable $content): self
+ {
+ $new = clone $this;
+ $new->afterRadio = $content;
+ return $new;
+ }
+
/**
* @param array[] $attributes
*/
@@ -344,7 +366,9 @@ private function formatItem(RadioItem $item): string
$radio = Html::radio($item->name, $item->value, $item->radioAttributes)
->checked($item->checked)
->label($item->label, $item->labelAttributes, $item->labelWrap)
- ->labelEncode($item->encodeLabel);
+ ->labelEncode($item->encodeLabel)
+ ->beforeInput($this->beforeRadio)
+ ->afterInput($this->afterRadio);
return $radio->render();
}
diff --git a/tests/Widget/CheckboxListTest.php b/tests/Widget/CheckboxListTest.php
index 63130f47..be0730d1 100644
--- a/tests/Widget/CheckboxListTest.php
+++ b/tests/Widget/CheckboxListTest.php
@@ -7,8 +7,10 @@
use ArrayObject;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
+use Stringable;
use Yiisoft\Html\Html;
use Yiisoft\Html\Tests\Objects\IterableObject;
+use Yiisoft\Html\Tests\Objects\StringableObject;
use Yiisoft\Html\Tests\Support\IntegerEnum;
use Yiisoft\Html\Tests\Support\StringEnum;
use Yiisoft\Html\Widget\CheckboxList\CheckboxList;
@@ -194,6 +196,46 @@ public function testCheckboxLabelAttributesMerge(): void
);
}
+ public static function dataBeforeCheckbox(): iterable
+ {
+ yield ['*', '*'];
+ yield ['*', new StringableObject('*')];
+ }
+
+ #[DataProvider('dataBeforeCheckbox')]
+ public function testBeforeCheckbox(string $expected, string|Stringable $content): void
+ {
+ $this->assertSame(
+ '' . "\n"
+ . '',
+ (new CheckboxList('test'))
+ ->items([1 => 'One', 2 => 'Two'])
+ ->beforeCheckbox($content)
+ ->withoutContainer()
+ ->render(),
+ );
+ }
+
+ public static function dataAfterCheckbox(): iterable
+ {
+ yield ['!', '!'];
+ yield ['!', new StringableObject('!')];
+ }
+
+ #[DataProvider('dataAfterCheckbox')]
+ public function testAfterCheckbox(string $expected, string|Stringable $content): void
+ {
+ $this->assertSame(
+ '' . "\n"
+ . '',
+ (new CheckboxList('test'))
+ ->items([1 => 'One', 2 => 'Two'])
+ ->afterCheckbox($content)
+ ->withoutContainer()
+ ->render(),
+ );
+ }
+
public function testAddIndividualInputAttributes(): void
{
$this->assertSame(
@@ -903,5 +945,7 @@ public function testImmutability(): void
$this->assertNotSame($widget, $widget->uncheckValue(null));
$this->assertNotSame($widget, $widget->separator(''));
$this->assertNotSame($widget, $widget->itemFormatter(null));
+ $this->assertNotSame($widget, $widget->beforeCheckbox(''));
+ $this->assertNotSame($widget, $widget->afterCheckbox(''));
}
}
diff --git a/tests/Widget/RadioListTest.php b/tests/Widget/RadioListTest.php
index 2ddfa938..dee4b313 100644
--- a/tests/Widget/RadioListTest.php
+++ b/tests/Widget/RadioListTest.php
@@ -6,7 +6,9 @@
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
+use Stringable;
use Yiisoft\Html\Html;
+use Yiisoft\Html\Tests\Objects\StringableObject;
use Yiisoft\Html\Tests\Support\IntegerEnum;
use Yiisoft\Html\Tests\Support\StringEnum;
use Yiisoft\Html\Widget\RadioList\RadioItem;
@@ -832,6 +834,46 @@ public function testStringable(): void
);
}
+ public static function dataBeforeRadio(): iterable
+ {
+ yield ['*', '*'];
+ yield ['*', new StringableObject('*')];
+ }
+
+ #[DataProvider('dataBeforeRadio')]
+ public function testBeforeRadio(string $expected, string|Stringable $content): void
+ {
+ $this->assertSame(
+ '' . "\n"
+ . '',
+ (new RadioList('test'))
+ ->items([1 => 'One', 2 => 'Two'])
+ ->beforeRadio($content)
+ ->withoutContainer()
+ ->render(),
+ );
+ }
+
+ public static function dataAfterRadio(): iterable
+ {
+ yield ['!', '!'];
+ yield ['!', new StringableObject('!')];
+ }
+
+ #[DataProvider('dataAfterRadio')]
+ public function testAfterRadio(string $expected, string|Stringable $content): void
+ {
+ $this->assertSame(
+ '' . "\n"
+ . '',
+ (new RadioList('test'))
+ ->items([1 => 'One', 2 => 'Two'])
+ ->afterRadio($content)
+ ->withoutContainer()
+ ->render(),
+ );
+ }
+
public function testImmutability(): void
{
$widget = new RadioList('test');
@@ -859,5 +901,7 @@ public function testImmutability(): void
$this->assertNotSame($widget, $widget->uncheckValue(null));
$this->assertNotSame($widget, $widget->separator(''));
$this->assertNotSame($widget, $widget->itemFormatter(null));
+ $this->assertNotSame($widget, $widget->beforeRadio(''));
+ $this->assertNotSame($widget, $widget->afterRadio(''));
}
}