Passed
Pull Request — master (#274)
by Sergei
13:23
created

ErrorSummary::addListClass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
eloc 3
c 1
b 1
f 0
nc 1
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Form\Field;
6
7
use InvalidArgumentException;
8
use Yiisoft\Form\Field\Base\BaseField;
9
use Yiisoft\Form\FormModelInterface;
10
use Yiisoft\Form\Helper\HtmlFormErrors;
11
use Yiisoft\Html\Html;
12
13
/**
14
 * Displays a summary of the form validation errors. If there is no validation error, field will be hidden.
15
 */
16
final class ErrorSummary extends BaseField
17
{
18
    private ?FormModelInterface $formModel = null;
19
    private bool $encode = true;
20
21
    private bool $showAllErrors = false;
22
    private array $onlyAttributes = [];
23
24
    private string $footer = '';
25
    private array $footerAttributes = [];
26
    private string $header = 'Please fix the following errors:';
27
    private array $headerAttributes = [];
28
    private array $listAttributes = [];
29
30 14
    public function formModel(FormModelInterface $formModel): self
31
    {
32 14
        $new = clone $this;
33 14
        $new->formModel = $formModel;
34 14
        return $new;
35
    }
36
37
    /**
38
     * Whether error content should be HTML-encoded.
39
     */
40 2
    public function encode(bool $value): self
41
    {
42 2
        $new = clone $this;
43 2
        $new->encode = $value;
44 2
        return $new;
45
    }
46
47
    /**
48
     * Whether to show all errors.
49
     */
50 3
    public function showAllErrors(bool $value = true): self
51
    {
52 3
        $new = clone $this;
53 3
        $new->showAllErrors = $value;
54 3
        return $new;
55
    }
56
57
    /**
58
     * Specific attributes to be filtered out when rendering the error summary.
59
     *
60
     * @param array $names The attribute names to be included in error summary.
61
     */
62 11
    public function onlyAttributes(string ...$names): self
63
    {
64 11
        $new = clone $this;
65 11
        $new->onlyAttributes = $names;
66 11
        return $new;
67
    }
68
69
    /**
70
     * Use only common errors when rendering the error summary.
71
     */
72 2
    public function onlyCommonErrors(): self
73
    {
74 2
        $new = clone $this;
75 2
        $new->onlyAttributes = [''];
76 2
        return $new;
77
    }
78
79
    /**
80
     * Set the footer text for the error summary
81
     */
82 2
    public function footer(string $value): self
83
    {
84 2
        $new = clone $this;
85 2
        $new->footer = $value;
86 2
        return $new;
87
    }
88
89
    /**
90
     * Set footer attributes for the error summary.
91
     *
92
     * @param array $values Attribute values indexed by attribute names.
93
     *
94
     * See {@see Html::renderTagAttributes} for details on how attributes are being rendered.
95
     */
96 2
    public function footerAttributes(array $values): self
97
    {
98 2
        $new = clone $this;
99 2
        $new->footerAttributes = $values;
100 2
        return $new;
101
    }
102
103
    /**
104
     * Set the header text for the error summary
105
     */
106 2
    public function header(string $value): self
107
    {
108 2
        $new = clone $this;
109 2
        $new->header = $value;
110 2
        return $new;
111
    }
112
113
    /**
114
     * Set header attributes for the error summary.
115
     *
116
     * @param array $values Attribute values indexed by attribute names.
117
     *
118
     * See {@see Html::renderTagAttributes} for details on how attributes are being rendered.
119
     */
120 2
    public function headerAttributes(array $values): self
121
    {
122 2
        $new = clone $this;
123 2
        $new->headerAttributes = $values;
124 2
        return $new;
125
    }
126
127
    /**
128
     * Set errors list container attributes.
129
     *
130
     * @param array $attributes Attribute values indexed by attribute names.
131
     *
132
     * See {@see Html::renderTagAttributes} for details on how attributes are being rendered.
133
     */
134 3
    public function listAttributes(array $attributes): self
135
    {
136 3
        $new = clone $this;
137 3
        $new->listAttributes = $attributes;
138 3
        return $new;
139
    }
140
141
    /**
142
     * Add one or more CSS classes to the list container tag.
143
     *
144
     * @param string|null ...$class One or many CSS classes.
145
     */
146 2
    public function addListClass(?string ...$class): self
147
    {
148 2
        $new = clone $this;
149 2
        Html::addCssClass($new->listAttributes, $class);
150 2
        return $new;
151
    }
152
153
    /**
154
     * Replace current list container tag CSS classes with a new set of classes.
155
     *
156
     * @param string|null ...$class One or many CSS classes.
157
     */
158 3
    public function listClass(?string ...$class): static
159
    {
160 3
        $new = clone $this;
161 3
        $new->listAttributes['class'] = array_filter($class, static fn ($c) => $c !== null);
162 3
        return $new;
163
    }
164
165 14
    protected function generateContent(): ?string
166
    {
167 14
        $messages = $this->collectErrors();
168 13
        if (empty($messages)) {
169 1
            return null;
170
        }
171
172 12
        $content = [];
173
174 12
        if ($this->header !== '') {
175 12
            $content[] = Html::p($this->header, $this->headerAttributes)->render();
176
        }
177
178 12
        $content[] = Html::ul()
179 12
            ->attributes($this->listAttributes)
180 12
            ->strings($messages, [], $this->encode)
181 12
            ->render();
182
183 12
        if ($this->footer !== '') {
184 1
            $content[] = Html::p($this->footer, $this->footerAttributes)->render();
185
        }
186
187 12
        return implode("\n", $content);
188
    }
189
190
    /**
191
     * Return array of the validation errors.
192
     *
193
     * @return string[] Array of the validation errors.
194
     */
195 14
    private function collectErrors(): array
196
    {
197 14
        if ($this->formModel === null) {
198 1
            throw new InvalidArgumentException('Form model is not set.');
199
        }
200
201 13
        $errors = HtmlFormErrors::getErrorSummaryFirstErrors($this->formModel);
202
203 13
        if ($this->showAllErrors) {
204 2
            $errors = HtmlFormErrors::getErrorSummary($this->formModel, $this->onlyAttributes);
205 11
        } elseif ($this->onlyAttributes !== []) {
206 9
            $errors = array_intersect_key($errors, array_flip($this->onlyAttributes));
207
        }
208
209
        /**
210
         * If there are the same error messages for different attributes, array_unique will leave gaps between
211
         * sequential keys. Applying array_values to reorder array keys.
212
         *
213
         * @var string[]
214
         */
215 13
        return array_values(array_unique($errors));
216
    }
217
}
218