Passed
Push — master ( 7d4083...604401 )
by Dmitrijs
02:39
created

Collection   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 173
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
wmc 27
eloc 59
c 2
b 0
f 1
dl 0
loc 173
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 8 2
A renderItems() 0 14 3
A renderSecondary() 0 17 6
B renderItem() 0 39 11
A hasHeader() 0 9 4
A run() 0 5 1
1
<?php
2
namespace dmgpage\yii2materialize\widgets;
3
4
use dmgpage\yii2materialize\helpers\Html;
5
use yii\helpers\ArrayHelper;
6
use yii\base\InvalidConfigException;
7
8
/**
9
 * Collections allow you to group list objects together.
10
 *
11
 * ```php
12
 * echo Collection::widget([
13
 *     'items' => [
14
 *         [
15
 *             'label' => '<h5>Best Panda</h5>',
16
 *             'encode' => false,
17
 *             'header' => true
18
 *         ],
19
 *         [
20
 *             'label' => 'Kung Fu Panda',
21
 *             'secondary' => [
22
 *                 'icon' => [
23
 *                     'name' => 'favorite',
24
 *                     'options' =>  ['class' => 'red-text'],
25
 *                 ],
26
 *                 'url' => '#',
27
 *                 'options' => ['target' => '_blank']
28
 *             ]
29
 *         ],
30
 *         [
31
 *             'label' => 'Kung Fu Panda',
32
 *             'secondary' => ['icon' => 'favorite']
33
 *         ],
34
 *         [
35
 *             'label' => 'Kung Fu Panda',
36
 *             'secondary' => ['icon' => 'favorite']
37
 *         ],
38
 *         [
39
 *             'label' => 'Kung Fu Panda',
40
 *             'secondary' => ['icon' => 'favorite']
41
 *         ]
42
 *     ]
43
 * ]);
44
 * ```
45
 * @see https://materializecss.com/collections.html
46
 * @package widgets
47
 */
48
class Collection extends Widget
49
{
50
    /**
51
     * @var array list of items in the collection widget. Each array element represents a single
52
     * row with the following structure:
53
     *
54
     * - label: string, required, the item label.
55
     * - header: boolean, optional, whether this label should be formatted as header.
56
     * - encode: boolean, optional, whether this label should be HTML-encoded. This param will override
57
     *   global `$this->encodeLabels` param.
58
     * - options: array, optional, the HTML attributes of the item container (LI).
59
     * - url: array|string, optional, the URL for the hyperlink tag. Defaults to "#".
60
     * - linkOptions: array, optional, the HTML attributes of the item's link.
61
     * - active: boolean, optional, whether this item should be active.
62
     * - visible: boolean, optional, whether the item tab header and pane should be visible or not. Defaults to true.
63
     * - secondary: array, optional, options for creating secondary content. Available options are:
64
     *   - icon: string|array, required, the options for the icon. See [[Html::icon()]]
65
     *   - options: array, optional, the HTML attributes of the icon link.
66
     *     for more description.
67
     *   - url: array|string, optional, the URL for the icon. Defaults to "#".
68
     * - avatarIcon: string|array, optional, the options for the icon. See [[Html::icon()]]
69
     * - avatarImg: array|string, optional, the path to the avatar image.
70
     * - avatarOptions: array, optional, the HTML attributes of the avatar image or icon tag.
71
     */
72
    public $items = [];
73
74
    /**
75
     * @var boolean whether the labels for items should be HTML-encoded.
76
     */
77
    public $encodeLabels = true;
78
79
    /**
80
     * @var boolean weather format each item as a link
81
     */
82
    public $asLinks = false;
83
84
    /**
85
     * Initializes the widget.
86
     */
87
    public function init()
88
    {
89
        parent::init();
90
91
        Html::addCssClass($this->options, ['widget' => 'collection']);
92
93
        if ($this->hasHeader()) {
94
            Html::addCssClass($this->options, ['header' => 'with-header']);
95
        }
96
    }
97
98
    /**
99
     * Renders the widget.
100
     */
101
    public function run()
102
    {
103
        $this->initializePlugin = true;
104
        $this->registerPlugin('collection');
105
        return $this->renderItems();
106
    }
107
108
    /**
109
     * Renders tab items as specified on [[items]].
110
     *
111
     * @return string the rendering result.
112
     * @throws InvalidConfigException.
113
     */
114
    protected function renderItems()
115
    {
116
        $rows = [];
117
118
        foreach ($this->items as $item) {
119
            $rows[] = $this->renderItem($item);
120
        }
121
        
122
        $containerTag = $this->asLinks ? 'div' : 'ul';
123
        $html = Html::beginTag($containerTag, $this->options);
124
        $html .= implode("\n", $rows);
125
        $html .= Html::endTag($containerTag);
126
127
        return $html;
128
    }
129
130
    /**
131
     * Renders single collection item as specified on [[items]].
132
     *
133
     * @param array $item single collection element
134
     * @return string the rendering result
135
     * @throws InvalidConfigException.
136
     */
137
    protected function renderItem($item)
138
    {
139
        if (!array_key_exists('label', $item)) {
140
            throw new InvalidConfigException("The 'label' option is required.");
141
        } elseif (ArrayHelper::remove($item, 'visible', true)) {
142
            $encodeLabel = isset($item['encode']) ? $item['encode'] : $this->encodeLabels;
143
            $label = $encodeLabel ? Html::encode($item['label']) : $item['label'];
144
            $isHeader = ArrayHelper::getValue($item, 'header', false);
145
            $defaultUrl = $this->asLinks ? '#' : null;
146
            $url = ArrayHelper::getValue($item, 'url', $defaultUrl);
147
            $linkOptions = ArrayHelper::getValue($item, 'linkOptions', []);
148
            $options = ArrayHelper::getValue($item, 'options', []);
149
            $isActive = ArrayHelper::getValue($item, 'active', false);
150
            $containerClass = $isHeader ? 'collection-header' : 'collection-item';
151
            $secondaryItem = ArrayHelper::getValue($item, 'secondary', []);
152
            Html::addCssClass($options, ['item' => $containerClass]);
153
154
            if ($isActive) {
155
                Html::addCssClass($options, ['active' => 'active']);
156
            }
157
158
            // Main content
159
            if (!$this->asLinks && !empty($url)) {
160
                $itemContent = Html::a($label, $url, $linkOptions);
161
            } else {
162
                $itemContent = $label;
163
            }
164
165
            // Secondary content
166
            $itemContent .= $this->renderSecondary($secondaryItem, $isHeader);
167
168
            // Item container
169
            if ($this->asLinks) {
170
                $html = Html::a($itemContent, $url, $options);
171
            } else {
172
                $html = Html::tag('li', $itemContent, $options);
173
            }
174
175
            return $html;
176
        }
177
    }
178
179
    /**
180
     * Renders single secondary content item as specified on [[secondary]].
181
     *
182
     * @param array $item single secondary content element
183
     * @param bool $isHeader whether this label should be formatted as header
184
     * @return string the rendering result
185
     *
186
     * @throws InvalidConfigException.
187
     * @see https://materializecss.com/collections.html#secondary
188
     */
189
    protected function renderSecondary($item, $isHeader)
190
    {
191
        $content = null;
192
193
        if (!empty($item) && !$isHeader && !array_key_exists('icon', $item)) {
194
            throw new InvalidConfigException("The 'icon' option is required for secondary content.");
195
        } else if (!empty($item) && !$isHeader) {
196
            $url = ArrayHelper::getValue($item, 'url', '#');
197
            $options = ArrayHelper::getValue($item, 'options', []);
198
199
            Html::addCssClass($options, ['secondary' => 'secondary-content']);
200
201
            $icon = $this->renderIcon($item['icon']);
202
            $content = Html::a($icon, $url, $options);
203
        }
204
205
        return $content;
206
    }
207
208
    /**
209
     * Searches for header value in [[items]]
210
     * @return boolean if there's header defined
211
     */
212
    protected function hasHeader()
213
    {
214
        foreach ($this->items as $item) {
215
            if (isset($item['header']) && $item['header'] === true) {
216
                return true;
217
            }
218
        }
219
220
        return false;
221
    }
222
}
223