Completed
Push — master ( 3239e9...e1b4b8 )
by Georgi
27s queued 16s
created

Kohana_Jam_Association_Hasmany::item_get()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 1
1
<?php defined('SYSPATH') OR die('No direct script access.');
2
3
/**
4
 * Handles has one to relationships
5
 *
6
 * @package    Jam
7
 * @category   Associations
8
 * @author     Ivan Kerin
9
 * @copyright  (c) 2012 Despark Ltd.
10
 * @license    http://www.opensource.org/licenses/isc-license.txt
11
 */
12
abstract class Kohana_Jam_Association_Hasmany extends Jam_Association_Collection {
13
14
	/**
15
	 * Set this for polymorphic associations, this has to be the name of the opposite belongsto relation,
16
	 * so if the oposite relation was item->parent, then this will have to be 'items' => Jam::association('hasmany', array('as' => 'parent')
17
	 * If this option is set then the foreign_key default becomes "{$as}_id", and polymorphic_key to "{$as}_model"
18
	 * @var string
19
	 */
20
	public $as;
21
22
	/**
23
	 * The field in the opposite model that is used to linking to this one.
24
	 * It defaults to "{$foreign_model}_id", but you can custumize it
25
	 * @var string
26
	 */
27
	public $foreign_key = NULL;
28
29
	/**
30
	 * The field in the opposite model that is used by the polymorphic association to determine the model
31
	 * It defaults to "{$as}_model"
32
	 * @var string
33
	 */
34
	public $polymorphic_key = NULL;
35
36
	/**
37
	 * You can set this to the name of the opposite belongsto relation for optimization purposes
38
	 * @var string
39
	 */
40
	public $inverse_of = NULL;
41
42
	/**
43
	 * Optionally delete the item when it is removed from the association
44
	 * @var string
45
	 */
46
	public $delete_on_remove = NULL;
47
48
	/**
49
	 * Initialize foreign_key, as, and polymorphic_key with default values
50
	 *
51
	 * @param   string  $model
0 ignored issues
show
Bug introduced by
There is no parameter named $model. 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...
52
	 * @param   string  $name
53
	 */
54 51
	public function initialize(Jam_Meta $meta, $name)
55
	{
56 51
		parent::initialize($meta, $name);
57
58 51
		if ( ! $this->foreign_key)
59
		{
60 46
			$this->foreign_key = $this->model.'_id';
61
		}
62
63
		// Polymorphic associations
64 51
		if ($this->as)
65
		{
66 14
			$this->foreign_key = $this->as.'_id';
67 14
			if ( ! $this->polymorphic_key)
68
			{
69 14
				$this->polymorphic_key = $this->as.'_model';
70
			}
71
		}
72 51
	}
73
74
	/**
75
	 * Return a Jam_Query_Builder_Join object to allow a query to join with this association
76
	 * @param  string $alias table name alias
77
	 * @param  string $type  join type (LEFT, NATURAL)
78
	 * @return Jam_Query_Builder_Join
79
	 */
80 9
	public function join($alias, $type = NULL)
81
	{
82 9
		$join = Jam_Query_Builder_Join::factory($alias ? array($this->foreign_model, $alias) : $this->foreign_model, $type)
0 ignored issues
show
Bug introduced by
It seems like $alias ? array($this->fo... : $this->foreign_model can also be of type array<integer,string,{"0":"string","1":"string"}>; however, Kohana_Jam_Query_Builder_Join::factory() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
83 9
			->context_model($this->model)
84 9
			->on($this->foreign_key, '=', ':primary_key');
85
86 9
		if ($this->is_polymorphic())
87
		{
88 2
			$join->on($this->polymorphic_key, '=', DB::expr(':model', array(':model' => $this->model)));
89
		}
90
91 9
		return $join;
92
	}
93
94 9
	public function collection(Jam_Model $model)
95
	{
96 9
		$collection = Jam::all($this->foreign_model);
97
98 9
		$collection->where($this->foreign_key, '=', $model->id());
99
100 9
		if ($this->is_polymorphic())
101
		{
102 3
			$collection->where($this->polymorphic_key, '=', $this->model);
103
		}
104
105 9
		return $collection;
106
	}
107
108
	/**
109
	 * Assign inverse associations to elements of arrays
110
	 * @param Jam_Validated $model
111
	 * @param mixed         $value
112
	 * @param boolean       $is_changed
113
	 */
114 1
	public function set(Jam_Validated $model, $value, $is_changed)
115
	{
116 1
		if (($this->inverse_of OR $this->as) AND is_array($value))
117
		{
118 1
			foreach ($value as & $item)
119
			{
120 1
				if ($item instanceof Jam_Model)
121
				{
122 1
					$this->assign_item($item, $model->id(), $this->model, $model);
123
				}
124
			}
125
		}
126
127 1
		return $value;
128
	}
129
130
	/**
131
	 * Before the model is deleted, and the depenedent option is set, remove the dependent models
132
	 * @param  Jam_Model $model
133
	 */
134 6
	public function model_before_delete(Jam_Model $model)
135
	{
136 6
		if (Jam_Association::DELETE === $this->dependent)
137
		{
138 2
			foreach ($model->{$this->name} as $item)
139
			{
140 2
				$item->delete();
141
			}
142
		}
143 6
		elseif (Jam_Association::ERASE === $this->dependent)
144
		{
145
			$query = $this->erase_query($model);
146
			if ($query)
147
			{
148
				$query->execute();
149
			}
150
		}
151 6
		elseif (Jam_Association::NULLIFY === $this->dependent)
152
		{
153
			$query = $this->nullify_query($model);
154
			if ($query)
155
			{
156
				$query->execute();
157
			}
158
		}
159 6
	}
160
161
	/**
162
	 * Remove items from this association (withought deleteing it) and persist the data in the database
163
	 * @param  Jam_Validated                $model
164
	 * @param  Jam_Array_Association $collection
165
	 */
166 1
	public function clear(Jam_Validated $model, Jam_Array_Association $collection)
167
	{
168 1
		foreach ($collection as $item)
169
		{
170 1
			$item->{$this->foreign_key} = NULL;
171
		}
172
173 1
		parent::clear($model, $collection);
174 1
	}
175
176
	/**
177
	 * Generate a query to delete associated models in the database
178
	 * @param  Jam_Model $model
179
	 * @return Database_Query
180
	 */
181 5
	public function erase_query(Jam_Model $model)
182
	{
183 5
		if (NULL === $model->id())
184
		{
185 1
			return NULL;
186
		}
187
188 4
		$query = Jam_Query_Builder_Delete::factory($this->foreign_model)
189 4
			->where($this->foreign_key, '=', $model->id());
190
191 4
		if ($this->is_polymorphic())
192
		{
193 1
			$query->where($this->polymorphic_key, '=', $this->model);
194
		}
195
196 4
		return $query;
197
	}
198
199
	/**
200
	 * Generate a query to remove models from this association (without deleting them)
201
	 * @param  Jam_Model $model
202
	 * @return Database_Query
203
	 */
204 5
	public function nullify_query(Jam_Model $model)
205
	{
206 5
		if (NULL === $model->id())
207
		{
208 1
			return NULL;
209
		}
210
211 4
		$query = Jam_Query_Builder_Update::factory($this->foreign_model)
212 4
			->value($this->foreign_key, NULL)
213 4
			->where($this->foreign_key, '=', $model->id());
214
215 4
		if ($this->is_polymorphic())
216
		{
217
			$query
218 1
				->where($this->polymorphic_key, '=', $this->model)
219 1
				->value($this->polymorphic_key, NULL);
220
		}
221 4
		return $query;
222
	}
223
224
	/**
225
	 * Generate a query to remove models from the association (without deleting them), for specific ids
226
	 * @param  Jam_Model $model
227
	 * @param  array     $ids
228
	 * @return Database_Query
229
	 */
230 7
	public function remove_items_query(Jam_Model $model, array $ids)
231
	{
232 7
		if (TRUE === $this->delete_on_remove OR Jam_Association::DELETE === $this->delete_on_remove)
233
		{
234 2
			foreach (Jam::all($this->foreign_model)->where_key($ids) as $item )
235
			{
236 2
				$item->delete();
237
			}
238 2
			$query = NULL;
239
		}
240 5
		elseif ($this->delete_on_remove === Jam_Association::ERASE)
241
		{
242 1
			$query = Jam_Query_Builder_Delete::factory($this->foreign_model)
243 1
				->where(':primary_key', 'IN', $ids);
244
245 1
			if ($this->is_polymorphic())
246
			{
247 1
				$query->value($this->polymorphic_key, NULL);
0 ignored issues
show
Documentation Bug introduced by
The method value does not exist on object<Jam_Query_Builder_Delete>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
248
			}
249
		}
250
		else
251
		{
252 4
			$query = Jam_Query_Builder_Update::factory($this->foreign_model)
253 4
				->where(':primary_key', 'IN', $ids)
254 4
				->value($this->foreign_key, NULL);
255
256 4
			if ($this->is_polymorphic())
257
			{
258 1
				$query->value($this->polymorphic_key, NULL);
259
			}
260
		}
261
262 7
		return $query;
263
	}
264
265
	/**
266
	 * Generate a query to add models from the association (without deleting them), for specific ids
267
	 * @param  Jam_Model $model
268
	 * @param  array     $ids
269
	 * @return Database_Query
270
	 */
271 4
	public function add_items_query(Jam_Model $model, array $ids)
272
	{
273 4
		$query = Jam_Query_Builder_Update::factory($this->foreign_model)
274 4
			->where(':primary_key', 'IN', $ids)
275 4
			->value($this->foreign_key, $model->id());
276
277 4
		if ($this->is_polymorphic())
278
		{
279 1
			$query->value($this->polymorphic_key, $this->model);
280
		}
281 4
		return $query;
282
	}
283
284
285 7
	protected function assign_item(Jam_Model $item, $foreign_key, $polymorphic_key, $inverse_of)
286
	{
287 7
		$item->{$this->foreign_key} = $foreign_key;
288
289 7
		if ($this->is_polymorphic())
290
		{
291 2
			$item->{$this->polymorphic_key} = $polymorphic_key;
292
		}
293
294 7
		if ($this->inverse_of)
295
		{
296 6
			$item->retrieved($this->inverse_of, $inverse_of);
297
		}
298
299 7
		if ($this->as)
300
		{
301 2
			$item->retrieved($this->as, $inverse_of);
302
		}
303
304 7
	}
305
306
	/**
307
	 * Set the foreign and polymorphic keys on an item when its requested from the associated collection
308
	 *
309
	 * @param  Jam_Model $model
310
	 * @param  Jam_Model $item
311
	 */
312 6
	public function item_get(Jam_Model $model, Jam_Model $item)
313
	{
314 6
		$this->assign_item($item, $model->id(), $this->model, $model);
315 6
	}
316
317
	/**
318
	 * Set the foreign and polymorphic keys on an item when its set to the associated collection
319
	 *
320
	 * @param  Jam_Model $model
321
	 * @param  Jam_Model $item
322
	 */
323 3
	public function item_set(Jam_Model $model, Jam_Model $item)
324
	{
325 3
		$this->assign_item($item, $model->id(), $this->model, $model);
326 3
	}
327
328
	/**
329
	 * Unset the foreign and polymorphic keys on an item when its removed from the associated collection
330
	 *
331
	 * @param  Jam_Model $model
332
	 * @param  Jam_Model $item
333
	 */
334
	public function item_unset(Jam_Model $model, Jam_Model $item)
335
	{
336
		$this->assign_item($item, NULL, NULL, NULL);
337
	}
338
339
	/**
340
	 * See if the association is polymorphic
341
	 * @return boolean
342
	 */
343 46
	public function is_polymorphic()
344
	{
345 46
		return (bool) $this->as;
346
	}
347
} // End Kohana_Jam_Association_HasMany
348