Passed
Push — master ( 598b94...5462ba )
by Wilmer
02:02
created

Progress   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 171
Duplicated Lines 0 %

Test Coverage

Coverage 97.96%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 47
c 1
b 0
f 0
dl 0
loc 171
ccs 48
cts 49
cp 0.9796
rs 10
wmc 12

8 Methods

Rating   Name   Duplication   Size   Complexity  
A run() 0 10 2
A label() 0 6 1
A percent() 0 6 1
A options() 0 6 1
A bars() 0 6 1
A renderBar() 0 16 1
A barOptions() 0 6 1
A renderProgress() 0 22 4
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 6
    protected function run(): string
64
    {
65 6
        if (!isset($this->options['id'])) {
66 6
            $this->options['id'] = "{$this->getId()}-progress";
67
        }
68
69
        /** @psalm-suppress InvalidArgument */
70 6
        Html::addCssClass($this->options, ['widget' => 'progress']);
71
72 6
        return $this->renderProgress();
73
    }
74
75
    /**
76
     * Set of bars that are stacked together to form a single progress bar.
77
     *
78
     * Each bar is an array of the following structure:
79
     *
80
     * ```php
81
     * [
82
     *     // required, the amount of progress as a percentage.
83
     *     'percent' => '30',
84
     *     // optional, the label to be displayed on the bar
85
     *     'label' => '30%',
86
     *     // optional, array, additional HTML attributes for the bar tag
87
     *     'options' => [],
88
     * ]
89
     * ```
90
     *
91
     * @param array $value
92
     *
93
     * @return self
94
     */
95 4
    public function bars(array $value): self
96
    {
97 4
        $new = clone $this;
98 4
        $new->bars = $value;
99
100 4
        return $new;
101
    }
102
103
    /**
104
     * The HTML attributes of the bar. This property will only be considered if {@see bars} is empty.
105
     *
106
     * @param array $value
107
     *
108
     * @return self
109
     *
110
     * {@see Html::renderTagAttributes() for details on how attributes are being rendered}
111
     */
112 1
    public function barOptions(array $value): self
113
    {
114 1
        $new = clone $this;
115 1
        $new->barOptions = $value;
116
117 1
        return $new;
118
    }
119
120
    /**
121
     * The button label.
122
     *
123
     * @param string $value
124
     *
125
     * @return self
126
     */
127 1
    public function label(string $value): self
128
    {
129 1
        $new = clone $this;
130 1
        $new->label = $value;
131
132 1
        return $new;
133
    }
134
135
    /**
136
     * The HTML attributes for the widget container tag. The following special options are recognized.
137
     *
138
     * @param array $value
139
     *
140
     * @return self
141
     *
142
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
143
     */
144 1
    public function options(array $value): self
145
    {
146 1
        $new = clone $this;
147 1
        $new->options = $value;
148
149 1
        return $new;
150
    }
151
152
    /**
153
     * The amount of progress as a percentage.
154
     *
155
     * @param string $value
156
     *
157
     * @return self
158
     */
159 2
    public function percent(string $value): self
160
    {
161 2
        $new = clone $this;
162 2
        $new->percent = $value;
163
164 2
        return $new;
165
    }
166
167
    /**
168
     * Renders the progress.
169
     *
170
     * @throws JsonException|RuntimeException if the "percent" option is not set in a stacked progress bar.
171
     *
172
     * @return string the rendering result.
173
     */
174 6
    private function renderProgress(): string
175
    {
176 6
        if (empty($this->bars)) {
177
            $this->bars = [
178 2
                ['label' => $this->label, 'percent' => $this->percent, 'options' => $this->barOptions],
179
            ];
180
        }
181
182 6
        $bars = [];
183
184 6
        foreach ($this->bars as $bar) {
185 6
            $label = ArrayHelper::getValue($bar, 'label', '');
186 6
            if (!isset($bar['percent'])) {
187 1
                throw new RuntimeException('The "percent" option is required.');
188
            }
189 5
            $options = ArrayHelper::getValue($bar, 'options', []);
190 5
            $bars[] = $this->renderBar($bar['percent'], $label, $options);
191
        }
192
193 5
        return Html::div(implode("\n", $bars), $this->options)
194 5
            ->encode($this->encodeTags)
195 5
            ->render();
196
    }
197
198
    /**
199
     * Generates a bar.
200
     *
201
     * @param string $percent the percentage of the bar
202
     * @param string $label , optional, the label to display at the bar
203
     * @param array $options the HTML attributes of the bar
204
     *
205
     * @throws JsonException
206
     *
207
     * @return string the rendering result.
208
     */
209 5
    private function renderBar(string $percent, string $label = '', array $options = []): string
210
    {
211 5
        $valuePercent = (float)trim(rtrim($percent, '%'));
212
213 5
        $options = array_merge($options, [
214 5
            'role' => 'progressbar',
215 5
            'aria-valuenow' => $percent,
216 5
            'aria-valuemin' => 0,
217 5
            'aria-valuemax' => 100,
218
        ]);
219
220
        /** @psalm-suppress InvalidArgument */
221 5
        Html::addCssClass($options, ['widget' => 'progress-bar']);
222 5
        Html::addCssStyle($options, ['width' => $valuePercent . '%'], true);
223
224 5
        return Html::div($label, $options)->render();
225
    }
226
}
227