Completed
Pull Request — master (#52)
by Alexander
03:31
created

Breadcrumbs::getContent()   B

Complexity

Conditions 9
Paths 16

Size

Total Lines 28
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 9

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 28
ccs 16
cts 16
cp 1
rs 8.0555
c 0
b 0
f 0
cc 9
nc 16
nop 0
crap 9
1
<?php
2
3
namespace Yiisoft\Widget;
4
5
use Yiisoft\Html\Html;
6
use Yiisoft\Arrays\ArrayHelper;
7
8
/**
9
 * Breadcrumbs displays a list of links indicating the position of the current page in the whole site hierarchy.
10
 *
11
 * For example, breadcrumbs like "Home / Sample Post / Edit" means the user is viewing an edit page for the
12
 * "Sample Post". He can click on "Sample Post" to view that page, or he can click on "Home" to return to the homepage.
13
 *
14
 * To use Breadcrumbs, you need to configure its {@see links} property, which specifies the links to be displayed. For
15
 * example,
16
 *
17
 * ```php
18
 * // $this is the view object currently being used
19
 * echo Breadcrumbs::widget()
20
 *     -> itemTemplate() => "<li><i>{link}</i></li>\n", // template for all links
21
 *     -> links() => [
22
 *         [
23
 *             'label' => 'Post Category',
24
 *             'url' => 'post-category/view?id=10',
25
 *             'template' => "<li><b>{link}</b></li>\n", // template for this link only
26
 *         ],
27
 *         ['label' => 'Sample Post', 'url' => 'post/edit?id=1',
28
 *         'Edit',
29
 *     ];
30
 * ```
31
 *
32
 * Because breadcrumbs usually appears in nearly every page of a website, you may consider placing it in a layout view.
33
 * You can use a view parameter (e.g. `$this->params['breadcrumbs']`) to configure the links in different views. In the
34
 * layout view, you assign this view parameter to the {@see links} property like the following:
35
 *
36
 * ```php
37
 * // $this is the view object currently being used
38
 * echo Breadcrumbs::widget()
39
 *     ->links() => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [];
40
 * ```
41
 *
42
 * @method static Breadcrumbs widget()
43
 */
44
class Breadcrumbs extends Widget
45
{
46
    /**
47
     * @var string the name of the breadcrumb container tag.
48
     */
49
    private $tag = 'ul';
50
51
    /**
52
     * @var array the HTML attributes for the breadcrumb container tag.
53
     *
54
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
55
     */
56
    private $options = ['class' => 'breadcrumb'];
57
58
    /**
59
     * @var bool whether to HTML-encode the link labels.
60
     */
61
    private $encodeLabels = true;
62
63
    /**
64
     * @var bool the first hyperlink in the breadcrumbs (called home link). If this property is true, it will default
65
     *           to a link pointing to HomeUrl '\' with the label 'Home'. If this property is false, the home link will
66
     *           not be rendered.
67
     */
68
    private $homeLink = true;
69
70
    /**
71
     * @var array $homeUrlLink
72
     */
73
    private $homeUrlLink;
74
75
    /**
76
     * @var array list of links to appear in the breadcrumbs. If this property is empty, the widget will not render
77
     *            anything. Each array element represents a single link in the breadcrumbs with the following structure:
78
     *
79
     * ```php
80
     * [
81
     *     'label' => 'label of the link',  // required
82
     *     'url' => 'url of the link',      // optional, will be processed by Url::to()
83
     *     'template' => 'own template of the item', // optional, if not set $this->itemTemplate will be used
84
     * ]
85
     * ```
86
     *
87
     * If a link is active, you only need to specify its "label", and instead of writing `['label' => $label]`, you may
88
     * simply use `$label`.
89
     *
90
     * Additional array elements for each link will be treated as the HTML attributes for the hyperlink tag.
91
     * For example, the following link specification will generate a hyperlink with CSS class `external`:
92
     *
93
     * ```php
94
     * [
95
     *     'label' => 'demo',
96
     *     'url' => 'http://example.com',
97
     *     'class' => 'external',
98
     * ]
99
     * ```
100
     *
101
     * Each individual link can override global {@see encodeLabels} param like the following:
102
     *
103
     * ```php
104
     * [
105
     *     'label' => '<strong>Hello!</strong>',
106
     *     'encode' => false,
107
     * ]
108
     * ```
109
     */
110
    private $links = [];
111
112
    /**
113
     * @var string the template used to render each inactive item in the breadcrumbs. The token `{link}` will be
114
     *             replaced with the actual HTML link for each inactive item.
115
     */
116
    private $itemTemplate = "<li>{link}</li>\n";
117
118
    /**
119
     * @var string the template used to render each active item in the breadcrumbs. The token `{link}` will be replaced
120
     *             with the actual HTML link for each active item.
121
     */
122
    private $activeItemTemplate = "<li class=\"active\">{link}</li>\n";
123
124
    /**
125
     * Renders the widget.
126
     *
127
     * @return string the result of widget execution to be outputted.
128
     */
129 8
    public function getContent(): string
130
    {
131 8
        if (empty($this->links)) {
132 1
            return '';
133
        }
134
135 7
        $links = [];
136
137 7
        if ($this->homeLink === true) {
138 2
            $links[] = $this->renderItem([
139 2
                'label' => 'Home',
140
                'url'   => '/',
141 2
            ], $this->itemTemplate);
142 5
        } elseif (!empty($this->homeUrlLink)) {
143 1
            $links[] = $this->renderItem($this->homeUrlLink, $this->itemTemplate);
144
        }
145
146 7
        foreach ($this->links as $link) {
147 7
            if (!is_array($link)) {
148 7
                $link = ['label' => $link];
149
            }
150
151 7
            if (!empty($link)) {
152 7
                $links[] = $this->renderItem($link, isset($link['url']) ? $this->itemTemplate : $this->activeItemTemplate);
153
            }
154
        }
155
156 7
        return Html::tag(!empty($this->tag) ? $this->tag : false, implode('', $links), $this->options);
157
    }
158
159
    /**
160
     * Renders a single breadcrumb item.
161
     *
162
     * @param array  $link the link to be rendered. It must contain the "label" element. The "url" element is optional.
163
     * @param string $template the template to be used to rendered the link. The token "{link}" will be replaced by the
164
     *                         link.
165
     *
166
     * @throws \InvalidArgumentException if `$link` does not have "label" element.
167
     *
168
     * @return string the rendering result
169
     */
170 7
    protected function renderItem(array $link, string $template): string
171
    {
172 7
        $encodeLabel = ArrayHelper::remove($link, 'encode', $this->encodeLabels);
173 7
        $label = $encodeLabel ? Html::encode($link['label']) : $link['label'];
174
175 7
        if (isset($link['template'])) {
176
            $template = $link['template'];
177
        }
178
179 7
        if (isset($link['url'])) {
180 2
            $options = $link;
181 2
            unset($options['template'], $options['label'], $options['url']);
182 2
            $link = Html::a($label, $link['url'], $options);
183
        } else {
184 7
            $link = $label;
185
        }
186
187 7
        return strtr($template, ['{link}' => $link]);
188
    }
189
190
    /**
191
     * {@see tag}
192
     *
193
     * @param string $value
194
     *
195
     * @return $this
196
     */
197 3
    public function tag(string $value): self
198
    {
199 3
        $this->tag = $value;
200
201 3
        return $this;
202
    }
203
204
    /**
205
     * {@see options}
206
     *
207
     * @param array $value
208
     *
209
     * @return $this
210
     */
211 4
    public function options(array $value): self
212
    {
213 4
        $this->options = $value;
214
215 4
        return $this;
216
    }
217
218
    /**
219
     * {@see encodeLabel}
220
     *
221
     * @param boolean $value
222
     *
223
     * @return $this
224
     */
225 1
    public function encodeLabels(bool $value): self
226
    {
227 1
        $this->encodeLabels = $value;
228
229 1
        return $this;
230
    }
231
232
    /**
233
     * {@see homeLink}
234
     *
235
     * @param bool $value
236
     *
237
     * @return $this
238
     */
239 7
    public function homeLink(bool $value): self
240
    {
241 7
        $this->homeLink = $value;
242
243 7
        return $this;
244
    }
245
246
    /**
247
     * {@see links}
248
     *
249
     * @param array $value
250
     *
251
     * @return $this
252
     */
253 1
    public function homeUrlLink(array $value): self
254
    {
255 1
        $this->homeUrlLink = $value;
256
257 1
        return $this;
258
    }
259
260
    /**
261
     * {@see links}
262
     *
263
     * @param array $value
264
     *
265
     * @return $this
266
     */
267 8
    public function links(array $value): self
268
    {
269 8
        if (!array_key_exists('label', $value)) {
270 1
            throw new \InvalidArgumentException('The "label" element is required for each link.');
271
        }
272
273 7
        $this->links = $value;
274
275 7
        return $this;
276
    }
277
278
    /**
279
     * {@see itemTemplate}
280
     *
281
     * @param string $value
282
     *
283
     * @return $this
284
     */
285 1
    public function itemTemplate(string $value): self
286
    {
287 1
        $this->itemTemplate = $value;
288
289 1
        return $this;
290
    }
291
292
    /**
293
     * {@see activeItemTemplate}
294
     *
295
     * @param string $value
296
     *
297
     * @return $this
298
     */
299 3
    public function activeItemTemplate(string $value): self
300
    {
301 3
        $this->activeItemTemplate = $value;
302
303 3
        return $this;
304
    }
305
306 8
    public function __toString()
307
    {
308 8
        return $this->run();
309
    }
310
}
311