Completed
Pull Request — master (#77)
by Haralan
11:07 queued 09:09
created

Kohana_Jam_Errors::messages()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 28
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 10.7052

Importance

Changes 0
Metric Value
dl 0
loc 28
ccs 7
cts 18
cp 0.3889
rs 8.439
c 0
b 0
f 0
cc 5
eloc 13
nc 5
nop 1
crap 10.7052
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 1
		{
17
18
		}
19 1
		elseif ($message = Kohana::message('validators', $error))
20
		{
21
22 1
		}
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 1
		{
35 1
			$label = $attribute->label;
36 1
		}
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 201
	public function __construct(Jam_Validated $model, $error_filename)
70
	{
71 201
		$this->_model = $model;
72 201
		$this->_meta = $model->meta();
73 201
		$this->_error_filename = $error_filename;
74 201
	}
75
76 179
	public function as_array()
77
	{
78 179
		return $this->_container;
79
	}
80
81 106
	public function add($attribute, $error, array $params = array())
82
	{
83 106
		if ( ! isset($this->_container[$attribute]))
84 106
		{
85 106
			$this->_container[$attribute] = array();
86 106
		}
87
88 106
		$this->_container[$attribute][$error] = $params;
89
90 106
		return $this;
91
	}
92
93 3
	public function messages($attribute = NULL)
94
	{
95 3
		$messages = array();
96
97 3
		if ($attribute !== NULL)
98 3
		{
99 3
			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_key' => $this->_model->name(),
106
						':attribute' => Jam_Errors::attribute_label($this->_meta, $attribute_name),
107
					)));
108
				}
109 3
			}
110
111 3
			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 1
			{
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
						':attribute' => Jam_Errors::attribute_label($model->meta(), $attribute_name),
155 1
					)));
156 1
				}
157
			}
158 1
		}
159
160 1
		return $messages;
161
	}
162
163
	public function messages_dump()
164
	{
165
		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...
166
	}
167
168
	private function _model_messages_dump(Jam_Model $model)
169
	{
170
		$messages = array();
171
		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...
172
		{
173
			if ($model->meta()->association($attribute_name) instanceof Jam_Association_Collection)
174
			{
175
				foreach ($model->$attribute_name as $i => $item)
176
				{
177
					if ( ! $item->is_valid())
178
					{
179
						$messages[] = UTF8::ucfirst(Inflector::humanize($attribute_name)).' ('.$i.'): '.join(', ', $this->_model_messages_dump($item));
180
					}
181
				}
182
			}
183
			elseif ($model->meta()->association($attribute_name) AND $model->$attribute_name)
184
			{
185
				$messages[] = UTF8::ucfirst(Inflector::humanize($attribute_name)).': '.join(', ', $this->_model_messages_dump($model->$attribute_name));
186
			}
187
			else
188
			{
189
				foreach ($errors as $error => $params)
190
				{
191
					$messages[] = Jam_Errors::message($model->meta()->errors_filename(), $attribute_name, $error, Arr::merge($params, array(
192
						':model' => $model->meta()->model(),
193
						':attribute' => Jam_Errors::attribute_label($model->meta(), $attribute_name),
194
					)));
195
				}
196
			}
197
		}
198
199
		return $messages;
200
	}
201
202
	public function __toString()
203
	{
204
		return $this->render();
205
	}
206
207
	public function render()
208
	{
209
		$all_messages = array();
210
		foreach ($this->messages() as $field => $messages)
211
		{
212
			$all_messages[] = join(', ', $messages);
213
		}
214
215
		return join(', ', $all_messages);
216
	}
217
218
	public function first()
219
	{
220
		$messages = $this->current();
221
222
		if (is_array($messages))
223
			return reset($messages);
224
225
		return NULL;
226
	}
227
228
	public function seek($offset)
229
	{
230
		if ($this->offsetExists($offset))
231
		{
232
			$this->_current = $offset;
233
234
			return TRUE;
235
		}
236
		else
237
		{
238
			return FALSE;
239
		}
240
	}
241
242
	public function offsetSet($offset, $value)
243
	{
244
		throw new Kohana_Exception('Cannot set the errors directly, must use add() method');
245
	}
246
247
	public function offsetExists($offset)
248
	{
249
	 return isset($this->_container[$offset]);
250
	}
251
252
	public function offsetUnset($offset)
253
	{
254
		unset($this->_container[$offset]);
255
		if ($this->_current == $offset)
256
		{
257
			$this->rewind();
258
		}
259
	}
260
261 1
	public function offsetGet($offset)
262
	{
263 1
		return isset($this->_container[$offset]) ? $this->_container[$offset] : NULL;
264
	}
265
266 1
	public function rewind()
267
	{
268 1
		reset($this->_container);
269 1
		$this->_current = key($this->_container);
270 1
	}
271
272 1
	public function current()
273
	{
274 1
		return $this->offsetGet($this->_current);
275
	}
276
277 1
	public function key()
278
	{
279 1
		return $this->_current;
280
	}
281
282 1
	public function next()
283
	{
284 1
		next($this->_container);
285 1
		$this->_current = key($this->_container);
286 1
		return $this->current();
287
	}
288
289
	public function prev()
290
	{
291
		prev($this->_container);
292
		$this->_current = key($this->_container);
293
		return $this->current();
294
	}
295
296 1
	public function valid()
297
	{
298 1
		return isset($this->_container[$this->_current]);
299
	}
300
301 21
	public function count()
302
	{
303 21
		return count($this->_container);
304
	}
305
}
306