Complex classes like Kohana_Jam_Association_Belongsto 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_Association_Belongsto, and based on these observations, apply Extract Interface, too.
1 | <?php defined('SYSPATH') OR die('No direct script access.'); |
||
11 | abstract class Kohana_Jam_Association_Belongsto extends Jam_Association { |
||
12 | |||
13 | /** |
||
14 | * Indicates whether this is a polymorphic association. Will add the polymorphic field, |
||
15 | * named <name>_model, if you set this as a string you can change the name of the field to it. |
||
16 | * @var boolean|string |
||
17 | */ |
||
18 | public $polymorphic = FALSE; |
||
19 | |||
20 | /** |
||
21 | * This will be set to the polymorphic model column automatically if nothing is set there |
||
22 | * @var model |
||
23 | */ |
||
24 | public $polymorphic_default_model = NULL; |
||
25 | |||
26 | /** |
||
27 | * The name of the actual field holding the id of the associated model. Defaults to |
||
28 | * <name>_id |
||
29 | * @var string |
||
30 | */ |
||
31 | public $foreign_key = NULL; |
||
32 | |||
33 | public $inverse_of = NULL; |
||
34 | |||
35 | public $count_cache = NULL; |
||
36 | |||
37 | public $field_options = array(); |
||
38 | |||
39 | protected $_default_field_options = array( |
||
40 | 'default' => NULL, |
||
41 | 'allow_null' => TRUE, |
||
42 | 'convert_empty' => TRUE, |
||
43 | ); |
||
44 | |||
45 | /** |
||
46 | * Automatically sets foreign to sensible defaults. |
||
47 | * |
||
48 | * @param string $model |
||
|
|||
49 | * @param string $name |
||
50 | * @return void |
||
51 | */ |
||
52 | 38 | public function initialize(Jam_Meta $meta, $name) |
|
94 | |||
95 | /** |
||
96 | * Load associated model (from database or after deserialization) |
||
97 | * @param Jam_Validated $model |
||
98 | * @param mixed $value |
||
99 | * @return Jam_Model |
||
100 | */ |
||
101 | 9 | public function load_fields(Jam_Validated $model, $value) |
|
102 | { |
||
103 | 9 | if (is_array($value)) |
|
104 | 9 | { |
|
105 | 9 | $value = Jam::build($this->foreign_model)->load_fields($value); |
|
106 | 9 | } |
|
107 | |||
108 | 9 | return $value; |
|
109 | } |
||
110 | |||
111 | /** |
||
112 | * Return a Jam_Query_Builder_Join object to allow a query to join with this association |
||
113 | * You can join polymorphic association only when you pass an alias, wich will be used as the |
||
114 | * name of the model to match to the polymorphic_key |
||
115 | * |
||
116 | * @param string $alias table name alias |
||
117 | * @param string $type join type (LEFT, NATURAL) |
||
118 | * @return Jam_Query_Builder_Join |
||
119 | */ |
||
120 | 18 | public function join($alias, $type = NULL) |
|
121 | { |
||
122 | 18 | if ($this->is_polymorphic()) |
|
123 | 18 | { |
|
124 | 2 | $foreign_model = $alias; |
|
125 | |||
126 | 2 | if ( ! $foreign_model) |
|
127 | 2 | throw new Kohana_Exception('Jam does not join automatically polymorphic belongsto associations!'); |
|
128 | |||
129 | 2 | $join = new Jam_Query_Builder_Join($foreign_model, $type); |
|
130 | 2 | $join->on(DB::expr(':model', array(':model' => $foreign_model)), '=', $this->polymorphic); |
|
131 | 2 | } |
|
132 | else |
||
133 | { |
||
134 | 16 | $join = new Jam_Query_Builder_Join($alias ? array($this->foreign_model, $alias) : $this->foreign_model, $type); |
|
135 | } |
||
136 | |||
137 | return $join |
||
138 | 18 | ->context_model($this->model) |
|
139 | 18 | ->on(':primary_key', '=', $this->foreign_key); |
|
140 | } |
||
141 | |||
142 | /** |
||
143 | * Get the belonging model for this association using the foreign key, |
||
144 | * if the data was changed, use the key from the changed data. |
||
145 | * Assign inverse_of |
||
146 | * |
||
147 | * @param Jam_Validated $model |
||
148 | * @param mixed $value changed data |
||
149 | * @param boolean $is_changed |
||
150 | * @return Jam_Model |
||
151 | */ |
||
152 | 22 | public function get(Jam_Validated $model, $value, $is_changed) |
|
153 | { |
||
154 | if ($is_changed) |
||
155 | 22 | { |
|
156 | 17 | if ($value instanceof Jam_Validated OR ! $value) |
|
157 | 17 | return $value; |
|
158 | |||
159 | 8 | $key = Jam_Association::primary_key($this->foreign_model($model), $value); |
|
160 | 8 | } |
|
161 | else |
||
162 | { |
||
163 | 6 | $key = $model->{$this->foreign_key}; |
|
164 | } |
||
165 | |||
166 | if ($key) |
||
167 | 13 | { |
|
168 | 12 | $item = $this->_find_item($this->foreign_model($model), $key); |
|
169 | 12 | } |
|
170 | 2 | elseif (is_array($value)) |
|
171 | { |
||
172 | 1 | $item = Jam::build($this->foreign_model($model), $value); |
|
173 | 1 | } |
|
174 | else |
||
175 | { |
||
176 | 1 | $item = NULL; |
|
177 | } |
||
178 | |||
179 | |||
180 | if ($item) |
||
181 | 13 | { |
|
182 | 12 | if (is_array($value) AND Jam_Association::is_changed($value)) |
|
183 | 12 | { |
|
184 | 4 | $item->set($value); |
|
185 | 4 | } |
|
186 | |||
187 | 12 | if ($item instanceof Jam_Model AND $this->inverse_of AND $item->meta()->association($this->inverse_of) instanceof Jam_Association_Hasone) |
|
188 | 12 | { |
|
189 | 1 | $item->retrieved($this->inverse_of, $model); |
|
190 | 1 | } |
|
191 | 12 | } |
|
192 | |||
193 | 13 | return $item; |
|
194 | } |
||
195 | |||
196 | /** |
||
197 | * Set releated model, by assigning foreign key for this model |
||
198 | * @param Jam_Validated $model |
||
199 | * @param mixed $value |
||
200 | * @param boolean $is_changed |
||
201 | */ |
||
202 | 25 | public function set(Jam_Validated $model, $value, $is_changed) |
|
203 | { |
||
204 | 25 | if ($this->polymorphic_default_model AND ! $model->{$this->polymorphic}) |
|
205 | 25 | { |
|
206 | 2 | $model->{$this->polymorphic} = $this->polymorphic_default_model; |
|
207 | 2 | } |
|
208 | |||
209 | 25 | if (is_array($value) AND $this->is_polymorphic()) |
|
210 | 25 | { |
|
211 | 3 | $model->{$this->polymorphic} = key($value); |
|
212 | 3 | $value = current($value); |
|
213 | 3 | } |
|
214 | 22 | elseif ($value instanceof Jam_Model) |
|
215 | { |
||
216 | 16 | $model->{$this->polymorphic} = $value->meta()->model(); |
|
217 | 16 | } |
|
218 | |||
219 | 25 | $key = Jam_Association::primary_key($this->foreign_model($model), $value); |
|
220 | |||
221 | 25 | if (is_numeric($key) OR $key === NULL) |
|
222 | 25 | { |
|
223 | 24 | $model->{$this->foreign_key} = $key; |
|
224 | 24 | } |
|
225 | |||
226 | 25 | if ($value instanceof Jam_Model AND $this->inverse_of AND $value->meta()->association($this->inverse_of) instanceof Jam_Association_Hasone) |
|
227 | 25 | { |
|
228 | 1 | $value->retrieved($this->inverse_of, $model); |
|
229 | 1 | } |
|
230 | |||
231 | 25 | return $value; |
|
232 | } |
||
233 | |||
234 | 2 | public function build(Jam_Validated $model, array $attributes = NULL) |
|
250 | |||
251 | /** |
||
252 | * Perform validation on the belonging model, if it was changed. |
||
253 | * @param Jam_Model $model |
||
254 | * @param Jam_Event_Data $data |
||
255 | * @param array $changed |
||
256 | */ |
||
257 | 19 | public function model_after_check(Jam_Model $model, Jam_Event_Data $data, $changed) |
|
258 | { |
||
259 | 19 | if ($value = Arr::get($changed, $this->name) AND Jam_Association::is_changed($value)) |
|
260 | 19 | { |
|
261 | 5 | if ( ! $model->{$this->name}->is_validating() AND ! $model->{$this->name}->check()) |
|
262 | 5 | { |
|
263 | $model->errors()->add($this->name, 'association', array(':errors' => $model->{$this->name}->errors())); |
||
264 | } |
||
265 | 5 | } |
|
266 | 19 | } |
|
267 | |||
268 | /** |
||
269 | * Save the related model before the main model, because we'll need the id to assign to the foreign key |
||
270 | * Only save related model if it has been changed, and is not in a process of saving itself |
||
271 | * @param Jam_Model $model |
||
272 | * @param Jam_Event_Data $data |
||
273 | * @param boolean $changed |
||
274 | */ |
||
275 | 14 | public function model_before_save(Jam_Model $model, Jam_Event_Data $data, $changed) |
|
293 | |||
294 | |||
295 | /** |
||
296 | * If we're using count_cache, increment the count_cache field on the foreign model |
||
297 | * @param Jam_Model $model |
||
298 | */ |
||
299 | 8 | public function model_after_create(Jam_Model $model) |
|
306 | |||
307 | /** |
||
308 | * Delete related model if it has been assigned as dependent |
||
309 | * If dependent is Jam_Association::DELETE - execute the delete method (and all events) |
||
310 | * IF dependent is Jam_Association::ERASE - simply remove from database without executing any events (faster) |
||
311 | * @param Jam_Model $model |
||
312 | */ |
||
313 | 8 | public function model_before_delete(Jam_Model $model) |
|
324 | |||
325 | /** |
||
326 | * If we're using count_cache, decrement the count_cache field on the foreign model |
||
327 | * @param Jam_Model $model |
||
328 | */ |
||
329 | 8 | public function model_after_delete(Jam_Model $model) |
|
336 | |||
337 | /** |
||
338 | * Check if association is polymophic |
||
339 | * @return boolean |
||
340 | */ |
||
341 | 68 | public function is_polymorphic() |
|
345 | |||
346 | /** |
||
347 | * Get the foreign model, if its a polymorphic, use the polymorphic field (e.g. item_model is the polymorphic field, then it's contents will be used) |
||
348 | * @param Jam_Model $model |
||
349 | * @return string |
||
350 | */ |
||
351 | 37 | public function foreign_model(Jam_Model $model) |
|
355 | |||
356 | /** |
||
357 | * Get an item based on a unique key from the database |
||
358 | * @param string $foreign_model |
||
359 | * @param string $key |
||
360 | * @return Jam_Model |
||
361 | */ |
||
362 | 3 | protected function _find_item($foreign_model, $key) |
|
369 | |||
370 | /** |
||
371 | * Delete an item with a specific key from the database |
||
372 | * @param string $foreign_model |
||
373 | * @param string $key |
||
374 | * @return Database_Result |
||
375 | */ |
||
376 | protected function _delete_item($foreign_model, $key) |
||
383 | |||
384 | } |
||
385 |
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 methodfinale(...)
.The most likely cause is that the parameter was removed, but the annotation was not.