Completed
Push — master ( 0c6e4d...a1420e )
by Tomáš
02:54
created

ContainerQuery   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 178
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 29
eloc 62
c 1
b 0
f 0
dl 0
loc 178
ccs 61
cts 61
cp 1
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A addSorter() 0 3 1
A unique() 0 3 1
B sortByPropertyCallback() 0 23 11
A desc() 0 3 1
A sortBy() 0 3 1
B get() 0 48 11
A sort() 0 3 1
A filter() 0 3 1
1
<?php
2
3
4
namespace TournamentGenerator\Containers;
5
6
use Closure;
7
use TournamentGenerator\Base;
8
use TournamentGenerator\Helpers\Sorter\BaseSorter;
9
10
/**
11
 * Class ContainerQuery
12
 *
13
 * Container query is a helper class to filter, sort, etc. the values of the container hierarchy.
14
 *
15
 * @package TournamentGenerator\Containers
16
 * @author  Tomáš Vojík <[email protected]>
17
 */
18
class ContainerQuery
19
{
20
21
	/** @var BaseContainer Queried container */
22
	protected BaseContainer $container;
23
	/** @var Closure[] Filter closures */
24
	protected array      $filters      = [];
25
	protected Closure    $sortClosure;
26
	protected string     $sortProperty;
27
	protected bool       $desc         = false;
28
	protected BaseSorter $sorter;
29
	protected bool       $topLevelOnly = false;
30
	protected bool       $uniqueOnly   = false;
31
32
	/**
33
	 * ContainerQuery constructor.
34
	 *
35
	 * @param BaseContainer $container Queried container
36
	 */
37 106
	public function __construct(BaseContainer $container, bool $topLevelOnly = false) {
38 106
		$this->container = $container;
39 106
		$this->topLevelOnly = $topLevelOnly;
40 106
	}
41
42
	/**
43
	 * Get the result
44
	 *
45
	 * @return array
46
	 */
47 106
	public function get() : array {
48
		// Get initial data
49 106
		if ($this->topLevelOnly) {
50 1
			$data = $this->container->getTopLevel();
51
		}
52
		else {
53 106
			$data = $this->container->get();
54
		}
55
56
		// Unique
57 106
		if ($this->uniqueOnly) {
58 105
			if (reset($data) instanceof Base) {
59 103
				$ids = [];
60 103
				foreach ($data as $key => $obj) {
61 103
					if (in_array($obj->getId(), $ids, true)) {
62 17
						unset($data[$key]);
63 17
						continue;
64
					}
65 103
					$ids[] = $obj->getId();
66
				}
67
			}
68
			else {
69 7
				$data = array_unique($data);
70
			}
71
		}
72
73
		// Filters
74 106
		foreach ($this->filters as $filter) {
75 1
			$data = array_filter($data, $filter);
76
		}
77
78
		// Sorting
79 106
		if (isset($this->sorter)) {
80 48
			$data = $this->sorter->sort($data);
81
		}
82 104
		elseif (isset($this->sortClosure)) {
83 1
			uasort($data, $this->sortClosure);
84
		}
85 104
		elseif (isset($this->sortProperty)) {
86 1
			uasort($data, [$this, 'sortByPropertyCallback']);
87
		}
88
89
		// Order reverse
90 106
		if ($this->desc) {
91 2
			$data = array_reverse($data, true);
92
		}
93
94 106
		return $data;
95
	}
96
97
	/**
98
	 * Add a filter callback
99
	 *
100
	 * @param Closure $callback
101
	 *
102
	 * @return $this
103
	 */
104 1
	public function filter(Closure $callback) : ContainerQuery {
105 1
		$this->filters[] = $callback;
106 1
		return $this;
107
	}
108
109
	/**
110
	 * Sort in descending order
111
	 *
112
	 * @return $this
113
	 */
114 2
	public function desc() : ContainerQuery {
115 2
		$this->desc = true;
116 2
		return $this;
117
	}
118
119
	/**
120
	 * Sort a result using a callback - maintaining the index association
121
	 *
122
	 * @param Closure $callback
123
	 *
124
	 * @return $this
125
	 */
126 1
	public function sort(Closure $callback) : ContainerQuery {
127 1
		$this->sortClosure = $callback;
128 1
		return $this;
129
	}
130
131
	/**
132
	 * Sort a result set by a given property
133
	 *
134
	 * @warning Sort callback has a priority.
135
	 *
136
	 * @param string $property
137
	 *
138
	 * @return $this
139
	 */
140 1
	public function sortBy(string $property) : ContainerQuery {
141 1
		$this->sortProperty = $property;
142 1
		return $this;
143
	}
144
145
	/**
146
	 * @param BaseSorter $sorter
147
	 *
148
	 * @return $this
149
	 */
150 48
	public function addSorter(BaseSorter $sorter) : ContainerQuery {
151 48
		$this->sorter = $sorter;
152 48
		return $this;
153
	}
154
155
	/**
156
	 * Get only unique values
157
	 *
158
	 * @return $this
159
	 */
160 105
	public function unique() : ContainerQuery {
161 105
		$this->uniqueOnly = true;
162 105
		return $this;
163
	}
164
165
	/**
166
	 * Sort function for sorting by a defined property
167
	 *
168
	 * @param array|object $value1
169
	 * @param array|object $value2
170
	 *
171
	 * @return int
172
	 */
173 1
	protected function sortByPropertyCallback($value1, $value2) : int {
174
		// Get values
175 1
		$property = $this->sortProperty ?? '';
176 1
		$property1 = null;
177 1
		$property2 = null;
178 1
		if (is_object($value1) && isset($value1->$property)) {
179 1
			$property1 = $value1->$property;
180
		}
181 1
		elseif (is_array($value1) && isset($value1[$property])) {
182 1
			$property1 = $value1[$property];
183
		}
184 1
		if (is_object($value2) && isset($value2->$property)) {
185 1
			$property2 = $value2->$property;
186
		}
187 1
		elseif (is_array($value2) && isset($value2[$property])) {
188 1
			$property2 = $value2[$property];
189
		}
190
191
		// Compare values
192 1
		if ($property1 === $property2) {
193 1
			return 0;
194
		}
195 1
		return $property1 < $property2 ? -1 : 1;
196
	}
197
198
}