Completed
Push — 2.0 ( 360d87...ea41ea )
by Olivier
03:48 queued 01:44
created

ErrorCollection::offsetExists()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 2
eloc 2
nc 2
nop 1
1
<?php
2
3
/*
4
 * This file is part of the ICanBoogie package.
5
 *
6
 * (c) Olivier Laviale <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace ICanBoogie;
13
14
/**
15
 * An error collection.
16
 */
17
class ErrorCollection implements \ArrayAccess, \IteratorAggregate, \Countable, \JsonSerializable, ToArray
18
{
19
	/**
20
	 * Special identifier used when an error is not associated with a specific attribute.
21
	 */
22
	const GENERIC = '__generic__';
23
24
	/**
25
	 * @var Error[][]
26
	 */
27
	private $collection = [];
28
29
	/**
30
	 * Add an error associated with an attribute.
31
	 *
32
	 * @param string|null $attribute Attribute name or `null` for _generic_.
33
	 * @param Error|string|bool $error_or_format_or_true A {@link Error} instance or
34
	 * a format to create that instance, or `true`.
35
	 * @param array $args Only used if `$error_or_format_or_true` is not a {@link Error}
36
	 * instance or `true`.
37
	 *
38
	 * @return $this
39
	 */
40
	public function add($attribute, $error_or_format_or_true = true, array $args = [])
41
	{
42
		$this->collection[$attribute ?: self::GENERIC][] = $this
43
			->ensure_error_instance($error_or_format_or_true, $args);
44
45
		return $this;
46
	}
47
48
	/**
49
	 * Add an error not associated with any attribute.
50
	 *
51
	 * @param Error|string|bool $error_or_format_or_true A {@link Error} instance or
52
	 * a format to create that instance, or `true`.
53
	 * @param array $args Only used if `$error_or_format_or_true` is not a {@link Error}
54
	 * instance or `true`.
55
	 *
56
	 * @return $this
57
	 */
58
	public function add_generic($error_or_format_or_true = true, array $args = [])
59
	{
60
		return $this->add(null, $error_or_format_or_true, $args);
61
	}
62
63
	/**
64
	 * Ensures a {@link Error} instance.
65
	 *
66
	 * @param Error|string|bool $error_or_format_or_true
67
	 * @param array $args
68
	 *
69
	 * @return Error
70
	 */
71
	protected function ensure_error_instance($error_or_format_or_true, array $args = [])
72
	{
73
		$error = $error_or_format_or_true;
74
75
		if (!$error instanceof Error)
76
		{
77
			$error = new Error($error === true ? "" : $error, $args);
0 ignored issues
show
Bug introduced by
It seems like $error === true ? '' : $error can also be of type boolean; however, ICanBoogie\Error::__construct() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
78
		}
79
80
		return $error;
81
	}
82
83
	/**
84
	 * Adds an error.
85
	 *
86
	 * @param string $attribute
87
	 * @param Error|string|true $error
88
	 *
89
	 * @see add()
90
	 */
91
	public function offsetSet($attribute, $error)
92
	{
93
		$this->add($attribute, $error);
94
	}
95
96
	/**
97
	 * Clears the errors of an attribute.
98
	 *
99
	 * @param string|null $attribute Attribute name or `null` for _generic_.
100
	 */
101
	public function offsetUnset($attribute)
102
	{
103
		unset($this->collection[$attribute ?: self::GENERIC]);
104
	}
105
106
	/**
107
	 * Checks if an error is defined for an attribute.
108
	 *
109
	 * ```php
110
	 * <?php
111
	 *
112
	 * use ICanBoogie\ErrorCollection
113
	 *
114
	 * $errors = new ErrorCollection;
115
	 * isset($errors['username']);
116
	 * // false
117
	 * $errors->add('username');
118
	 * isset($errors['username']);
119
	 * // true
120
	 * ```
121
	 *
122
	 * @param string|null $attribute Attribute name or `null` for _generic_.
123
	 *
124
	 * @return boolean true if an error is defined for the specified attribute, false otherwise.
125
	 */
126
	public function offsetExists($attribute)
127
	{
128
		return isset($this->collection[$attribute ?: self::GENERIC]);
129
	}
130
131
	/**
132
	 * Returns errors associated with an attribute.
133
	 *
134
	 * ```php
135
	 * <?php
136
	 *
137
	 * use ICanBoogie\ErrorCollection;
138
	 *
139
	 * $errors = new ErrorCollection;
140
	 * $errors['password']
141
	 * // []
142
	 * $errors->add('password')
143
	 * // [ Message ]
144
	 * ```
145
	 *
146
	 * @param string|null $attribute Attribute name or `null` for _generic_.
147
	 *
148
	 * @return Error[]
149
	 */
150
	public function offsetGet($attribute)
151
	{
152
		if (!$this->offsetExists($attribute))
153
		{
154
			return [];
155
		}
156
157
		return $this->collection[$attribute ?: self::GENERIC];
158
	}
159
160
	/**
161
	 * @inheritdoc
162
	 */
163
	public function getIterator()
164
	{
165
		foreach ($this->to_array() as $attribute => $errors)
166
		{
167
			foreach ($errors as $error)
168
			{
169
				yield $attribute => $error;
170
			}
171
		}
172
	}
173
174
	/**
175
	 * Iterates through errors using a callback.
176
	 *
177
	 * ```php
178
	 * <?php
179
	 *
180
	 * use ICanBoogie\ErrorCollection;
181
	 *
182
	 * $errors = new ErrorCollection;
183
	 * $errors->add('username', "Funny user name");
184
	 * $errors->add('password', "Weak password");
185
	 *
186
	 * $errors->each(function ($error, $attribute, $errors) {
187
	 *
188
	 *     echo "$attribute => $error<br />";
189
	 *
190
	 * });
191
	 * </pre>
192
	 *
193
	 * @param callable $callback Function to execute for each element, taking three arguments:
194
	 *
195
	 * - `Error $error`: The current error.
196
	 * - `string $attribute`: The attribute or {@link self::GENERIC}.
197
	 * - `ErrorCollection $collection`: This instance.
198
	 */
199
	public function each(callable $callback)
200
	{
201
		foreach ($this as $attribute => $error)
202
		{
203
			$callback($error, $attribute, $this);
204
		}
205
	}
206
207
	/**
208
	 * Returns the total number of errors.
209
	 *
210
	 * @inheritdoc
211
	 */
212
	public function count()
213
	{
214
		$n = 0;
215
216
		foreach ($this->collection as $errors)
217
		{
218
			$n += count($errors);
219
		}
220
221
		return $n;
222
	}
223
224
	/**
225
	 * @inheritdoc
226
	 */
227
	public function jsonSerialize()
228
	{
229
		return $this->to_array();
230
	}
231
232
	/**
233
	 * Converts the object into an array.
234
	 *
235
	 * @return Error[][]
236
	 */
237
	public function to_array()
238
	{
239
		return array_filter(array_merge([ self::GENERIC => [] ], $this->collection));
240
	}
241
242
	/**
243
	 * Clears errors.
244
	 *
245
	 * @return $this
246
	 */
247
	public function clear()
248
	{
249
		$this->collection = [];
250
251
		return $this;
252
	}
253
}
254