Completed
Push — master ( 363bc6...2f4e75 )
by Peter
06:19
created

CompositionIterator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

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
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: peter
5
 * Date: 07.03.18
6
 * Time: 17:46
7
 */
8
9
namespace Maslosoft\Mangan\Helpers;
10
11
12
use Countable;
13
use Iterator;
14
use Maslosoft\Addendum\Interfaces\AnnotatedInterface;
15
use Maslosoft\Addendum\Utilities\ClassChecker;
16
use Maslosoft\Mangan\Mangan;
17
use Maslosoft\Mangan\Meta\ManganMeta;
18
19
/**
20
 * Iterate over composition of documents.
21
 *
22
 * NOTE: This will include only AnnotatedInterface instances.
23
 *
24
 * @package Maslosoft\Mangan\Helpers
25
 */
26
class CompositionIterator implements Iterator, Countable
27
{
28
	private $model = null;
29
30
	private $direct = false;
31
32
	private $types = [];
33
34
	/**
35
	 * Models holder
36
	 * @var null|AnnotatedInterface[]
37
	 */
38
	private $models = null;
39
40
	private $pointer = 0;
41
42 16
	public function __construct(AnnotatedInterface $model)
43
	{
44 16
		$this->model = $model;
45 16
	}
46
47
	/**
48
	 * Limit results to only direct descendants.
49
	 * @return $this
50
	 */
51 3
	public function direct()
52
	{
53 3
		$this->direct = true;
54 3
		return $this;
55
	}
56
57
	/**
58
	 * Limit results to only to the type provided.
59
	 *
60
	 * The `$type` should be class or interface name
61
	 * or object instance.
62
	 *
63
	 * Repeated calls will add types uniquely.
64
	 *
65
	 * @param $type string|object
66
	 * @param $include boolean Whether to include this type or skip
67
	 * @return $this
68
	 */
69 14
	public function ofType($type, $include = true)
70
	{
71 14
		if (is_object($type))
72
		{
73
			$type = get_class($type);
74
		}
75 14
		assert(is_string($type));
76 14
		assert(ClassChecker::exists($type));
77 14
		$this->types[$type] = $include;
78 14
		return $this;
79
	}
80
81 16
	private function init()
82
	{
83 16
		if (null === $this->models)
84
		{
85 16
			$this->models = [];
86 16
			$this->iterate($this->model);
87
		}
88 16
	}
89
90 16
	private function iterate($model)
91
	{
92 16
		foreach (ManganMeta::create($model)->fields() as $name => $meta)
93
		{
94 16
			if (is_array($model->$name))
95
			{
96 9
				foreach ($model->$name as $child)
97
				{
98 9
					if ($this->skip($child))
99
					{
100 2
						continue;
101
					}
102 7
					if ($this->doInclude($child))
103
					{
104 6
						$this->models[] = $child;
105
					}
106 7
					if($this->recurse())
107
					{
108 7
						$this->iterate($child);
109
					}
110
				}
111 9
				continue;
112
			}
113 16
			if ($this->skip($model->$name))
114
			{
115 16
				continue;
116
			}
117 4
			if ($this->doInclude($model->$name))
118
			{
119 4
				$this->models[] = $model->$name;
120
			}
121 4
			if($this->recurse())
122
			{
123 4
				$this->iterate($model->$name);
124
			}
125
		}
126 16
	}
127
128 16
	private function skip($model)
129
	{
130
		// Non-object
131 16
		if (!is_object($model))
132
		{
133 16
			return true;
134
		}
135
		// Skip if not annotated
136 13
		if (!$model instanceof AnnotatedInterface)
137
		{
138 6
			return true;
139
		}
140 7
		return false;
141
	}
142
143
	/**
144
	 * Whether to include `$model` in result
145
	 * @param $model
146
	 * @return bool
147
	 */
148 7
	private function doInclude($model)
149
	{
150
		// Don't skip if no types
151 7
		if (empty($this->types))
152
		{
153 4
			return true;
154
		}
155
156
		// Include if is_a type
157 5
		foreach ($this->types as $type => $include)
158
		{
159 5
			if (is_a($model, $type))
160
			{
161 5
				return $include;
162
			}
163
		}
164 2
		return false;
165
	}
166
167 7
	private function recurse()
168
	{
169 7
		return !$this->direct;
170
	}
171
172 6
	public function current()
173
	{
174 6
		$this->init();
175 6
		return $this->models[$this->pointer];
176
	}
177
178 6
	public function next()
179
	{
180 6
		$this->init();
181 6
		++$this->pointer;
182 6
	}
183
184
	public function key()
185
	{
186
		$this->init();
187
		return $this->pointer;
188
	}
189
190 16
	public function valid()
191
	{
192 16
		$this->init();
193 16
		return isset($this->models[$this->pointer]);
194
	}
195
196 16
	public function rewind()
197
	{
198 16
		$this->init();
199 16
		$this->pointer = 0;
200 16
	}
201
202 5
	public function count()
203
	{
204 5
		$this->init();
205 5
		return count($this->models);
206
	}
207
208
209
}