Passed
Pull Request — master (#29)
by Mr.
02:40
created

Progress::renderProgress()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4.0092

Importance

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