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

Breadcrumbs::withHomeLink()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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