Passed
Push — master ( f44342...332901 )
by Alexander
01:52
created

src/ButtonDropdown.php (1 issue)

Labels
Severity
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Bootstrap5;
6
7
use Yiisoft\Arrays\ArrayHelper;
8
9
/**
10
 * ButtonDropdown renders a group or split button dropdown bootstrap component.
11
 *
12
 * For example,
13
 *
14
 * ```php
15
 * // a button group using Dropdown widget
16
 * echo ButtonDropdown::widget()
17
 *     ->label('Action')
18
 *     ->dropdown'([
19
 *         'items' => [
20
 *             ['label' => 'DropdownA', 'url' => '/'],
21
 *             ['label' => 'DropdownB', 'url' => '#'],
22
 *         ],
23
 *     ]);
24
 * ```
25
 */
26
class ButtonDropdown extends Widget
27
{
28
    /**
29
     * The css class part of dropdown
30
     */
31
    public const DIRECTION_DOWN = 'down';
32
33
    /**
34
     * The css class part of dropleft
35
     */
36
    public const DIRECTION_LEFT = 'left';
37
38
    /**
39
     * The css class part of dropright
40
     */
41
    public const DIRECTION_RIGHT = 'right';
42
43
    /**
44
     * The css class part of dropup
45
     */
46
    public const DIRECTION_UP = 'up';
47
48
    private string $label = 'Button';
49
50
    private array $options = [];
51
52
    private array $buttonOptions = [];
53
54
    private array $dropdown = [];
55
56
    private string $direction = self::DIRECTION_DOWN;
57
58
    private bool $split = false;
59
60
    private string $tagName = 'button';
61
62
    private bool $encodeLabels = true;
63
64
    private string $dropdownClass = Dropdown::class;
65
66
    private bool $renderContainer = true;
67
68
    protected function run(): string
69
    {
70
        /* Set options id to button options id to ensure correct css selector in plugin initialisation */
71
        if (empty($this->options['id'])) {
72
            $id = $this->getId();
73
74
            $this->options['id'] = "{$id}-button-dropdown";
75
            $this->buttonOptions['id'] = "{$id}-button";
76
        }
77
78
        $html = $this->renderButton() . "\n" . $this->renderDropdown();
79
80
        if ($this->renderContainer) {
81
            Html::addCssClass($this->options, ['widget' => 'drop' . $this->direction, 'btn-group']);
82
83
            $options = $this->options;
84
            $tag = ArrayHelper::remove($options, 'tag', 'div');
85
            $html = Html::tag($tag, $html, $options);
86
        }
87
88
        $this->registerPlugin('dropdown', $this->options);
89
90
        return $html;
91
    }
92
93
    /**
94
     * Generates the button dropdown.
95
     *
96
     * @return string the rendering result.
97
     */
98
    protected function renderButton(): string
99
    {
100
        Html::addCssClass($this->buttonOptions, ['widget' => 'btn']);
101
102
        $label = $this->label;
103
104
        if ($this->encodeLabels) {
105
            $label = Html::encode($label);
106
        }
107
108
        if ($this->split) {
109
            $buttonOptions = $this->buttonOptions;
110
111
            $this->buttonOptions['data-toggle'] = 'dropdown';
112
            $this->buttonOptions['aria-haspopup'] = 'true';
113
            $this->buttonOptions['aria-expanded'] = 'false';
114
115
            Html::addCssClass($this->buttonOptions, ['toggle' => 'dropdown-toggle dropdown-toggle-split']);
116
117
            unset($buttonOptions['id']);
118
119
            $splitButton = Button::widget()
120
                ->label('<span class="sr-only">Toggle Dropdown</span>')
121
                ->encodeLabels(false)
122
                ->options($this->buttonOptions)
123
                ->run();
124
        } else {
125
            $buttonOptions = $this->buttonOptions;
126
127
            Html::addCssClass($buttonOptions, ['toggle' => 'dropdown-toggle']);
128
129
            $buttonOptions['data-toggle'] = 'dropdown';
130
            $buttonOptions['aria-haspopup'] = 'true';
131
            $buttonOptions['aria-expanded'] = 'false';
132
            $splitButton = '';
133
        }
134
135
        if (!isset($buttonOptions['href']) && ($this->tagName === 'a')) {
136
            $buttonOptions['href'] = '#';
137
            $buttonOptions['role'] = 'button';
138
        }
139
140
        return Button::widget()
141
                ->tagName($this->tagName)
142
                ->label($label)
143
                ->options($buttonOptions)
144
                ->encodeLabels(false)
145
                ->run()
146
                . "\n" . $splitButton;
147
    }
148
149
    /**
150
     * Generates the dropdown menu.
151
     *
152
     * @return string the rendering result.
153
     */
154
    protected function renderDropdown(): string
155
    {
156
        /** @var Widget $dropdownClass */
157
        $dropdownClass = $this->dropdownClass;
158
159
        return $dropdownClass::widget()
160
            ->items($this->dropdown['items'])
0 ignored issues
show
The method items() does not exist on Yiisoft\Widget\Widget. It seems like you code against a sub-type of Yiisoft\Widget\Widget such as Yiisoft\Yii\Bootstrap5\Nav or Yiisoft\Yii\Bootstrap5\Carousel or Yiisoft\Yii\Bootstrap5\Dropdown or Yiisoft\Yii\Bootstrap5\Tabs or Yiisoft\Yii\Bootstrap5\Accordion. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

160
            ->/** @scrutinizer ignore-call */ items($this->dropdown['items'])
Loading history...
161
            ->render();
162
    }
163
164
    /**
165
     * The HTML attributes of the button.
166
     *
167
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
168
     */
169
    public function buttonOptions(array $value): self
170
    {
171
        $this->buttonOptions = $value;
172
173
        return $this;
174
    }
175
176
    /**
177
     * The drop-direction of the widget.
178
     *
179
     * Possible values are 'left', 'right', 'up', or 'down' (default)
180
     */
181
    public function direction(string $value): self
182
    {
183
        $this->direction = $value;
184
185
        return $this;
186
    }
187
188
    /**
189
     * The configuration array for example:
190
     *
191
     * ```php
192
     *    [
193
     *        'items' => [
194
     *            ['label' => 'DropdownA', 'url' => '/'],
195
     *            ['label' => 'DropdownB', 'url' => '#'],
196
     *        ],
197
     *    ]
198
     * ```
199
     *
200
     * {@see Dropdown}
201
     */
202
    public function dropdown(array $value): self
203
    {
204
        $this->dropdown = $value;
205
206
        return $this;
207
    }
208
209
    /**
210
     * Name of a class to use for rendering dropdowns withing this widget. Defaults to {@see Dropdown}.
211
     */
212
    public function dropdownClass(string $value): self
213
    {
214
        $this->dropdownClass = $value;
215
216
        return $this;
217
    }
218
219
    /**
220
     * Whether the label should be HTML-encoded.
221
     */
222
    public function encodeLabels(bool $value): self
223
    {
224
        $this->encodeLabels = $value;
225
226
        return $this;
227
    }
228
229
    /**
230
     * The button label.
231
     */
232
    public function label(string $value): self
233
    {
234
        $this->label = $value;
235
236
        return $this;
237
    }
238
239
    /**
240
     * The HTML attributes for the container tag. The following special options are recognized.
241
     *
242
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
243
     */
244
    public function options(array $value): self
245
    {
246
        $this->options = $value;
247
248
        return $this;
249
    }
250
251
    /**
252
     * Whether to render the container using the {@see options} as HTML attributes. If set to `false`, the container
253
     * element enclosing the button and dropdown will NOT be rendered.
254
     */
255
    public function renderContainer(bool $value): self
256
    {
257
        $this->renderContainer = $value;
258
259
        return $this;
260
    }
261
262
    /**
263
     * Whether to display a group of split-styled button group.
264
     */
265
    public function split(bool $value): self
266
    {
267
        $this->split = $value;
268
269
        return $this;
270
    }
271
272
    /**
273
     * The tag to use to render the button.
274
     */
275
    public function tagName(string $value): self
276
    {
277
        $this->tagName = $value;
278
279
        return $this;
280
    }
281
}
282