Passed
Push — master ( 566566...d0f53d )
by Alexander
02:18
created

Progress   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 186
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 50
dl 0
loc 186
ccs 53
cts 53
cp 1
rs 10
c 1
b 0
f 0
wmc 14

9 Methods

Rating   Name   Duplication   Size   Complexity  
A run() 0 14 3
A renderBar() 0 16 1
A renderProgress() 0 20 4
A label() 0 6 1
A percent() 0 6 1
A options() 0 6 1
A bars() 0 6 1
A barOptions() 0 6 1
A encodeTags() 0 6 1
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_merge;
13
use function implode;
14
use function rtrim;
15
use function trim;
16
17
/**
18
 * Progress renders a bootstrap progress bar component.
19
 *
20
 * For example,
21
 *
22
 * ```php
23
 * // default with label
24
 * echo Progress::widget()
25
 *     ->percent('60')
26
 *     ->label('test');
27
 *
28
 * // styled
29
 * echo Progress::widget()
30
 *     ->bars([
31
 *         ['percent' => '65', 'options' => ['class' => 'bg-danger']]
32
 *     ]);
33
 *
34
 * // striped
35
 * echo Progress::widget()
36
 *     ->bars([
37
 *         ['percent' => '70', 'options' => ['class' => 'bg-warning progress-bar-striped']]
38
 *     ]);
39
 *
40
 * // striped animated
41
 * echo Progress::widget()
42
 *     ->percent('70')
43
 *     ->barOptions(['class' => 'bg-success progress-bar-animated progress-bar-striped']);
44
 *
45
 * // stacked bars
46
 * echo Progress::widget()
47
 *     bars => ([
48
 *         ['percent' => '30', 'options' => ['class' => 'bg-danger']],
49
 *         ['percent' => '30', 'label' => 'test', 'options' => ['class' => 'bg-success']],
50
 *         ['percent' => '35', 'options' => ['class' => 'bg-warning']],
51
 *     ]);
52
 * ```
53
 */
54
final class Progress extends Widget
55
{
56
    private string $label = '';
57
    private string $percent = '';
58
    private array $bars = [];
59
    private array $options = [];
60
    private array $barOptions = [];
61
    private bool $encodeTags = false;
62
63 7
    protected function run(): string
64
    {
65 7
        if (!isset($this->options['id'])) {
66 7
            $this->options['id'] = "{$this->getId()}-progress";
67
        }
68
69
        /** @psalm-suppress InvalidArgument */
70 7
        Html::addCssClass($this->options, ['widget' => 'progress']);
71
72 7
        if ($this->encodeTags === false) {
73 6
            $this->options ['encode'] = false;
74
        }
75
76 7
        return $this->renderProgress();
77
    }
78
79
    /**
80
     * Set of bars that are stacked together to form a single progress bar.
81
     *
82
     * Each bar is an array of the following structure:
83
     *
84
     * ```php
85
     * [
86
     *     // required, the amount of progress as a percentage.
87
     *     'percent' => '30',
88
     *     // optional, the label to be displayed on the bar
89
     *     'label' => '30%',
90
     *     // optional, array, additional HTML attributes for the bar tag
91
     *     'options' => [],
92
     * ]
93
     * ```
94
     *
95
     * @param array $value
96
     *
97
     * @return $this
98
     */
99 5
    public function bars(array $value): self
100
    {
101 5
        $new = clone $this;
102 5
        $new->bars = $value;
103
104 5
        return $new;
105
    }
106
107
    /**
108
     * The HTML attributes of the bar. This property will only be considered if {@see bars} is empty.
109
     *
110
     * @param array $value
111
     *
112
     * @return $this
113
     *
114
     * {@see Html::renderTagAttributes() for details on how attributes are being rendered}
115
     */
116 1
    public function barOptions(array $value): self
117
    {
118 1
        $new = clone $this;
119 1
        $new->barOptions = $value;
120
121 1
        return $new;
122
    }
123
124
    /**
125
     * The button label.
126
     *
127
     * @param string $value
128
     *
129
     * @return $this
130
     */
131 1
    public function label(string $value): self
132
    {
133 1
        $new = clone $this;
134 1
        $new->label = $value;
135
136 1
        return $new;
137
    }
138
139
    /**
140
     * The HTML attributes for the widget container tag. The following special options are recognized.
141
     *
142
     * @param array $value
143
     *
144
     * @return $this
145
     *
146
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
147
     */
148 1
    public function options(array $value): self
149
    {
150 1
        $new = clone $this;
151 1
        $new->options = $value;
152
153 1
        return $new;
154
    }
155
156
    /**
157
     * The amount of progress as a percentage.
158
     *
159
     * @param string $value
160
     *
161
     * @return $this
162
     */
163 2
    public function percent(string $value): self
164
    {
165 2
        $new = clone $this;
166 2
        $new->percent = $value;
167
168 2
        return $new;
169
    }
170
171
    /**
172
     * Allows you to enable the encoding tags html.
173
     *
174
     * @return self
175
     */
176 1
    public function encodeTags(): self
177
    {
178 1
        $new = clone $this;
179 1
        $new->encodeTags = true;
180
181 1
        return $new;
182
    }
183
184
    /**
185
     * Renders the progress.
186
     *
187
     * @throws JsonException|RuntimeException if the "percent" option is not set in a stacked progress bar.
188
     *
189
     * @return string the rendering result.
190
     */
191 7
    private function renderProgress(): string
192
    {
193 7
        if (empty($this->bars)) {
194 2
            $this->bars = [
195 2
                ['label' => $this->label, 'percent' => $this->percent, 'options' => $this->barOptions],
196
            ];
197
        }
198
199 7
        $bars = [];
200
201 7
        foreach ($this->bars as $bar) {
202 7
            $label = ArrayHelper::getValue($bar, 'label', '');
203 7
            if (!isset($bar['percent'])) {
204 1
                throw new RuntimeException('The "percent" option is required.');
205
            }
206 6
            $options = ArrayHelper::getValue($bar, 'options', []);
207 6
            $bars[] = $this->renderBar($bar['percent'], $label, $options);
208
        }
209
210 6
        return Html::div(implode("\n", $bars), $this->options);
211
    }
212
213
    /**
214
     * Generates a bar.
215
     *
216
     * @param string $percent the percentage of the bar
217
     * @param string $label , optional, the label to display at the bar
218
     * @param array $options the HTML attributes of the bar
219
     *
220
     * @throws JsonException
221
     *
222
     * @return string the rendering result.
223
     */
224 6
    private function renderBar(string $percent, string $label = '', array $options = []): string
225
    {
226 6
        $valuePercent = (float) trim(rtrim($percent, '%'));
227
228 6
        $options = array_merge($options, [
229 6
            'role' => 'progressbar',
230 6
            'aria-valuenow' => $percent,
231 6
            'aria-valuemin' => 0,
232 6
            'aria-valuemax' => 100,
233
        ]);
234
235
        /** @psalm-suppress InvalidArgument */
236 6
        Html::addCssClass($options, ['widget' => 'progress-bar']);
237 6
        Html::addCssStyle($options, ['width' => $valuePercent . '%'], true);
238
239 6
        return Html::div($label, $options);
240
    }
241
}
242