Errors::add()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 6
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 9
rs 10
1
<?php
2
3
namespace Kontrolio\Error;
4
5
use Countable;
6
use Kontrolio\Data\Attribute;
7
use Kontrolio\Rules\RuleInterface;
8
9
/**
10
 * Validation errors.
11
 */
12
final class Errors implements Countable
13
{
14
    private $messages;
15
    private $errors = [];
16
17
    public function __construct(array $messages)
18
    {
19
        $this->messages = $messages;
20
    }
21
22
    public function raw()
23
    {
24
        return $this->errors;
25
    }
26
27
    /**
28
     * Returns a flattened list of validation errors.
29
     *
30
     * @return array
31
     */
32
    public function flatten()
33
    {
34
        $list = [];
35
36
        foreach ($this->errors as $messages) {
37
            foreach ($messages as $message) {
38
                $list[] = $message;
39
            }
40
        }
41
42
        return $list;
43
    }
44
45
    /**
46
     * @param Attribute|string $attribute
47
     *
48
     * @return bool
49
     */
50
    public function has($attribute)
51
    {
52
        $attribute = $attribute instanceof Attribute ? $attribute->getName() : $attribute;
53
54
        return array_key_exists($attribute, $this->errors);
55
    }
56
57
    #[\ReturnTypeWillChange]
58
    public function count()
59
    {
60
        return count($this->errors);
61
    }
62
63
    public function isEmpty()
64
    {
65
        return $this->count() === 0;
66
    }
67
68
    /**
69
     * Adds a new validation error for the given attribute and rule.
70
     *
71
     * @param Attribute $attribute
72
     * @param RuleInterface $rule
73
     */
74
    public function add(Attribute $attribute, RuleInterface $rule)
75
    {
76
        $name = $attribute->getName();
77
        $errors = $this->prepareErrors($name, $this->prepareRuleKey($name, $rule), $rule);
78
79
        if ($this->has($name)) {
80
            $this->errors[$name] = array_merge($this->errors[$name], $errors);
81
        } else {
82
            $this->errors[$name] = $errors;
83
        }
84
    }
85
86
    /**
87
     * Prepares rule key for the validation error messages array.
88
     *
89
     * @param string $attribute
90
     * @param RuleInterface $rule
91
     *
92
     * @return string
93
     */
94
    private function prepareRuleKey($attribute, RuleInterface $rule)
95
    {
96
        $name = $rule->getName();
97
98
        if ($name) {
99
            return $name;
100
        }
101
102
        if ($this->has($attribute)) {
103
            return $this->count();
104
        }
105
106
        return 0;
107
    }
108
109
    /**
110
     * Prepares validation error messages to proper format.
111
     *
112
     * @param string $attribute
113
     * @param string $ruleName
114
     * @param RuleInterface $rule
115
     *
116
     * @return array
117
     */
118
    private function prepareErrors($attribute, $ruleName, RuleInterface $rule)
119
    {
120
        $messages = $this->getMessagesByAttributeAndRuleName($attribute, $ruleName);
121
        $violations = $rule->getViolations();
122
123
        if (!count($violations)) {
124
            return [reset($messages)];
125
        }
126
127
        return $this->getMessagesForViolations($messages, $violations, $attribute . '.' . $ruleName);
128
    }
129
130
    /**
131
     * Filter all given messages by the attribute and the rule name.
132
     *
133
     * @param string $attribute
134
     * @param string $ruleName
135
     *
136
     * @return array
137
     */
138
    private function getMessagesByAttributeAndRuleName($attribute, $ruleName)
139
    {
140
        $prefix = $attribute . '.' . $ruleName;
141
142
        $messages = array_filter($this->messages, static function ($key) use ($attribute, $prefix) {
143
            return $key === $attribute || strpos($key, $prefix) === 0;
144
        }, ARRAY_FILTER_USE_KEY);
145
146
        if (empty($messages)) {
147
            $messages = [$prefix];
148
        }
149
150
        return $messages;
151
    }
152
153
    /**
154
     * Returns messages for all validation rule violations.
155
     *
156
     * @param array $messages
157
     * @param array $violations
158
     * @param string $prefix
159
     *
160
     * @return array
161
     */
162
    private function getMessagesForViolations(array $messages, array $violations, $prefix)
163
    {
164
        $result = [];
165
166
        foreach ($violations as $violation) {
167
            $keys = [
168
                $prefix,
169
                $prefix . '.' . $violation
170
            ];
171
172
            foreach ($keys as $key) {
173
                if (array_key_exists($key, $messages)) {
174
                    $result[] = $messages[$key];
175
                }
176
            }
177
        }
178
179
        return $result;
180
    }
181
}
182