|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* @author Jared King <[email protected]> |
|
5
|
|
|
* |
|
6
|
|
|
* @link http://jaredtking.com |
|
7
|
|
|
* |
|
8
|
|
|
* @copyright 2015 Jared King |
|
9
|
|
|
* @license MIT |
|
10
|
|
|
*/ |
|
11
|
|
|
namespace Pulsar; |
|
12
|
|
|
|
|
13
|
|
|
use Pimple\Container; |
|
14
|
|
|
|
|
15
|
|
|
class Errors implements \Iterator, \Countable, \ArrayAccess |
|
16
|
|
|
{ |
|
17
|
|
|
/** |
|
18
|
|
|
* @var array |
|
19
|
|
|
*/ |
|
20
|
|
|
private $stack; |
|
21
|
|
|
|
|
22
|
|
|
/** |
|
23
|
|
|
* @var string |
|
24
|
|
|
*/ |
|
25
|
|
|
private $context; |
|
26
|
|
|
|
|
27
|
|
|
/** |
|
28
|
|
|
* @var \Pimple\Container |
|
29
|
|
|
*/ |
|
30
|
|
|
private $app; |
|
31
|
|
|
|
|
32
|
|
|
/** |
|
33
|
|
|
* @var int |
|
34
|
|
|
*/ |
|
35
|
|
|
private $pointer; |
|
36
|
|
|
|
|
37
|
|
|
public function __construct(Container $app) |
|
38
|
|
|
{ |
|
39
|
|
|
$this->stack = []; |
|
40
|
|
|
$this->context = ''; |
|
41
|
|
|
$this->app = $app; |
|
42
|
|
|
$this->pointer = 0; |
|
43
|
|
|
} |
|
44
|
|
|
|
|
45
|
|
|
/** |
|
46
|
|
|
* Adds an error message to the stack. |
|
47
|
|
|
* |
|
48
|
|
|
* @param array|string $error |
|
49
|
|
|
* - error: error code |
|
50
|
|
|
* - params: array of parameters to be passed to message |
|
51
|
|
|
* - context: (optional) the context which the error message occured in |
|
52
|
|
|
* - class: (optional) the class invoking the error |
|
53
|
|
|
* - function: (optional) the function invoking the error |
|
54
|
|
|
* |
|
55
|
|
|
* @return self |
|
56
|
|
|
*/ |
|
57
|
|
|
public function push($error) |
|
58
|
|
|
{ |
|
59
|
|
|
$this->stack[] = $this->sanitize($error); |
|
60
|
|
|
|
|
61
|
|
|
return $this; |
|
62
|
|
|
} |
|
63
|
|
|
|
|
64
|
|
|
/** |
|
65
|
|
|
* Sets the current default error context. |
|
66
|
|
|
* |
|
67
|
|
|
* @param string $context |
|
68
|
|
|
* |
|
69
|
|
|
* @return self |
|
70
|
|
|
*/ |
|
71
|
|
|
public function setCurrentContext($context = '') |
|
72
|
|
|
{ |
|
73
|
|
|
$this->context = $context; |
|
74
|
|
|
|
|
75
|
|
|
return $this; |
|
76
|
|
|
} |
|
77
|
|
|
|
|
78
|
|
|
/** |
|
79
|
|
|
* Clears the current default error context. |
|
80
|
|
|
* |
|
81
|
|
|
* @return self |
|
82
|
|
|
*/ |
|
83
|
|
|
public function clearCurrentContext() |
|
84
|
|
|
{ |
|
85
|
|
|
$this->context = ''; |
|
86
|
|
|
|
|
87
|
|
|
return $this; |
|
88
|
|
|
} |
|
89
|
|
|
|
|
90
|
|
|
/** |
|
91
|
|
|
* Gets all of the errors on the stack and also attempts |
|
92
|
|
|
* translation using the Locale class. |
|
93
|
|
|
* |
|
94
|
|
|
* @param string $context optional context |
|
95
|
|
|
* @param string $locale optional locale |
|
96
|
|
|
* |
|
97
|
|
|
* @return array errors |
|
98
|
|
|
*/ |
|
99
|
|
|
public function errors($context = '', $locale = '') |
|
100
|
|
|
{ |
|
101
|
|
|
$errors = []; |
|
102
|
|
|
foreach ($this->stack as $error) { |
|
103
|
|
|
if (!$context || $error['context'] == $context) { |
|
104
|
|
|
$errors[] = $this->parse($error, $locale); |
|
105
|
|
|
} |
|
106
|
|
|
} |
|
107
|
|
|
|
|
108
|
|
|
return $errors; |
|
109
|
|
|
} |
|
110
|
|
|
|
|
111
|
|
|
/** |
|
112
|
|
|
* Gets the messages of errors on the stack. |
|
113
|
|
|
* |
|
114
|
|
|
* @param string $context optional context |
|
115
|
|
|
* @param string $locale optional locale |
|
116
|
|
|
* |
|
117
|
|
|
* @return array errors |
|
118
|
|
|
*/ |
|
119
|
|
|
public function messages($context = '', $locale = '') |
|
120
|
|
|
{ |
|
121
|
|
|
$messages = []; |
|
122
|
|
|
foreach ($this->errors($context, $locale) as $error) { |
|
123
|
|
|
$messages[] = $error['message']; |
|
124
|
|
|
} |
|
125
|
|
|
|
|
126
|
|
|
return $messages; |
|
127
|
|
|
} |
|
128
|
|
|
|
|
129
|
|
|
/** |
|
130
|
|
|
* Gets an error for a specific parameter on the stack. |
|
131
|
|
|
* |
|
132
|
|
|
* @param string $value value we are searching for |
|
133
|
|
|
* @param string $param parameter name |
|
134
|
|
|
* |
|
135
|
|
|
* @return array|bool |
|
136
|
|
|
*/ |
|
137
|
|
|
public function find($value, $param = 'field') |
|
138
|
|
|
{ |
|
139
|
|
|
foreach ($this->errors() as $error) { |
|
140
|
|
|
if (array_value($error['params'], $param) === $value) { |
|
141
|
|
|
return $error; |
|
142
|
|
|
} |
|
143
|
|
|
} |
|
144
|
|
|
|
|
145
|
|
|
return false; |
|
146
|
|
|
} |
|
147
|
|
|
|
|
148
|
|
|
/** |
|
149
|
|
|
* Checks if an error exists with a specific parameter on the stack. |
|
150
|
|
|
* |
|
151
|
|
|
* @param string $value value we are searching for |
|
152
|
|
|
* @param string $param parameter name |
|
153
|
|
|
* |
|
154
|
|
|
* @return bool |
|
155
|
|
|
*/ |
|
156
|
|
|
public function has($value, $param = 'field') |
|
157
|
|
|
{ |
|
158
|
|
|
return $this->find($value, $param) !== false; |
|
159
|
|
|
} |
|
160
|
|
|
|
|
161
|
|
|
/** |
|
162
|
|
|
* Clears the error stack. |
|
163
|
|
|
* |
|
164
|
|
|
* @return self |
|
165
|
|
|
*/ |
|
166
|
|
|
public function clear() |
|
167
|
|
|
{ |
|
168
|
|
|
$this->stack = []; |
|
169
|
|
|
|
|
170
|
|
|
return $this; |
|
171
|
|
|
} |
|
172
|
|
|
|
|
173
|
|
|
/** |
|
174
|
|
|
* Formats an incoming error message. |
|
175
|
|
|
* |
|
176
|
|
|
* @param array|string $error |
|
177
|
|
|
* |
|
178
|
|
|
* @return array |
|
179
|
|
|
*/ |
|
180
|
|
|
private function sanitize($error) |
|
181
|
|
|
{ |
|
182
|
|
|
if (!is_array($error)) { |
|
183
|
|
|
$error = ['error' => $error]; |
|
184
|
|
|
} |
|
185
|
|
|
|
|
186
|
|
|
if (!isset($error['context'])) { |
|
187
|
|
|
$error['context'] = $this->context; |
|
188
|
|
|
} |
|
189
|
|
|
|
|
190
|
|
|
if (!isset($error['params'])) { |
|
191
|
|
|
$error['params'] = []; |
|
192
|
|
|
} |
|
193
|
|
|
|
|
194
|
|
|
return $error; |
|
195
|
|
|
} |
|
196
|
|
|
|
|
197
|
|
|
/** |
|
198
|
|
|
* Parses an error message before displaying it. |
|
199
|
|
|
* |
|
200
|
|
|
* @param array $error |
|
201
|
|
|
* @param string $locale |
|
202
|
|
|
* |
|
203
|
|
|
* @return array |
|
204
|
|
|
*/ |
|
205
|
|
|
private function parse(array $error, $locale = '') |
|
206
|
|
|
{ |
|
207
|
|
|
// attempt to translate error into a message |
|
208
|
|
|
if (!isset($error['message'])) { |
|
209
|
|
|
$error['message'] = $this->app['locale']->t($error['error'], $error['params'], $locale); |
|
210
|
|
|
} |
|
211
|
|
|
|
|
212
|
|
|
return $error; |
|
213
|
|
|
} |
|
214
|
|
|
|
|
215
|
|
|
////////////////////////// |
|
216
|
|
|
// Iterator Interface |
|
217
|
|
|
////////////////////////// |
|
218
|
|
|
|
|
219
|
|
|
/** |
|
220
|
|
|
* Rewind the Iterator to the first element. |
|
221
|
|
|
*/ |
|
222
|
|
|
public function rewind() |
|
223
|
|
|
{ |
|
224
|
|
|
$this->pointer = 0; |
|
225
|
|
|
} |
|
226
|
|
|
|
|
227
|
|
|
/** |
|
228
|
|
|
* Returns the current element. |
|
229
|
|
|
* |
|
230
|
|
|
* @return array|null |
|
231
|
|
|
*/ |
|
232
|
|
|
public function current() |
|
233
|
|
|
{ |
|
234
|
|
|
if ($this->pointer >= $this->count()) { |
|
235
|
|
|
return; |
|
236
|
|
|
} |
|
237
|
|
|
|
|
238
|
|
|
$errors = $this->errors(); |
|
239
|
|
|
|
|
240
|
|
|
return $errors[$this->pointer]; |
|
241
|
|
|
} |
|
242
|
|
|
|
|
243
|
|
|
/** |
|
244
|
|
|
* Return the key of the current element. |
|
245
|
|
|
* |
|
246
|
|
|
* @return int |
|
247
|
|
|
*/ |
|
248
|
|
|
public function key() |
|
249
|
|
|
{ |
|
250
|
|
|
return $this->pointer; |
|
251
|
|
|
} |
|
252
|
|
|
|
|
253
|
|
|
/** |
|
254
|
|
|
* Move forward to the next element. |
|
255
|
|
|
*/ |
|
256
|
|
|
public function next() |
|
257
|
|
|
{ |
|
258
|
|
|
++$this->pointer; |
|
259
|
|
|
} |
|
260
|
|
|
|
|
261
|
|
|
/** |
|
262
|
|
|
* Checks if current position is valid. |
|
263
|
|
|
* |
|
264
|
|
|
* @return bool |
|
265
|
|
|
*/ |
|
266
|
|
|
public function valid() |
|
267
|
|
|
{ |
|
268
|
|
|
return $this->pointer < $this->count(); |
|
269
|
|
|
} |
|
270
|
|
|
|
|
271
|
|
|
////////////////////////// |
|
272
|
|
|
// Countable Interface |
|
273
|
|
|
////////////////////////// |
|
274
|
|
|
|
|
275
|
|
|
/** |
|
276
|
|
|
* Get total number of models matching query. |
|
277
|
|
|
* |
|
278
|
|
|
* @return int |
|
279
|
|
|
*/ |
|
280
|
|
|
public function count() |
|
281
|
|
|
{ |
|
282
|
|
|
return count($this->stack); |
|
283
|
|
|
} |
|
284
|
|
|
|
|
285
|
|
|
///////////////////////////// |
|
286
|
|
|
// ArrayAccess Interface |
|
287
|
|
|
///////////////////////////// |
|
288
|
|
|
|
|
289
|
|
|
public function offsetExists($offset) |
|
290
|
|
|
{ |
|
291
|
|
|
return isset($this->stack[$offset]); |
|
292
|
|
|
} |
|
293
|
|
|
|
|
294
|
|
View Code Duplication |
public function offsetGet($offset) |
|
|
|
|
|
|
295
|
|
|
{ |
|
296
|
|
|
if (!$this->offsetExists($offset)) { |
|
297
|
|
|
throw new \OutOfBoundsException("$offset does not exist on this ErrorStack"); |
|
298
|
|
|
} |
|
299
|
|
|
|
|
300
|
|
|
$this->pointer = $offset; |
|
301
|
|
|
|
|
302
|
|
|
return $this->current(); |
|
303
|
|
|
} |
|
304
|
|
|
|
|
305
|
|
|
public function offsetSet($offset, $error) |
|
306
|
|
|
{ |
|
307
|
|
|
if (!is_numeric($offset)) { |
|
308
|
|
|
throw new \Exception('Can only perform set on numeric indices'); |
|
309
|
|
|
} |
|
310
|
|
|
|
|
311
|
|
|
$this->stack[$offset] = $this->sanitize($error); |
|
312
|
|
|
} |
|
313
|
|
|
|
|
314
|
|
|
public function offsetUnset($offset) |
|
315
|
|
|
{ |
|
316
|
|
|
unset($this->stack[$offset]); |
|
317
|
|
|
} |
|
318
|
|
|
} |
|
319
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.