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

ContainerQuery::get()   B

Complexity

Conditions 11
Paths 96

Size

Total Lines 48
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 12.0935

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 25
c 1
b 0
f 0
dl 0
loc 48
ccs 19
cts 24
cp 0.7917
rs 7.3166
cc 11
nc 96
nop 0
crap 12.0935

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 104
	public function __construct(BaseContainer $container, bool $topLevelOnly = false) {
38 104
		$this->container = $container;
39 104
		$this->topLevelOnly = $topLevelOnly;
40 104
	}
41
42
	/**
43
	 * Get the result
44
	 *
45
	 * @return array
46
	 */
47 104
	public function get() : array {
48
		// Get initial data
49 104
		if ($this->topLevelOnly) {
50
			$data = $this->container->getTopLevel();
51
		}
52
		else {
53 104
			$data = $this->container->get();
54
		}
55
56
		// Unique
57 104
		if ($this->uniqueOnly) {
58 104
			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 6
				$data = array_unique($data);
70
			}
71
		}
72
73
		// Filters
74 104
		foreach ($this->filters as $filter) {
75
			$data = array_filter($data, $filter);
76
		}
77
78
		// Sorting
79 104
		if (isset($this->sorter)) {
80 48
			$data = $this->sorter->sort($data);
81
		}
82 102
		elseif (isset($this->sortClosure)) {
83
			uasort($data, $this->sortClosure);
84
		}
85 102
		elseif (isset($this->sortProperty)) {
86
			uasort($data, [$this, 'sortByPropertyCallback']);
87
		}
88
89
		// Order reverse
90 104
		if ($this->desc) {
91
			$data = array_reverse($data, true);
92
		}
93
94 104
		return $data;
95
	}
96
97
	/**
98
	 * Add a filter callback
99
	 *
100
	 * @param Closure $callback
101
	 *
102
	 * @return $this
103
	 */
104
	public function filter(Closure $callback) : ContainerQuery {
105
		$this->filters[] = $callback;
106
		return $this;
107
	}
108
109
	/**
110
	 * Sort in descending order
111
	 *
112
	 * @return $this
113
	 */
114
	public function desc() : ContainerQuery {
115
		$this->desc = true;
116
		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
	public function sort(Closure $callback) : ContainerQuery {
127
		$this->sortClosure = $callback;
128
		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
	public function sortBy(string $property) : ContainerQuery {
141
		$this->sortProperty = $property;
142
		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 104
	public function unique() : ContainerQuery {
161 104
		$this->uniqueOnly = true;
162 104
		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
	protected function sortByPropertyCallback($value1, $value2) : int {
174
		if (!isset($this->sortProperty)) {
175
			return 0;
176
		}
177
178
		// Get values
179
		$property = $this->sortProperty;
180
		$property1 = null;
181
		$property2 = null;
182
		if (is_object($value1) && isset($value1->$property)) {
183
			$property1 = $value1->$property;
184
		}
185
		elseif (is_array($value1) && isset($value1[$property])) {
186
			$property1 = $value1[$property];
187
		}
188
		if (is_object($value2) && isset($value2->$property)) {
189
			$property2 = $value2->$property;
190
		}
191
		elseif (is_array($value2) && isset($value2[$property])) {
192
			$property2 = $value2[$property];
193
		}
194
195
		// Compare values
196
		if ($property1 === $property2) {
197
			return 0;
198
		}
199
		return $property1 < $property2 ? -1 : 1;
200
	}
201
202
}