Passed
Push — master ( 566566...d0f53d )
by Alexander
02:18
created

Breadcrumbs::withoutEncodeLabels()   A

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 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
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
    private string $tag = 'ol';
30
    private bool $encodeLabels = true;
31
    private bool $encodeTags = false;
32
    private array $homeLink = [];
33
    private array $links = [];
34
    private string $itemTemplate = "<li class=\"breadcrumb-item\">{link}</li>\n";
35
    private string $activeItemTemplate = "<li class=\"breadcrumb-item active\" aria-current=\"page\">{link}</li>\n";
36
    private array $navOptions = ['aria-label' => 'breadcrumb'];
37
    private array $options = [];
38
39 10
    protected function run(): string
40
    {
41 10
        if (empty($this->links)) {
42 1
            return '';
43
        }
44
45 9
        if (!isset($this->options['id'])) {
46 9
            $this->options['id'] = "{$this->getId()}-breadcrumb";
47
        }
48
49
        /** @psalm-suppress InvalidArgument */
50 9
        Html::addCssClass($this->options, ['widget' => 'breadcrumb']);
51
52 9
        $links = [];
53
54 9
        if ($this->homeLink === []) {
55 8
            $links[] = $this->renderItem([
56 8
                'label' => 'Home',
57
                'url' => '/',
58 8
            ], $this->itemTemplate);
59
        } else {
60 1
            $links[] = $this->renderItem($this->homeLink, $this->itemTemplate);
61
        }
62
63 9
        foreach ($this->links as $link) {
64 9
            if (!is_array($link)) {
65 1
                $link = ['label' => $link];
66
            }
67
68 9
            $links[] = $this->renderItem($link, isset($link['url']) ? $this->itemTemplate : $this->activeItemTemplate);
69
        }
70
71 8
        if ($this->encodeTags === false) {
72 7
            $this->navOptions['encode'] = false;
73 7
            $this->options['encode'] = false;
74
        }
75
76 8
        return Html::tag('nav', Html::tag($this->tag, implode('', $links), $this->options), $this->navOptions);
77
    }
78
79
    /**
80
     * The template used to render each active item in the breadcrumbs. The token `{link}` will be replaced with the
81
     * actual HTML link for each active item.
82
     *
83
     * @param string $value
84
     *
85
     * @return $this
86
     */
87 1
    public function activeItemTemplate(string $value): self
88
    {
89 1
        $new = clone $this;
90 1
        $new->activeItemTemplate = $value;
91
92 1
        return $new;
93
    }
94
95
    /**
96
     * When tags Labels HTML should not be encoded.
97
     *
98
     * @return $this
99
     */
100 1
    public function withoutEncodeLabels(): self
101
    {
102 1
        $new = clone $this;
103 1
        $new->encodeLabels = false;
104
105 1
        return $new;
106
    }
107
108
    /**
109
     * The first hyperlink in the breadcrumbs (called home link).
110
     *
111
     * Please refer to {@see links} on the format of the link.
112
     *
113
     * If this property is not set, it will default to a link pointing with the label 'Home'. If this property is false,
114
     * the home link will not be rendered.
115
     *
116
     * @param array $value
117
     *
118
     * @return $this
119
     */
120 1
    public function homeLink(array $value): self
121
    {
122 1
        $new = clone $this;
123 1
        $new->homeLink = $value;
124
125 1
        return $new;
126
    }
127
128
    /**
129
     * The template used to render each inactive item in the breadcrumbs. The token `{link}` will be replaced with the
130
     * actual HTML link for each inactive item.
131
     *
132
     * @param string $value
133
     *
134
     * @return $this
135
     */
136 1
    public function itemTemplate(string $value): self
137
    {
138 1
        $new = clone $this;
139 1
        $new->itemTemplate = $value;
140
141 1
        return $new;
142
    }
143
144
    /**
145
     * List of links to appear in the breadcrumbs. If this property is empty, the widget will not render anything. Each
146
     * array element represents a single link in the breadcrumbs with the following structure:
147
     *
148
     * ```php
149
     * [
150
     *     'label' => 'label of the link',  // required
151
     *     'url' => 'url of the link',      // optional, will be processed by Url::to()
152
     *     'template' => 'own template of the item', // optional, if not set $this->itemTemplate will be used
153
     * ]
154
     * ```
155
     *
156
     * @param array $value
157
     *
158
     * @return $this
159
     */
160 10
    public function links(array $value): self
161
    {
162 10
        $new = clone $this;
163 10
        $new->links = $value;
164
165 10
        return $new;
166
    }
167
168
    /**
169
     * The HTML attributes for the widgets nav container tag.
170
     *
171
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
172
     *
173
     * @param array $value
174
     *
175
     * @return $this
176
     */
177 1
    public function navOptions(array $value): self
178
    {
179 1
        $new = clone $this;
180 1
        $new->navOptions = $value;
181
182 1
        return $new;
183
    }
184
185
    /**
186
     * The HTML attributes for the widget container tag. The following special options are recognized.
187
     *
188
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
189
     *
190
     * @param array $value
191
     *
192
     * @return $this
193
     */
194 1
    public function options(array $value): self
195
    {
196 1
        $new = clone $this;
197 1
        $new->options = $value;
198
199 1
        return $new;
200
    }
201
202
    /**
203
     * The name of the breadcrumb container tag.
204
     *
205
     * @param string $value
206
     *
207
     * @return $this
208
     */
209 1
    public function tag(string $value): self
210
    {
211 1
        $new = clone $this;
212 1
        $new->tag = $value;
213
214 1
        return $new;
215
    }
216
217
    /**
218
     * Allows you to enable the encoding tags html.
219
     *
220
     * @return self
221
     */
222 1
    public function encodeTags(): self
223
    {
224 1
        $new = clone $this;
225 1
        $new->encodeTags = true;
226
227 1
        return $new;
228
    }
229
230
    /**
231
     * Renders a single breadcrumb item.
232
     *
233
     * @param array $link the link to be rendered. It must contain the "label" element. The "url" element is optional.
234
     * @param string $template the template to be used to rendered the link. The token "{link}" will be replaced by the
235
     * link.
236
     *
237
     * @throws JsonException|RuntimeException if `$link` does not have "label" element.
238
     *
239
     * @return string the rendering result
240
     */
241 9
    private function renderItem(array $link, string $template): string
242
    {
243 9
        $encodeLabel = ArrayHelper::remove($link, 'encode', $this->encodeLabels);
244
245 9
        if (array_key_exists('label', $link)) {
246 9
            $label = $encodeLabel ? Html::encode($link['label']) : $link['label'];
247
        } else {
248 1
            throw new RuntimeException('The "label" element is required for each link.');
249
        }
250
251 9
        if (isset($link['template'])) {
252 1
            $template = $link['template'];
253
        }
254
255 9
        if ($this->encodeTags === false) {
256 8
            $link['encode'] = false;
257
        }
258
259 9
        if (isset($link['url'])) {
260 9
            $options = $link;
261 9
            unset($options['template'], $options['label'], $options['url']);
262 9
            $linkHtml = Html::a($label, $link['url'], $options);
263
        } else {
264 8
            $linkHtml = $label;
265
        }
266
267 9
        return strtr($template, ['{link}' => $linkHtml]);
268
    }
269
}
270