Skip to content

Commit

Permalink
Refactor AccordionItem to improve constructor property handling and…
Browse files Browse the repository at this point in the history
… add immutable methods.
  • Loading branch information
terabytesoftw committed Jan 21, 2025
1 parent 3dc4609 commit 91229cf
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 15 deletions.
109 changes: 103 additions & 6 deletions src/AccordionItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
) {
}

Expand Down Expand Up @@ -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.
Expand Down
44 changes: 35 additions & 9 deletions tests/AccordionItemTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

0 comments on commit 91229cf

Please sign in to comment.