diff --git a/src/AccordionItem.php b/src/AccordionItem.php index 343d9ca7..01ceb18d 100644 --- a/src/AccordionItem.php +++ b/src/AccordionItem.php @@ -31,12 +31,12 @@ final class AccordionItem * Use {@see AccordionItem::to()} to create a new instance. */ private function __construct( - private readonly bool $active = false, - private readonly string $body = '', - private readonly bool $encodeBody = true, - private readonly bool $encodeHeader = true, - private readonly string $header = '', - private readonly bool|string $id = true, + private bool $active = false, + private string $body = '', + private bool $encodeBody = true, + private bool $encodeHeader = true, + private string $header = '', + private bool|string $id = true, ) { } @@ -64,6 +64,103 @@ public static function to( return new self($active, $body, $encodeBody, $encodeHeader, $header, $id); } + /** + * Sets the active state of the accordion item. + * + * @param bool $value Whether the accordion item is active. + * + * @return self A new instance with the specified active state. + */ + public function active(bool $value): self + { + $new = clone $this; + $new->active = $value; + + return $new; + } + + /** + * Sets the body content of the accordion item. + * + * @param string $value The body content. + * + * @return self A new instance with the specified body content. + */ + public function body(string $value): self + { + $new = clone $this; + $new->body = $value; + + return $new; + } + + /** + * Sets whether to encode the body content. + * + * @param bool $value Whether to encode the body content. + * + * @return self A new instance with the specified encoding setting. + */ + public function encodeBody(bool $value): self + { + $new = clone $this; + $new->encodeBody = $value; + + return $new; + } + + /** + * Sets whether to encode the header content. + * + * @param bool $value Whether to encode the header content. + * + * @return self A new instance with the specified encoding setting. + */ + public function encodeHeader(bool $value): self + { + $new = clone $this; + $new->encodeHeader = $value; + + return $new; + } + + /** + * Sets the header content of the accordion item. + * + * @param string $value The header content. + * + * @return self A new instance with the specified header content. + */ + public function header(string $value): self + { + $new = clone $this; + $new->header = $value; + + return $new; + } + + /** + * Sets the ID of the accordion item. + * + * @param bool|string $value The ID of the accordion item. If `true`, an auto-generated ID will be used. If `false`, + * no ID will be set. + * + * @throws InvalidArgumentException If the "id" property is empty or `false`. + * + * @return self A new instance with the specified ID. + */ + public function id(bool|string $value): self + { + if ($value === '' || $value === false) { + throw new InvalidArgumentException('The "id" property must be a non-empty string or `true`.'); + } + + $new = clone $this; + $new->id = $value; + + return $new; + } + /** * @return string The encoded header content. If {@see encodeHeader} is `false`, the header content will not be * encoded. diff --git a/tests/AccordionItemTest.php b/tests/AccordionItemTest.php index 5e7fdfb0..b26dd3d4 100644 --- a/tests/AccordionItemTest.php +++ b/tests/AccordionItemTest.php @@ -50,28 +50,54 @@ public function testId(): void $this->assertStringMatchesFormat('collapse-%x', $item->getId()); } - public function testIdWithEmpty(): void + public function testIdWithValue(): void + { + $item = AccordionItem::to('header', 'body', 'custom-id'); + + $this->assertSame('custom-id', $item->getId()); + } + + public function testImmutability(): void + { + $item = AccordionItem::to(); + + $this->assertNotSame($item, $item->active(false)); + $this->assertNotSame($item, $item->body('')); + $this->assertNotSame($item, $item->encodeBody(false)); + $this->assertNotSame($item, $item->encodeHeader(false)); + $this->assertNotSame($item, $item->id('custom-id')); + $this->assertNotSame($item, $item->header('')); + } + + public function testThrowExceptionForIdWithEmptyConstructor(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('The "id" property must be a non-empty string or `true`.'); - $accordionItem = AccordionItem::to('header', 'body', ''); - $accordionItem->getId(); + AccordionItem::to('header', 'body', '')->getId(); } - public function testIdWithFalse(): void + public function testThrowExceptionForIdWithFalseConstructor(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('The "id" property must be a non-empty string or `true`.'); - $accordionItem = AccordionItem::to('header', 'body', false); - $accordionItem->getId(); + AccordionItem::to('header', 'body', false)->getId(); } - public function testIdWithValue(): void + public function testThrowExceptionForIdWithEmptyMethod(): void { - $item = AccordionItem::to('header', 'body', 'custom-id'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The "id" property must be a non-empty string or `true`.'); - $this->assertSame('custom-id', $item->getId()); + AccordionItem::to('header', 'body')->id(''); + } + + public function testThrowExceptionForIdWithFalseMethod(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The "id" property must be a non-empty string or `true`.'); + + AccordionItem::to('header', 'body')->id(false); } }