Completed
Push — master ( a3d1fb...97f6f8 )
by Dmitrijs
07:38
created

Breadcrumbs::renderItem()   A

Complexity

Conditions 6
Paths 17

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 15
dl 0
loc 26
rs 9.2222
c 0
b 0
f 0
cc 6
nc 17
nop 1
1
<?php
2
/**
3
 * @link https://github.com/DMGPage/yii2-materialize
4
 * @copyright Copyright (c) 2018 Dmitrijs Reinmanis
5
 * @license https://github.com/DMGPage/yii2-materialize/blob/master/LICENSE
6
 */
7
8
namespace dmgpage\yii2materialize\widgets;
9
10
use yii\base\InvalidConfigException;
11
use yii\base\Widget as BaseWidget;
12
use yii\helpers\ArrayHelper;
13
use dmgpage\yii2materialize\helpers\Html;
14
use dmgpage\yii2materialize\assets\MaterializeExtraAsset;
15
16
/**
17
 * Breadcrumbs displays a list of links indicating the position of the current page in the whole site hierarchy.
18
 *
19
 * For example, breadcrumbs like "Home / Sample Post / Edit" means the user is viewing an edit page
20
 * for the "Sample Post". He can click on "Sample Post" to view that page, or he can click on "Home"
21
 * to return to the homepage.
22
 *
23
 * To use Breadcrumbs, you need to configure its [[links]] property, which specifies the links to be displayed. For example,
24
 *
25
 * ```php
26
 * echo Breadcrumbs::widget([
27
 *     'links' => [
28
 *         [
29
 *             'label' => 'Post Category',
30
 *             'url' => ['post-category/view', 'id' => 10],
31
 *             'target' => '_blank'
32
 *         ],
33
 *         [
34
 *             'label' => 'Sample Post',
35
 *             'url' => ['post/edit', 'id' => 1]
36
 *         ],
37
 *         'Edit',
38
 *     ],
39
 * ]);
40
 * ```
41
 *
42
 * Because breadcrumbs usually appears in nearly every page of a website, you may consider placing it in a layout view.
43
 * You can use a view parameter (e.g. `$this->params['breadcrumbs']`) to configure the links in different
44
 * views. In the layout view, you assign this view parameter to the [[links]] property like the following:
45
 *
46
 * ```php
47
 * // $this is the view object currently being used
48
 * echo Breadcrumbs::widget([
49
 *     'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
50
 * ]);
51
 * ```
52
 */
53
class Breadcrumbs extends BaseWidget
54
{
55
    /**
56
     * @var array the HTML attributes for the breadcrumb container tag.
57
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
58
     */
59
    public $options = [];
60
61
    /**
62
     * @var array the HTML attributes for the breadcrumb wrapper tag.
63
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
64
     */
65
    public $wrapperOptions = [];
66
67
    /**
68
     * @var array the HTML attributes for the breadcrumb column tag.
69
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
70
     */
71
    public $columnOptions = [];
72
73
    /**
74
     * @var string the type of breadcrumb to be rendered
75
     * @see \dmgpage\yii2materialize\helpers\Type
76
     */
77
    public $type;
78
79
    /**
80
     * @var bool whether to HTML-encode the link labels.
81
     */
82
    public $encodeLabels = true;
83
84
    /**
85
     * @var array the first hyperlink in the breadcrumbs (called home link).
86
     * Please refer to [[links]] on the format of the link.
87
     * If this property is not set, it will default to a link pointing to [[\yii\web\Application::homeUrl]]
88
     * with the label 'Home'. If this property contains `['render' => false]`, the home link will not be rendered.
89
     */
90
    public $homeLink;
91
92
    /**
93
     * @var array list of links to appear in the breadcrumbs. If this property is empty,
94
     * the widget will not render anything. Each array element represents a single link in the breadcrumbs
95
     * with the following structure:
96
     *
97
     * ```php
98
     * [
99
     *     'label' => 'label of the link',  // required
100
     *     'url' => 'url of the link',      // optional, will be processed by Url::to()
101
     *     'icon' => [
102
     *         'name' => 'home',
103
     *         'options' =>  ['class' => 'red']
104
     *     ]
105
     * ]
106
     * ```
107
     *
108
     * If a link is active, you only need to specify its "label", and instead of writing `['label' => $label]`,
109
     * you may simply use `$label`.
110
     */
111
    public $links = [];
112
113
    /**
114
     * Initialize the widget.
115
     */
116
    public function init()
117
    {
118
        if (!isset($this->wrapperOptions['class'])) {
119
            Html::addCssClass($this->wrapperOptions, 'nav-wrapper');
120
        }
121
122
        if (!isset($this->columnOptions['class'])) {
123
            Html::addCssClass($this->columnOptions, 'col s12');
124
        }
125
    }
126
127
    /**
128
     * Renders the widget.
129
     */
130
    public function run()
131
    {
132
        if (!empty($this->links)) {
133
            $links = [];
134
135
            if (empty($this->homeLink)) {
136
                $links[] = $this->renderItem(
137
                    [
138
                        'label' => \Yii::t('yii', 'Home'),
139
                        'url' => \Yii::$app->homeUrl
140
                    ]
141
                );
142
            } elseif (!isset($this->homeLink['render']) || $this->homeLink['render'] === true) {
143
                $links[] = $this->renderItem($this->homeLink);
144
            }
145
146
            foreach ($this->links as $link) {
147
                if (!is_array($link)) {
148
                    $link = ['label' => $link];
149
                }
150
151
                $links[] = $this->renderItem($link);
152
            }
153
154
            $column = Html::tag('div', implode('', $links), $this->columnOptions);
155
            $wraper = Html::tag('div', $column, $this->wrapperOptions);
156
157
            if (!empty($this->type)) {
158
                Html::addCssClass($this->options, $this->type);
159
                $view = $this->getView();
160
                MaterializeExtraAsset::register($view);
161
            }
162
163
            return Html::tag('nav', $wraper, $this->options);
164
        }
165
    }
166
167
    /**
168
     * Renders a single breadcrumb item.
169
     *
170
     * @param array $link the link to be rendered. It must contain the "label" element. The "url" element is optional.
171
     * @return string the rendering result
172
     * @throws InvalidConfigException if `$link` does not have "label" element.
173
     */
174
    protected function renderItem($link)
175
    {
176
        $encodeLabel = ArrayHelper::remove($link, 'encode', $this->encodeLabels);
177
178
        if (array_key_exists('label', $link)) {
179
            $label = $encodeLabel ? Html::encode($link['label']) : $link['label'];
180
        } else {
181
            throw new InvalidConfigException('The "label" element is required for each link.');
182
        }
183
184
        // Add icon to label text
185
        if (isset($link['icon'])) {
186
            $label = $this->renderIcon($link['icon']) . $label;
187
        }
188
189
        $options = $link;
190
        unset($options['label'], $options['url'], $options['icon']);
191
192
        if (!isset($options['class'])) {
193
            Html::addCssClass($options, 'breadcrumb');
194
        }
195
196
        if (isset($link['url'])) {
197
            return Html::a($label, $link['url'], $options);
198
        } else {
199
            return Html::tag('span', $label, $options) ;
200
        }
201
    }
202
203
    /**
204
     * Renders an icon.
205
     * Has issues on positioning: https://github.com/Dogfalo/materialize/issues/6224
206
     *
207
     * @param string|array $icon the options for the optional icon.
208
     * @return string the rendered icon
209
     * @throws \yii\base\InvalidConfigException if icon name is not specified
210
     *
211
     * @uses http://www.yiiframework.com/doc-2.0/yii-helpers-basearrayhelper.html#getValue()-detail
212
     * @see Icon::run
213
     */
214
    protected function renderIcon($icon)
215
    {
216
        $html = '';
217
218
        if (!empty($icon)) {
219
            if (is_array($icon) && isset($icon['name'])) {
220
                $iconName = ArrayHelper::getValue($icon, 'name', null);
221
            } elseif (is_string($icon)) {
222
                $iconName = $icon;
223
            } else {
224
                throw new InvalidConfigException('The icon name must be specified.');
225
            }
226
227
            $iconOptions = ArrayHelper::getValue($icon, 'options', []);
228
            $html = Html::icon($iconName, $iconOptions);
229
        }
230
231
        return $html;
232
    }
233
}
234