Test Failed
Pull Request — master (#35)
by Wilmer
02:28
created

Breadcrumbs::withActiveItemTemplate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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