Breadcrumbs::itemTemplate()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Bootstrap5;
6
7
use JsonException;
8
use RuntimeException;
9
use Yiisoft\Arrays\ArrayHelper;
10
use Yiisoft\Html\Html;
11
12
use function array_key_exists;
13
use function implode;
14
use function is_array;
15
use function strtr;
16
17
/**
18
 * Button renders a bootstrap button.
19
 *
20
 * For example,
21
 *
22
 * ```php
23
 * echo Breadcrumbs::widget()
24
 *     ->links(['label' => !empty($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : []]);
25
 * ```
26
 */
27
final class Breadcrumbs extends Widget
28
{
29
    /** @psalm-var non-empty-string */
30
    private string $tag = 'ol';
31
    private bool $encodeLabels = true;
32
    private bool $encodeTags = false;
33
    private array $homeLink = ['label' => 'Home', 'url' => '/'];
34
    private array $links = [];
35
    private string $itemTemplate = "<li class=\"breadcrumb-item\">{link}</li>\n";
36
    private string $activeItemTemplate = "<li class=\"breadcrumb-item active\" aria-current=\"page\">{link}</li>\n";
37
    private array $navOptions = ['aria-label' => 'breadcrumb'];
38
    private array $options = [];
39
40 10
    public function render(): string
41
    {
42 10
        if (empty($this->links)) {
43 1
            return '';
44
        }
45
46 9
        if (!isset($this->options['id'])) {
47 9
            $this->options['id'] = "{$this->getId()}-breadcrumb";
48
        }
49
50
        /** @psalm-suppress InvalidArgument */
51 9
        Html::addCssClass($this->options, ['widget' => 'breadcrumb']);
52
53 9
        $links = [];
54
55 9
        if ($this->homeLink !== []) {
56 8
            $links[] = $this->renderItem($this->homeLink, $this->itemTemplate);
57
        }
58
59 9
        foreach ($this->links as $link) {
60 9
            if (!is_array($link)) {
61 2
                $link = ['label' => $link];
62
            }
63
64 9
            $links[] = $this->renderItem($link, isset($link['url']) ? $this->itemTemplate : $this->activeItemTemplate);
65
        }
66
67 8
        return Html::tag(
68 8
            'nav',
69 8
            Html::tag($this->tag, implode('', $links), $this->options)
70 8
                ->encode($this->encodeTags)
71 8
                ->render(),
72 8
            $this->navOptions
73 8
        )
74 8
            ->encode($this->encodeTags)
75 8
            ->render();
76
    }
77
78
    /**
79
     * The template used to render each active item in the breadcrumbs. The token `{link}` will be replaced with the
80
     * actual HTML link for each active item.
81
     */
82 1
    public function activeItemTemplate(string $value): self
83
    {
84 1
        $new = clone $this;
85 1
        $new->activeItemTemplate = $value;
86
87 1
        return $new;
88
    }
89
90
    /**
91
     * When tags Labels HTML should not be encoded.
92
     */
93 1
    public function withoutEncodeLabels(): self
94
    {
95 1
        $new = clone $this;
96 1
        $new->encodeLabels = false;
97
98 1
        return $new;
99
    }
100
101
    /**
102
     * The first hyperlink in the breadcrumbs (called home link).
103
     *
104
     * Please refer to {@see links} on the format of the link.
105
     *
106
     * If this property is not set, it will default to a link pointing with the label 'Home'. If this property is false,
107
     * the home link will not be rendered.
108
     */
109 2
    public function homeLink(array $value): self
110
    {
111 2
        $new = clone $this;
112 2
        $new->homeLink = $value;
113
114 2
        return $new;
115
    }
116
117
    /**
118
     * The template used to render each inactive item in the breadcrumbs. The token `{link}` will be replaced with the
119
     * actual HTML link for each inactive item.
120
     */
121 1
    public function itemTemplate(string $value): self
122
    {
123 1
        $new = clone $this;
124 1
        $new->itemTemplate = $value;
125
126 1
        return $new;
127
    }
128
129
    /**
130
     * List of links to appear in the breadcrumbs. If this property is empty, the widget will not render anything. Each
131
     * array element represents a single link in the breadcrumbs with the following structure:
132
     *
133
     * ```php
134
     * [
135
     *     'label' => 'label of the link',  // required
136
     *     'url' => 'url of the link',      // optional, will be processed by Url::to()
137
     *     'template' => 'own template of the item', // optional, if not set $this->itemTemplate will be used
138
     * ]
139
     * ```
140
     */
141 10
    public function links(array $value): self
142
    {
143 10
        $new = clone $this;
144 10
        $new->links = $value;
145
146 10
        return $new;
147
    }
148
149
    /**
150
     * The HTML attributes for the widgets nav container tag.
151
     *
152
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
153
     */
154 1
    public function navOptions(array $value): self
155
    {
156 1
        $new = clone $this;
157 1
        $new->navOptions = $value;
158
159 1
        return $new;
160
    }
161
162
    /**
163
     * The HTML attributes for the widget container tag. The following special options are recognized.
164
     *
165
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
166
     */
167 1
    public function options(array $value): self
168
    {
169 1
        $new = clone $this;
170 1
        $new->options = $value;
171
172 1
        return $new;
173
    }
174
175
    /**
176
     * The name of the breadcrumb container tag.
177
     *
178
     * @psalm-param non-empty-string $value
179
     */
180 1
    public function tag(string $value): self
181
    {
182 1
        $new = clone $this;
183 1
        $new->tag = $value;
184
185 1
        return $new;
186
    }
187
188
    /**
189
     * Renders a single breadcrumb item.
190
     *
191
     * @param array $link the link to be rendered. It must contain the "label" element. The "url" element is optional.
192
     * @param string $template the template to be used to rendered the link. The token "{link}" will be replaced by the
193
     * link.
194
     *
195
     * @throws JsonException|RuntimeException if `$link` does not have "label" element.
196
     *
197
     * @return string the rendering result
198
     */
199 9
    private function renderItem(array $link, string $template): string
200
    {
201 9
        $encodeLabel = ArrayHelper::remove($link, 'encode', $this->encodeLabels);
202
203 9
        if (array_key_exists('label', $link)) {
204 9
            $label = $encodeLabel ? Html::encode($link['label']) : $link['label'];
205
        } else {
206 1
            throw new RuntimeException('The "label" element is required for each link.');
207
        }
208
209 9
        if (isset($link['template'])) {
210 2
            $template = $link['template'];
211
        }
212
213 9
        if (isset($link['url'])) {
214 9
            $options = $link;
215 9
            unset($options['template'], $options['label'], $options['url']);
216 9
            $linkHtml = Html::a($label, $link['url'], $options)->encode($this->encodeTags);
217
        } else {
218 8
            $linkHtml = $label;
219
        }
220
221 9
        return strtr($template, ['{link}' => $linkHtml]);
222
    }
223
}
224