Kohana_Jam_Errors::as_array()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php defined('SYSPATH') OR die('No direct script access.');
2
/**
3
 * Jam Errors
4
 *
5
 * @package    Jam
6
 * @category   Model
7
 * @author     Ivan Kerin
8
 * @copyright  (c) 2011-2012 Despark Ltd.
9
 * @license    http://www.opensource.org/licenses/isc-license.txt
10
 */
11
abstract class Kohana_Jam_Errors implements Countable, SeekableIterator, ArrayAccess {
12
13 1
	public static function message($error_filename, $attribute, $error, $params)
14
	{
15 1
		if ($message = Kohana::message($error_filename, "{$attribute}.{$error}"))
16
		{
17
18
		}
19 1
		elseif ($message = Kohana::message('validators', $error))
20 1
		{
21
22
		}
23
		else
24
		{
25
			return $error_filename.":{$attribute}.{$error}";
26
		}
27
28 1
		return __($message, $params);
29
	}
30
31 1
	public static function attribute_label(Jam_Meta $meta, $attribute_name)
32
	{
33 1
		if ($attribute = $meta->attribute($attribute_name))
34
		{
35 1
			$label = $attribute->label;
36
		}
37
		else
38
		{
39
			$label = Inflector::humanize($attribute_name);
40
		}
41
42 1
		return UTF8::ucfirst($label);
43
	}
44
45
	/**
46
	 * @var  Jam_Meta  The current meta object, based on the model we're returning
47
	 */
48
	protected $_meta = NULL;
49
50
	/**
51
	 * @var  Jam_Validated  The current class we're placing results into
52
	 */
53
	protected $_model = NULL;
54
55
	/**
56
	 * @var  string
57
	 */
58
	protected $_error_filename = NULL;
59
60
	private $_container = array();
61
	private $_current;
62
63
	/**
64
	 * Tracks a database result
65
	 *
66
	 * @param  mixed  $result
0 ignored issues
show
Bug introduced by
There is no parameter named $result. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
67
	 * @param  mixed  $model
68
	 */
69 202
	public function __construct(Jam_Validated $model, $error_filename)
70
	{
71 202
		$this->_model = $model;
72 202
		$this->_meta = $model->meta();
73 202
		$this->_error_filename = $error_filename;
74 202
	}
75
76 182
	public function as_array()
77
	{
78 182
		return $this->_container;
79
	}
80
81 107
	public function add($attribute, $error, array $params = array())
82
	{
83 107
		if ( ! isset($this->_container[$attribute]))
84
		{
85 107
			$this->_container[$attribute] = array();
86
		}
87
88 107
		$this->_container[$attribute][$error] = $params;
89
90 107
		return $this;
91
	}
92
93 1
	public function messages($attribute = NULL)
94
	{
95 1
		$messages = array();
96
97 1
		if ($attribute !== NULL)
98
		{
99 1
			foreach (array_filter(Arr::extract($this->_container, (array) $attribute)) as $attribute_name => $errors)
100
			{
101
				foreach ($errors as $error => $params)
102
				{
103
					$messages[] = Jam_Errors::message($this->_error_filename, $attribute_name, $error, Arr::merge($params, array(
104
						':model' => $this->_meta->model(),
105
						':name' => $this->_model->name(),
106
						':attribute' => Jam_Errors::attribute_label($this->_meta, $attribute_name),
107
					)));
108
				}
109
			}
110
111 1
			return $messages;
112
		}
113
114
		foreach ($this->_container as $attribute => $errors)
115
		{
116
			$messages[$attribute] = $this->messages($attribute);
117
		}
118
119
		return $messages;
120
	}
121
122 1
	public function messages_all()
123
	{
124 1
		$messages = array();
125 1
		return $this->_add_messages_all($this->_model, $messages);
126
	}
127
128 1
	private function _add_messages_all(Jam_Validated $model, array & $messages)
129
	{
130 1
		foreach ($model->errors() as $attribute_name => $errors)
0 ignored issues
show
Bug introduced by
The expression $model->errors() of type object<Jam_Errors>|array<integer,string>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
131
		{
132 1
			if ($model->meta()->association($attribute_name) instanceof Jam_Association_Collection)
133
			{
134
				foreach ($model->$attribute_name as $i => $item)
135
				{
136
					if ( ! $item->is_valid())
137
					{
138
						$this->_add_messages_all($item, $messages);
139
					}
140
				}
141
			}
142 1
			elseif ($model->meta()->association($attribute_name) AND $model->$attribute_name)
143
			{
144
				$this->_add_messages_all($model->$attribute_name, $messages);
145
			}
146
			else
147
			{
148 1
				foreach ($errors as $error => $params)
149
				{
150 1
					$model_name = UTF8::ucfirst(Inflector::humanize($model->meta()->model()));
151
152 1
					$messages[] = $model_name.': '.Jam_Errors::message($model->meta()->errors_filename(), $attribute_name, $error, Arr::merge($params, array(
153 1
						':model' => $model->meta()->model(),
154 1
						':name' => $model->name(),
155 1
						':attribute' => Jam_Errors::attribute_label($model->meta(), $attribute_name),
156
					)));
157
				}
158
			}
159
		}
160
161 1
		return $messages;
162
	}
163
164
	public function messages_dump()
165
	{
166
		return $this->_model_messages_dump($this->_model);
0 ignored issues
show
Compatibility introduced by
$this->_model of type object<Jam_Validated> is not a sub-type of object<Jam_Model>. It seems like you assume a child class of the class Jam_Validated to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
167
	}
168
169
	private function _model_messages_dump(Jam_Model $model)
170
	{
171
		$messages = array();
172
		foreach ($model->errors() as $attribute_name => $errors)
0 ignored issues
show
Bug introduced by
The expression $model->errors() of type object<Jam_Errors>|array<integer,string>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
173
		{
174
			if ($model->meta()->association($attribute_name) instanceof Jam_Association_Collection)
175
			{
176
				foreach ($model->$attribute_name as $i => $item)
177
				{
178
					if ( ! $item->is_valid())
179
					{
180
						$messages[] = UTF8::ucfirst(Inflector::humanize($attribute_name)).' ('.$i.'): '.join(', ', $this->_model_messages_dump($item));
181
					}
182
				}
183
			}
184
			elseif ($model->meta()->association($attribute_name) AND $model->$attribute_name)
185
			{
186
				$messages[] = UTF8::ucfirst(Inflector::humanize($attribute_name)).': '.join(', ', $this->_model_messages_dump($model->$attribute_name));
187
			}
188
			else
189
			{
190
				foreach ($errors as $error => $params)
191
				{
192
					$messages[] = Jam_Errors::message($model->meta()->errors_filename(), $attribute_name, $error, Arr::merge($params, array(
193
						':model' => $model->meta()->model(),
194
						':attribute' => Jam_Errors::attribute_label($model->meta(), $attribute_name),
195
					)));
196
				}
197
			}
198
		}
199
200
		return $messages;
201
	}
202
203
	public function __toString()
204
	{
205
		return $this->render();
206
	}
207
208
	public function render()
209
	{
210
		$all_messages = array();
211
		foreach ($this->messages() as $field => $messages)
212
		{
213
			$all_messages[] = join(', ', $messages);
214
		}
215
216
		return join(', ', $all_messages);
217
	}
218
219
	public function first()
220
	{
221
		$messages = $this->current();
222
223
		if (is_array($messages))
224
			return reset($messages);
225
226
		return NULL;
227
	}
228
229
	public function seek($offset)
230
	{
231
		if ($this->offsetExists($offset))
232
		{
233
			$this->_current = $offset;
234
235
			return TRUE;
236
		}
237
		else
238
		{
239
			return FALSE;
240
		}
241
	}
242
243
	public function offsetSet($offset, $value)
244
	{
245
		throw new Kohana_Exception('Cannot set the errors directly, must use add() method');
246
	}
247
248
	public function offsetExists($offset)
249
	{
250
	 return isset($this->_container[$offset]);
251
	}
252
253
	public function offsetUnset($offset)
254
	{
255
		unset($this->_container[$offset]);
256
		if ($this->_current == $offset)
257
		{
258
			$this->rewind();
259
		}
260
	}
261
262 1
	public function offsetGet($offset)
263
	{
264 1
		return isset($this->_container[$offset]) ? $this->_container[$offset] : NULL;
265
	}
266
267 1
	public function rewind()
268
	{
269 1
		reset($this->_container);
270 1
		$this->_current = key($this->_container);
271 1
	}
272
273 1
	public function current()
274
	{
275 1
		return $this->offsetGet($this->_current);
276
	}
277
278 1
	public function key()
279
	{
280 1
		return $this->_current;
281
	}
282
283 1
	public function next()
284
	{
285 1
		next($this->_container);
286 1
		$this->_current = key($this->_container);
287 1
		return $this->current();
288
	}
289
290
	public function prev()
291
	{
292
		prev($this->_container);
293
		$this->_current = key($this->_container);
294
		return $this->current();
295
	}
296
297 1
	public function valid()
298
	{
299 1
		return isset($this->_container[$this->_current]);
300
	}
301
302 19
	public function count()
303
	{
304 19
		return count($this->_container);
305
	}
306
}
307