Passed
Push — enums ( 8bfe56...7bf697 )
by Fabio
06:38 queued 01:28
created

TPriorityCollectionTrait::flattenPriorities()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 7
rs 10
1
<?php
2
/**
3
 * TPriorityCollectionTrait class
4
 *
5
 * @author Brad Anderson <[email protected]>
6
 * @link https://github.com/pradosoft/prado
7
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
8
 */
9
10
namespace Prado\Collections;
11
12
use Prado\Exceptions\TInvalidDataTypeException;
13
use Prado\Exceptions\TInvalidDataValueException;
14
use Prado\Exceptions\TInvalidOperationException;
15
use Prado\TPropertyValue;
16
17
/**
18
 * TPriorityCollectionTrait class
19
 *
20
 * This trait implements the common properties and methods of Priority Collection
21
 * classes.
22
 *
23
 * The trait adds a boolean for whether or not _d is ordered, a cached flattened
24
 * array _fd, a default priority (by default, 10) _dp, and precision of priorities (by
25
 * default, 8 [decimal places]) _p.
26
 *
27
 * The trait adds methods:
28
 *	- {@link getDefaultPriority} returns the default priority of items without priority.
29
 *	- {@link setDefaultPriority} sets the default priority. (protected)
30
 *	- {@link getPrecision} returns the precision of priorities.
31
 *	- {@link setPrecision} sets the precision of priorities. (protected)
32
 *	- {@link ensurePriority} standardize and round priorities. (protected)
33
 *	- {@link sortPriorities} sorts _d and flags as sorted. (protected)
34
 *	- {@link flattenPriorities} flattens the priority items, in order into cache.. (protected)
35
 *	- {@link getPriorities} gets the priorities of the collection.
36
 *	- {@link getPriorityCount} gets the number of items at a priority.
37
 *	- {@link itemsAtPriority} gets the items at a given priority.
38
 *	- {@link getIterator} overrides subclasses for an iterator of the flattened array.
39
 *	- {@link toArray} the flattened collection in order.
40
 *	- {@link toPriorityArray} the array of priorities (keys) and array of items (value).
41
 *	- {@link toArrayBelowPriority} the items below a Priority, default is not inclusive
42
 *	- {@link toArrayAbovePriority} the items above a priority, default is inclusive.
43
 *	- {@link _priorityZappableSleepProps} to add the excluded trait properties on sleep.
44
 *
45
 * The priorities are implemented as numeric strings
46
 *
47
 * @author Brad Anderson <[email protected]>
48
 * @since 4.2.3
49
 */
50
trait TPriorityCollectionTrait
51
{
52
	/**
53
	 * @var bool indicates if the _d is currently ordered.
54
	 */
55
	protected bool $_o = false;
56
57
	/**
58
	 * @var null|array cached flattened internal data storage
59
	 */
60
	protected ?array $_fd = null;
61
62
	/**
63
	 * @var string the default priority of items without specified priorities
64
	 */
65
	private string $_dp = '10';
66
67
	/**
68
	 * @var int the precision of the numeric priorities within this priority list.
69
	 */
70
	private int $_p = 8;
71
72
	/**
73
	 * @return numeric gets the default priority of inserted items without a specified priority
0 ignored issues
show
Bug introduced by
The type Prado\Collections\numeric was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
74
	 */
75
	public function getDefaultPriority()
76
	{
77
		return $this->_dp;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->_dp returns the type string which is incompatible with the documented return type Prado\Collections\numeric.
Loading history...
78
	}
79
80
	/**
81
	 * This must be called internally or when instantiated.
82
	 * @param numeric $value sets the default priority of inserted items without a specified priority
83
	 */
84
	protected function setDefaultPriority($value)
85
	{
86
		$this->_dp = (string) round(TPropertyValue::ensureFloat($value), $this->_p);
87
	}
88
89
	/**
90
	 * @return int The precision of numeric priorities, defaults to 8
91
	 */
92
	public function getPrecision(): int
93
	{
94
		return $this->_p;
95
	}
96
97
	/**
98
	 * This must be called internally or when instantiated.
99
	 * This resets the array priorities to the new precision and adjusts
100
	 * the DefaultPriority to the new precision as well.
101
	 * @param int $value The precision of numeric priorities.
102
	 */
103
	protected function setPrecision($value): void
104
	{
105
		$this->_p = TPropertyValue::ensureInteger($value);
106
		$this->setDefaultPriority($this->_dp);
0 ignored issues
show
Bug introduced by
$this->_dp of type string is incompatible with the type Prado\Collections\numeric expected by parameter $value of Prado\Collections\TPrior...t::setDefaultPriority(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

106
		$this->setDefaultPriority(/** @scrutinizer ignore-type */ $this->_dp);
Loading history...
107
		$_d = [];
108
		foreach(array_keys($this->_d) as $priority) {
109
			$newPriority = $this->ensurePriority($priority);
110
			if (array_key_exists($newPriority, $_d)) {
111
				$_d[$newPriority] = array_merge($_d[$newPriority], $this->_d[$priority]);
112
			} else {
113
				$_d[$newPriority] = $this->_d[$priority];
114
			}
115
		}
116
		$this->_d = $_d;
0 ignored issues
show
Bug Best Practice introduced by
The property _d does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
117
		$this->_fd = null;
118
	}
119
120
	/**
121
	 * Taken an input Priority and ensures its value.
122
	 * Sets the default $priority when none is set,
123
	 * then rounds to the proper precision and makes
124
	 * into a string.
125
	 * @param mixed $priority
126
	 * @return string the priority in string format
127
	 */
128
	protected function ensurePriority($priority): string
129
	{
130
		if ($priority === null || !is_numeric($priority)) {
131
			$priority = $this->getDefaultPriority();
132
		}
133
		return (string) round((float) $priority, $this->_p);
134
	}
135
136
137
	/**
138
	 * This orders the priority list internally.
139
	 */
140
	protected function sortPriorities(): void
141
	{
142
		if (!$this->_o) {
143
			ksort($this->_d, SORT_NUMERIC);
144
			$this->_o = true;
145
		}
146
	}
147
148
	/**
149
	 * This flattens the priority list into a flat array [0,...,n-1]
150
	 */
151
	protected function flattenPriorities(): void
152
	{
153
		if (is_array($this->_fd)) {
154
			return;
155
		}
156
		$this->sortPriorities();
157
		$this->_fd = array_merge(...$this->_d);
158
	}
159
160
	/**
161
	 * This returns a list of the priorities within this list, ordered lowest to highest.
162
	 * @return array the array of priority numerics in decreasing priority order
163
	 */
164
	public function getPriorities(): array
165
	{
166
		$this->sortPriorities();
167
		return array_keys($this->_d);
168
	}
169
170
	/**
171
	 * Gets the number of items at a priority within the list
172
	 * @param null|numeric $priority optional priority at which to count items.  if no parameter, it will be set to the default {@link getDefaultPriority}
173
	 * @return false|int the number of items in the list at the specified priority
174
	 */
175
	public function getPriorityCount($priority = null)
176
	{
177
		$priority = $this->ensurePriority($priority);
178
		if (!isset($this->_d[$priority]) || !is_array($this->_d[$priority])) {
179
			return false;
180
		}
181
		return count($this->_d[$priority]);
182
	}
183
184
	/**
185
	 * Returns an iterator for traversing the items in the list.
186
	 * This method is required by the interface \IteratorAggregate.
187
	 * @return \Iterator an iterator for traversing the items in the list.
188
	 */
189
	public function getIterator(): \Iterator
190
	{
191
		$this->flattenPriorities();
192
		return new \ArrayIterator($this->_fd);
193
	}
194
195
	/**
196
	 * Gets all the items at a specific priority.
197
	 * @param null|numeric $priority priority of the items to get.  Defaults to null, filled in with the default priority, if left blank.
198
	 * @return ?array all items at priority in index order, null if there are no items at that priority
199
	 */
200
	public function itemsAtPriority($priority = null): ?array
201
	{
202
		$priority = $this->ensurePriority($priority);
203
		return $this->_d[$priority] ?? null;
204
	}
205
206
	/**
207
	 * @return array the priority list of items in array
208
	 */
209
	public function toArray(): array
210
	{
211
		$this->flattenPriorities();
212
		return $this->_fd;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->_fd could return the type null which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
213
	}
214
215
	/**
216
	 * @return array the array of priorities keys with values of arrays of items.  The priorities are sorted so important priorities, lower numerics, are first.
217
	 */
218
	public function toPriorityArray(): array
219
	{
220
		$this->sortPriorities();
221
		return $this->_d;
222
	}
223
224
	/**
225
	 * Combines the map elements which have a priority below the parameter value
226
	 * @param numeric $priority the cut-off priority.  All items of priority less than this are returned.
227
	 * @param bool $inclusive whether or not the input cut-off priority is inclusive.  Default: false, not inclusive.
228
	 * @return array the array of priorities keys with values of arrays of items that are below a specified priority.
229
	 *  The priorities are sorted so important priorities, lower numerics, are first.
230
	 */
231
	public function toArrayBelowPriority($priority, bool $inclusive = false): array
232
	{
233
		$this->sortPriorities();
234
		$items = [];
235
		foreach ($this->_d as $itemspriority => $itemsatpriority) {
236
			if ((!$inclusive && $itemspriority >= $priority) || $itemspriority > $priority) {
237
				break;
238
			}
239
			$items[] = $itemsatpriority;
240
		}
241
		return array_merge(...$items);
242
	}
243
244
	/**
245
	 * Combines the map elements which have a priority above the parameter value
246
	 * @param numeric $priority the cut-off priority.  All items of priority greater than this are returned.
247
	 * @param bool $inclusive whether or not the input cut-off priority is inclusive.  Default: true, inclusive.
248
	 * @return array the array of priorities keys with values of arrays of items that are above a specified priority.
249
	 *  The priorities are sorted so important priorities, lower numerics, are first.
250
	 */
251
	public function toArrayAbovePriority($priority, bool $inclusive = true): array
252
	{
253
		$this->sortPriorities();
254
		$items = [];
255
		foreach ($this->_d as $itemspriority => $itemsatpriority) {
256
			if ((!$inclusive && $itemspriority <= $priority) || $itemspriority < $priority) {
257
				continue;
258
			}
259
			$items[] = $itemsatpriority;
260
		}
261
		return array_merge(...$items);
262
	}
263
264
	/**
265
	 * Returns an array with the names of all variables of this object that should NOT be serialized
266
	 * because their value is the default one or useless to be cached for the next page loads.
267
	 * Reimplement in derived classes to add new variables, but remember to  also to call the parent
268
	 * implementation first.
269
	 * @param array $exprops by reference
270
	 */
271
	protected function _priorityZappableSleepProps(&$exprops)
272
	{
273
		if ($this->_o === false) {
274
			$exprops[] = "\0*\0_o";
275
		}
276
		$exprops[] = "\0*\0_fd";
277
		if ($this->_dp == 10) {
278
			$exprops[] = "\0" . __CLASS__ . "\0_dp";
279
		}
280
		if ($this->_p === 8) {
281
			$exprops[] = "\0" . __CLASS__ . "\0_p";
282
		}
283
	}
284
}
285