Kohana_Jam_Behavior_Cascade::collect_models()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 20
ccs 8
cts 8
cp 1
rs 9.6
c 0
b 0
f 0
cc 4
nc 3
nop 2
crap 4
1
<?php defined('SYSPATH') OR die('No direct access allowed.');
2
/**
3
 *  Nested behavior for Jam ORM library
4
 *  Creates a nested set for this model, where an object can have a parent object of the same model. Requires parent_id field in the database. Reference @ref behaviors
5
 *
6
 * @package    Jam
7
 * @category   Behavior
8
 * @author     Ivan Kerin
9
 * @copyright  (c) 2011-2012 Despark Ltd.
10
 * @license    http://www.opensource.org/licenses/isc-license.txt
11
 */
12
abstract class Kohana_Jam_Behavior_Cascade extends Jam_Behavior {
13
14
	static public $nesting_depth = 0;
15
16
	protected $_callbacks = array();
17
18
	public function initialize(Jam_Meta $meta, $name)
19
	{
20
		parent::initialize($meta, $name);
21
22
		$meta->events()
23
			->bind('model.before_save', array($this, 'record_depth'))
24
			->bind('model.after_save', array($this, 'rollback_depth'));
25
	}
26
27
	public function callbacks()
28
	{
29
		return $this->_callbacks;
30
	}
31
32 4
	protected static function _get_current_children_of_parent($current, $parent, array $children = array())
33
	{
34 4
		if ($current === $parent)
35 2
			return $children;
36
37 3
		foreach ($children as $association_name => $association_children)
38
		{
39 3
			$name = is_numeric($association_name) ? $association_children : $association_name;
40 3
			$association = Jam::meta($parent)->association($name);
41
42 3
			if ($association AND ! $association->is_polymorphic())
0 ignored issues
show
Bug introduced by
The method is_polymorphic does only exist in Jam_Association, but not in Kohana_Jam_Meta.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
43
			{
44 3
				$child_model = $association->foreign_model;
45 3
				$child_children = is_numeric($association_name) ? array() : $association_children;
46 3
				$result = Jam_Behavior_Cascade::_get_current_children_of_parent($current, $child_model, $child_children);
0 ignored issues
show
Bug introduced by
The method _get_current_children_of_parent() cannot be called from this context as it is declared protected in class Kohana_Jam_Behavior_Cascade.

This check looks for access to methods that are not accessible from the current context.

If you need to make a method accessible to another context you can raise its visibility level in the defining class.

Loading history...
47
48 3
				if ($result !== NULL)
49 3
					return $result;
50
			}
51
		}
52 2
		return NULL;
53
	}
54
55 4
	public static function get_current_children($current, array $children = array())
56
	{
57 4
		foreach ($children as $model => $associations)
58
		{
59 4
			if ($result = Jam_Behavior_Cascade::_get_current_children_of_parent($current, $model, $associations))
0 ignored issues
show
Bug introduced by
The method _get_current_children_of_parent() cannot be called from this context as it is declared protected in class Kohana_Jam_Behavior_Cascade.

This check looks for access to methods that are not accessible from the current context.

If you need to make a method accessible to another context you can raise its visibility level in the defining class.

Loading history...
60 4
				return $result;
61
		}
62 2
		return NULL;
63
	}
64
65 1
	protected static function _models($models)
66
	{
67 1
		if ($models instanceof Jam_Model)
68
		{
69 1
			return array($models);
70
		}
71 1
		if ($models instanceof Jam_Array_Association AND count($models))
72
		{
73 1
			return $models->as_array();
74
		}
75
		return array();
76
	}
77
78 1
	public static function collect_models(Jam_Model $model, array $children = array())
79
	{
80 1
		$collection = array($model);
81
82 1
		foreach ($children as $child_name => $child_children)
83
		{
84 1
			if (is_numeric($child_name))
85
			{
86 1
				$collection = array_merge($collection, Jam_Behavior_Cascade::_models($model->$child_children));
0 ignored issues
show
Bug introduced by
The method _models() cannot be called from this context as it is declared protected in class Kohana_Jam_Behavior_Cascade.

This check looks for access to methods that are not accessible from the current context.

If you need to make a method accessible to another context you can raise its visibility level in the defining class.

Loading history...
87
			}
88
			else
89
			{
90 1
				foreach (Jam_Behavior_Cascade::_models($model->$child_name) as $child_item)
0 ignored issues
show
Bug introduced by
The method _models() cannot be called from this context as it is declared protected in class Kohana_Jam_Behavior_Cascade.

This check looks for access to methods that are not accessible from the current context.

If you need to make a method accessible to another context you can raise its visibility level in the defining class.

Loading history...
91
				{
92 1
					$collection = array_merge($collection, Jam_Behavior_Cascade::collect_models($child_item, (array) $child_children));
93
				}
94
			}
95
		}
96 1
		return $collection;
97
	}
98
99
	/**
100
	 * Record another level of nesting for model saving
101
	 */
102
	public function record_depth()
103
	{
104
		Jam_Behavior_Cascade::$nesting_depth++;
105
	}
106
107
	/**
108
	 * Rollback a level of nesting for model saving, when we reech the top, call the execute method
109
	 * @param  Jam_Model $model
110
	 */
111
	public function rollback_depth(Jam_Model $model)
112
	{
113
		Jam_Behavior_Cascade::$nesting_depth--;
114
115
		if (Jam_Behavior_Cascade::$nesting_depth === 0)
116
		{
117
			$this->execute($model);
118
		}
119
	}
120
121
	public function execute(Jam_Model $model)
122
	{
123
		foreach ($this->callbacks() as $method => $model_names)
124
		{
125
			$children = Jam_Behavior_Cascade::get_current_children($model->meta()->model(), $model_names);
126
			$models = Jam_Behavior_Cascade::collect_models($model, (array) $children);
127
128
			call_user_func($method, $model, $models);
129
		}
130
	}
131
}
132