Skip to content

Commit

Permalink
Remove Breadcrumbs::withoutHomeItem(), rename variables (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
devanych committed Jul 22, 2021
1 parent 82bb4df commit 6d0312c
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 58 deletions.
3 changes: 1 addition & 2 deletions docs/breadcrumbs.md
Expand Up @@ -64,8 +64,7 @@ Method | Description | Default
`id(string $value)` | Widget ID. | `''`
`autoIdPrefix(string $value)` | Prefix to the automatically generated widget ID. | `w`
`withoutEncodeLabels()` | Disable encoding for labels. | `false`
`withoutHomeItem()` | Do not render home item. | `true`
`homeItem(array $value)` | The first item in the breadcrumbs (called home link). | `[]`
`homeItem(?array $value)` | The first item in the breadcrumbs (called home link). | `['label' => 'Home', 'url' => '/']`
`itemTemplate(string $value)` | Template used to render each inactive item in the breadcrumbs. | `<li>{icon}{link}</li>\n`
`activeItemTemplate(string $value)`| Template used to render each active item in the breadcrumbs. | `<li class=\"is-active\"><a aria-current=\"page\">{icon}{label}</li>\n`
`items(array $value)` | List of items to appear in the breadcrumbs. | `[]`
Expand Down
90 changes: 38 additions & 52 deletions src/Breadcrumbs.php
Expand Up @@ -30,8 +30,7 @@
final class Breadcrumbs extends Widget
{
private bool $encodeLabels = true;
private array $homeItem = [];
private bool $withoutHomeItem = false;
private ?array $homeItem = ['label' => 'Home', 'url' => '/'];
private string $itemTemplate = "<li>{icon}{link}</li>\n";
private string $activeItemTemplate = "<li class=\"is-active\"><a aria-current=\"page\">{icon}{label}</a></li>\n";
private array $items = [];
Expand Down Expand Up @@ -67,28 +66,24 @@ public function withoutEncodeLabels(): self
}

/**
* Do not render home item.
* Returns a new instance with the specified first item in the breadcrumbs (called home link).
*
* @return self
*/
public function withoutHomeItem(): self
{
$new = clone $this;
$new->withoutHomeItem = true;
return $new;
}

/**
* The first item in the breadcrumbs (called home link).
* If a null is specified, the home item will not be rendered.
*
* Please refer to {@see $items} on the format.
* @param array|null $value Please refer to {@see items()} on the format.
*
* @param array $value
* @throws InvalidArgumentException If an empty array is specified.
*
* @return self
*/
public function homeItem(array $value): self
public function homeItem(?array $value): self
{
if ($value === []) {
throw new InvalidArgumentException(
'The home item cannot be an empty array. To disable rendering of the home item, specify null.',
);
}

$new = clone $this;
$new->homeItem = $value;
return $new;
Expand Down Expand Up @@ -210,80 +205,71 @@ private function renderIcon(string $icon, array $iconOptions): string
/**
* Renders a single breadcrumb item.
*
* @param array $link The link to be rendered. It must contain the "label" element. The "url" element is optional.
* @param array $item The item to be rendered. It must contain the "label" element. The "url" element is optional.
* @param string $template The template to be used to rendered the link. The token "{link}" will be replaced by the
* link.
*
* @throws InvalidArgumentException|JsonException If `$link` does not have "label" element.
* @throws InvalidArgumentException|JsonException If `$item` does not have "label" element.
*
* @return string The rendering result
* @return string The rendering result.
*/
private function renderItem(array $link, string $template): string
private function renderItem(array $item, string $template): string
{
$encodeLabel = ArrayHelper::remove($link, 'encode', $this->encodeLabels);
$encodeLabel = ArrayHelper::remove($item, 'encode', $this->encodeLabels);

$icon = '';
$iconOptions = [];

if (isset($link['icon'])) {
$icon = $link['icon'];
if (isset($item['icon'])) {
$icon = $item['icon'];
}

if (isset($link['iconOptions']) && is_array($link['iconOptions'])) {
if (isset($item['iconOptions']) && is_array($item['iconOptions'])) {
$iconOptions = $this->addOptions($iconOptions, 'icon');
}

unset($link['icon'], $link['iconOptions']);
unset($item['icon'], $item['iconOptions']);

if (array_key_exists('label', $link)) {
$label = $encodeLabel ? Html::encode($link['label']) : $link['label'];
if (array_key_exists('label', $item)) {
$label = $encodeLabel ? Html::encode($item['label']) : $item['label'];
} else {
throw new InvalidArgumentException('The "label" element is required for each link.');
}

if (isset($link['template'])) {
$template = $link['template'];
if (isset($item['template'])) {
$template = $item['template'];
}

if (isset($link['url'])) {
$options = $link;
if (isset($item['url'])) {
$options = $item;
unset($options['template'], $options['label'], $options['url'], $options['icon']);
$linkHtml = Html::a($label, $link['url'], $options)->encode(false)->render();
$link = Html::a($label, $item['url'], $options)->encode(false)->render();
} else {
$linkHtml = $label;
$link = $label;
}

return strtr(
$template,
['{label}' => $label, '{link}' => $linkHtml, '{icon}' => $this->renderIcon($icon, $iconOptions)]
['{label}' => $label, '{link}' => $link, '{icon}' => $this->renderIcon($icon, $iconOptions)],
);
}

private function renderItems(): array
{
$links = [];
$items = [];

if ($this->withoutHomeItem === false) {
$links[] = $this->renderHomeLink();
if ($this->homeItem !== null) {
$items[] = $this->renderItem($this->homeItem, $this->itemTemplate);
}

foreach ($this->items as $link) {
if (!is_array($link)) {
$link = ['label' => $link];
foreach ($this->items as $item) {
if (!is_array($item)) {
$item = ['label' => $item];
}

$links[] = $this->renderItem($link, isset($link['url']) ? $this->itemTemplate : $this->activeItemTemplate);
}

return $links;
}

private function renderHomeLink(): string
{
if ($this->homeItem === []) {
$this->homeItem = ['label' => 'Home', 'url' => '/'];
$items[] = $this->renderItem($item, isset($item['url']) ? $this->itemTemplate : $this->activeItemTemplate);
}

return $this->renderItem($this->homeItem, $this->itemTemplate);
return $items;
}
}
16 changes: 12 additions & 4 deletions tests/BreadcrumbsTest.php
Expand Up @@ -186,7 +186,7 @@ public function testBreadcrumbsLinksException(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The "label" element is required for each link.');
$html = Breadcrumbs::widget()
Breadcrumbs::widget()
->items([['url' => '/about', 'template' => '<div>{link}</div>']])
->render();
}
Expand Down Expand Up @@ -273,7 +273,7 @@ public function testBreadcrumbsWithoutHomeItem(): void

$html = Breadcrumbs::widget()
->items([['label' => 'About', 'url' => '/about']])
->withoutHomeItem()
->homeItem(null)
->render();
$expected = <<<'HTML'
<nav id="w1-breadcrumbs" class="breadcrumb" aria-label="breadcrumbs">
Expand All @@ -285,12 +285,20 @@ public function testBreadcrumbsWithoutHomeItem(): void
$this->assertEqualsWithoutLE($expected, $html);
}

public function testHomeItemThrowExceptionForEmptyArray(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage(
'The home item cannot be an empty array. To disable rendering of the home item, specify null.',
);
Breadcrumbs::widget()->homeItem([]);
}

public function testImmutability(): void
{
$widget = Breadcrumbs::widget();

$this->assertNotSame($widget, $widget->homeItem([]));
$this->assertNotSame($widget, $widget->withoutHomeItem());
$this->assertNotSame($widget, $widget->homeItem(null));
$this->assertNotSame($widget, $widget->itemTemplate(''));
$this->assertNotSame($widget, $widget->activeItemTemplate(''));
$this->assertNotSame($widget, $widget->items([]));
Expand Down

0 comments on commit 6d0312c

Please sign in to comment.