Complex classes like Kohana_Jam_Array_Model often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Kohana_Jam_Array_Model, and based on these observations, apply Extract Interface, too.
1 | <?php defined('SYSPATH') OR die('No direct script access.'); |
||
12 | abstract class Kohana_Jam_Array_Model extends Jam_Array { |
||
13 | |||
14 | public static function factory() |
||
15 | { |
||
16 | return new Jam_Array_Model(); |
||
17 | } |
||
18 | |||
19 | /** |
||
20 | * Convert a collection to an array, keep an array or make a Jam_Model to an array(Jam_Model) |
||
21 | * @param mixed $collection |
||
22 | * @return array |
||
23 | */ |
||
24 | 21 | public static function convert_collection_to_array($collection) |
|
25 | { |
||
26 | 21 | if ($collection instanceof Jam_Query_Builder_Collection OR $collection instanceof Jam_Array_Model) |
|
27 | 21 | { |
|
28 | 6 | $array = $collection->as_array(); |
|
29 | 6 | } |
|
30 | 20 | elseif ( ! is_array($collection)) |
|
31 | { |
||
32 | 13 | $array = array($collection); |
|
33 | 13 | } |
|
34 | else |
||
35 | { |
||
36 | 10 | $array = $collection; |
|
37 | } |
||
38 | 21 | return array_values(array_filter($array)); |
|
39 | } |
||
40 | |||
41 | /** |
||
42 | * A collection used to load the content |
||
43 | * @var Jam_Query_Builder_Collection |
||
44 | */ |
||
45 | protected $_collection; |
||
46 | |||
47 | /** |
||
48 | * The name of the models in this iterator |
||
49 | * @var string |
||
50 | */ |
||
51 | protected $_model; |
||
52 | |||
53 | /** |
||
54 | * The original content, loaded from the database |
||
55 | * @var array |
||
56 | */ |
||
57 | protected $_original; |
||
58 | |||
59 | /** |
||
60 | * This is set if the whole collection has been replaced. |
||
61 | * @var boolean |
||
62 | */ |
||
63 | protected $_replace = FALSE; |
||
64 | |||
65 | /** |
||
66 | * Getter / Setter of the model name |
||
67 | * @param string $model |
||
68 | * @return string |
||
69 | */ |
||
70 | 637 | public function model($model = NULL) |
|
71 | { |
||
72 | 637 | if ($model !== NULL) |
|
73 | 637 | { |
|
74 | 637 | $this->_model = $model; |
|
75 | 637 | return $this; |
|
76 | } |
||
77 | 25 | return $this->_model; |
|
78 | } |
||
79 | |||
80 | /** |
||
81 | * Getter of the meta object for this iterator (based on $_model) |
||
82 | * @return Jam_Model |
||
83 | * @throws Kohana_Exception If $_model not present |
||
84 | */ |
||
85 | 19 | public function meta() |
|
86 | { |
||
87 | 19 | if ( ! $this->model()) |
|
88 | 19 | throw new Kohana_Exception('Model not set'); |
|
89 | |||
90 | 19 | return Jam::meta($this->model()); |
|
|
|||
91 | } |
||
92 | |||
93 | /** |
||
94 | * Getter / Setter of the collection, used to lazy load the data for this iterator |
||
95 | * @param Jam_Query_Builder_Collection $collection |
||
96 | * @return Jam_Query_Builder_Collection |
||
97 | */ |
||
98 | 29 | public function collection(Jam_Query_Builder_Collection $collection = NULL) |
|
99 | { |
||
100 | 18 | if ($collection !== NULL) |
|
101 | 18 | { |
|
102 | 18 | $this->_collection = $collection; |
|
103 | 18 | return $this; |
|
104 | } |
||
105 | |||
106 | 29 | return $this->_collection; |
|
107 | } |
||
108 | |||
109 | /** |
||
110 | * Load the content from the database, using $_collection. |
||
111 | * If some items have been added to the iterator before it has been loaded, merge the results |
||
112 | * @throws Kohana_Exception If the $_collection has not been loaded |
||
113 | */ |
||
114 | 28 | protected function _load_content() |
|
115 | { |
||
116 | 28 | if ($this->_original === NULL) |
|
117 | 28 | { |
|
118 | 28 | if ( ! $this->collection()) |
|
119 | 28 | throw new Kohana_Exception('Cannot load content because collection not loaded for Jam_Array(:model)', array(':model' => $this->model())); |
|
120 | |||
121 | 28 | $collection = clone $this->collection(); |
|
122 | |||
123 | 28 | $this->_original = $collection->result()->as_array(); |
|
124 | |||
125 | 28 | if ( ! $this->_replace) |
|
126 | 28 | { |
|
127 | 23 | if ($this->_content !== NULL) |
|
128 | 23 | { |
|
129 | 1 | $this->_content = array_merge($this->_content, $this->_original); |
|
130 | 1 | } |
|
131 | else |
||
132 | { |
||
133 | 22 | $this->_content = $this->_original; |
|
134 | } |
||
135 | 23 | } |
|
136 | 28 | } |
|
137 | 28 | } |
|
138 | |||
139 | public function reload() |
||
140 | { |
||
141 | $this->_original = NULL; |
||
142 | $this->_replace = FALSE; |
||
143 | return parent::reload(); |
||
144 | } |
||
145 | |||
146 | /** |
||
147 | * Load an item from the database, based on a unique key |
||
148 | * @param string $key |
||
149 | * @return Jam_Model |
||
150 | */ |
||
151 | 1 | protected function _find_item($key) |
|
155 | |||
156 | /** |
||
157 | * Convert an item from the $_content to a Jam_Model |
||
158 | * @param mixed $value |
||
159 | * @param boolean $is_changed |
||
160 | * @param int $offset |
||
161 | * @return Jam_Model |
||
162 | */ |
||
163 | 20 | protected function _load_item($value, $is_changed, $offset) |
|
207 | |||
208 | /** |
||
209 | * Find out the primary_key of an item of the $_content |
||
210 | * @param mixed $value |
||
211 | * @return int |
||
212 | */ |
||
213 | 22 | protected function _id($value) |
|
227 | |||
228 | 16 | public function search($item) |
|
229 | { |
||
230 | 16 | $search_id = $this->_id($item); |
|
231 | |||
232 | 16 | if ( ! $search_id) |
|
233 | 16 | return NULL; |
|
234 | |||
235 | 11 | $this->_load_content(); |
|
236 | |||
237 | 11 | if ($this->_content) |
|
238 | 11 | { |
|
239 | 11 | foreach ($this->_content as $offset => $current) |
|
240 | { |
||
241 | 11 | if ($this->_id($current) === $search_id) |
|
242 | 11 | { |
|
243 | 9 | return (int) $offset; |
|
244 | } |
||
245 | 8 | } |
|
246 | 4 | } |
|
247 | |||
248 | 5 | return NULL; |
|
249 | } |
||
250 | |||
251 | 12 | public function as_array($key = NULL, $value = NULL) |
|
252 | { |
||
253 | 12 | $results = array(); |
|
254 | 12 | $key = Jam_Query_Builder::resolve_meta_attribute($key, $this->meta()); |
|
255 | 12 | $value = Jam_Query_Builder::resolve_meta_attribute($value, $this->meta()); |
|
256 | |||
257 | 12 | foreach ($this as $i => $item) |
|
258 | { |
||
259 | 9 | $results[$key ? $item->$key : $i] = $value ? $item->$value : $item; |
|
260 | 12 | } |
|
261 | |||
262 | 12 | return $results; |
|
263 | } |
||
264 | |||
265 | 7 | public function ids() |
|
266 | { |
||
267 | 7 | $this->_load_content(); |
|
268 | |||
269 | 7 | return $this->_content ? array_filter(array_map(array($this, '_id'), $this->_content)) : array(); |
|
270 | } |
||
271 | |||
272 | 7 | public function load_fields(array $data) |
|
273 | { |
||
274 | 7 | $this->_content = $this->_original = $data; |
|
275 | 7 | return $this; |
|
276 | } |
||
277 | |||
278 | public function original() |
||
279 | { |
||
280 | return $this->_original; |
||
281 | } |
||
282 | |||
283 | 2 | public function original_ids() |
|
284 | { |
||
285 | 2 | $this->_load_content(); |
|
286 | |||
287 | 2 | return $this->_original ? array_filter(array_map(array($this, '_id'), $this->_original)) : array(); |
|
288 | } |
||
289 | |||
290 | 4 | public function has($item) |
|
291 | { |
||
292 | 4 | return $this->search($item) !== NULL; |
|
293 | } |
||
294 | |||
295 | 9 | public function set($items) |
|
296 | { |
||
297 | 9 | $this->_content = Jam_Array_Model::convert_collection_to_array($items); |
|
298 | 9 | $this->_changed = count($this->_content) ? array_fill(0, count($this->_content), TRUE) : array(); |
|
299 | 9 | $this->_replace = TRUE; |
|
300 | 9 | $this->_removed = TRUE; |
|
301 | |||
302 | 9 | return $this; |
|
303 | } |
||
304 | |||
305 | 8 | public function add($items) |
|
306 | { |
||
307 | 8 | $items = Jam_Array_Model::convert_collection_to_array($items); |
|
308 | |||
309 | 8 | foreach ($items as $item) |
|
310 | { |
||
311 | 8 | $this->offsetSet($this->search($item), $item); |
|
312 | 8 | } |
|
313 | |||
314 | 8 | return $this; |
|
315 | } |
||
316 | |||
317 | 6 | public function remove($items) |
|
318 | { |
||
319 | 6 | $items = Jam_Array_Model::convert_collection_to_array($items); |
|
320 | |||
321 | 6 | foreach ($items as $item) |
|
322 | { |
||
323 | 6 | if (($offset = $this->search($item)) !== NULL) |
|
324 | 6 | { |
|
325 | 5 | $this->offsetUnset($offset); |
|
326 | 5 | } |
|
327 | 6 | } |
|
328 | |||
329 | 6 | return $this; |
|
330 | } |
||
331 | |||
332 | /** |
||
333 | * Build a new Jam Model, add it to the collection and return the newly built model |
||
334 | * @param array $values set values on the new model |
||
335 | * @return Jam_Model |
||
336 | */ |
||
337 | 1 | public function build(array $values = NULL) |
|
348 | |||
349 | /** |
||
350 | * The same as build but saves the model in the database |
||
351 | * @param array $values |
||
352 | * @return Jam_Model |
||
353 | */ |
||
354 | public function create(array $values = NULL) |
||
358 | |||
359 | 2 | public function check_changed() |
|
374 | |||
375 | 2 | public function save_changed() |
|
376 | { |
||
377 | 2 | foreach ($this->_changed as $offset => $is_changed) |
|
378 | { |
||
379 | 2 | $item = $this->offsetGet($offset); |
|
380 | 2 | if ($is_changed AND $item AND ! $item->is_saving()) |
|
381 | 2 | { |
|
382 | 2 | $item->save(); |
|
383 | 2 | } |
|
384 | 2 | } |
|
385 | |||
386 | 2 | return $this; |
|
387 | } |
||
388 | |||
389 | 1 | public function clear() |
|
397 | |||
398 | 1 | public function clear_changed() |
|
405 | |||
406 | 16 | public function __toString() |
|
407 | { |
||
408 | 16 | if ( ! $this->collection()) |
|
409 | 16 | return 'Jam_Array ('.$this->model().')[NOT LOADED COLLECTION]'; |
|
410 | |||
411 | 16 | return $this->collection()->__toString(); |
|
412 | } |
||
413 | |||
414 | 2 | public function __call($method, $args) |
|
415 | { |
||
416 | 2 | if ( ! $this->collection()) |
|
417 | 2 | throw new Kohana_Exception('Cannot call method :method on collection because collection not loaded for Jam_Array(:model)', array(':method' => $method, ':model' => $this->model())); |
|
418 | |||
419 | 2 | return call_user_func_array(array(clone $this->collection(), $method), $args); |
|
420 | } |
||
421 | |||
422 | /** |
||
423 | * Getter for the changed array - check if any or a particular item has been changed |
||
424 | * @param int $offset |
||
425 | * @return bool |
||
426 | */ |
||
427 | 7 | public function changed($offset = NULL) |
|
442 | |||
443 | 637 | public function serialize() |
|
458 | |||
459 | 637 | public function unserialize($data) |
|
471 | } |
||
472 |
This check looks at variables that are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.