Passed
Pull Request — master (#192)
by Alexander
05:47 queued 02:55
created

ErrorSummary   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 170
Duplicated Lines 0 %

Test Coverage

Coverage 44.83%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 57
dl 0
loc 170
ccs 26
cts 58
cp 0.4483
rs 10
c 1
b 0
f 0
wmc 19

10 Methods

Rating   Name   Duplication   Size   Complexity  
A formModel() 0 5 1
A footerAttributes() 0 5 1
A encode() 0 5 1
A headerAttributes() 0 5 1
A footer() 0 5 1
B collectErrors() 0 31 7
A header() 0 5 1
A onlyAttributes() 0 5 1
A showAllErrors() 0 5 1
A generateContent() 0 20 4
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
final class ErrorSummary extends BaseField
14
{
15
    private ?FormModelInterface $formModel = null;
16
    private bool $encode = true;
17
18
    private bool $showAllErrors = false;
19
    private array $onlyAttributes = [];
20
21
    private string $footer = '';
22
    private array $footerAttributes = [];
23
    private string $header = 'Please fix the following errors:';
24
    private array $headerAttributes = [];
25
26 5
    public function formModel(FormModelInterface $formModel): self
27
    {
28 5
        $new = clone $this;
29 5
        $new->formModel = $formModel;
30 5
        return $new;
31
    }
32
33
    /**
34
     * Whether error content should be HTML-encoded.
35
     */
36
    public function encode(bool $value): self
37
    {
38
        $new = clone $this;
39
        $new->encode = $value;
40
        return $new;
41
    }
42
43
    /**
44
     * Whether to show all errors.
45
     */
46
    public function showAllErrors(bool $value = true): self
47
    {
48
        $new = clone $this;
49
        $new->showAllErrors = $value;
50
        return $new;
51
    }
52
53
    /**
54
     * Specific attributes to be filtered out when rendering the error summary.
55
     *
56
     * @param array $names The attribute names to be included in error summary.
57
     */
58
    public function onlyAttributes(string ...$names): self
59
    {
60
        $new = clone $this;
61
        $new->onlyAttributes = $names;
62
        return $new;
63
    }
64
65
    /**
66
     * Set the footer text for the error summary
67
     *
68
     * @param string $value
69
     *
70
     * @return self
71
     */
72
    public function footer(string $value): self
73
    {
74
        $new = clone $this;
75
        $new->footer = $value;
76
        return $new;
77
    }
78
79
    /**
80
     * Set footer attributes for the error summary.
81
     *
82
     * @param array $values Attribute values indexed by attribute names.
83
     *
84
     * @return self
85
     *
86
     * See {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
87
     */
88
    public function footerAttributes(array $values): self
89
    {
90
        $new = clone $this;
91
        $new->footerAttributes = $values;
92
        return $new;
93
    }
94
95
    /**
96
     * Set the header text for the error summary
97
     *
98
     * @param string $value
99
     *
100
     * @return self
101
     */
102
    public function header(string $value): self
103
    {
104
        $new = clone $this;
105
        $new->header = $value;
106
        return $new;
107
    }
108
109
    /**
110
     * Set header attributes for the error summary.
111
     *
112
     * @param array $values Attribute values indexed by attribute names.
113
     *
114
     * @return self
115
     *
116
     * See {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
117
     */
118
    public function headerAttributes(array $values): self
119
    {
120
        $new = clone $this;
121
        $new->headerAttributes = $values;
122
        return $new;
123
    }
124
125 5
    protected function generateContent(): ?string
126
    {
127 5
        $messages = $this->collectErrors();
128 5
        if (empty($messages)) {
129 1
            return null;
130
        }
131
132 4
        $content = [];
133
134 4
        if ($this->header !== '') {
135 4
            $content[] = Html::p($this->header, $this->headerAttributes)->render();
136
        }
137
138 4
        $content[] = Html::ul()->strings($messages)->render();
139
140 4
        if ($this->footer !== '') {
141
            $content[] = Html::p($this->footer, $this->footerAttributes)->render();
142
        }
143
144 4
        return implode("\n", $content);
145
    }
146
147
    /**
148
     * Return array of the validation errors.
149
     *
150
     * @return string[] Array of the validation errors.
151
     */
152 5
    private function collectErrors(): array
153
    {
154 5
        if ($this->formModel === null) {
155
            throw new InvalidArgumentException('Form model is not set.');
156
        }
157
158 5
        $errors = HtmlFormErrors::getErrorSummaryFirstErrors($this->formModel);
159 5
        $errorMessages = [];
160
161 5
        if ($this->showAllErrors) {
162
            $errors = HtmlFormErrors::getErrorSummary($this->formModel, $this->onlyAttributes);
163 5
        } elseif ($this->onlyAttributes !== []) {
164
            $errors = array_intersect_key($errors, array_flip($this->onlyAttributes));
165
        }
166
167
        /**
168
         * If there are the same error messages for different attributes, array_unique will leave gaps between
169
         * sequential keys. Applying array_values to reorder array keys.
170
         */
171 5
        $lines = array_values(array_unique($errors));
172
173 5
        if ($this->encode) {
174
            /** @var string $line */
175 5
            foreach ($lines as $line) {
176 4
                if (!empty($line)) {
177 4
                    $errorMessages[] = Html::encode($line);
178
                }
179
            }
180
        }
181
182 5
        return $errorMessages;
183
    }
184
}
185