1 | <?php |
||||||||
2 | |||||||||
3 | /** |
||||||||
4 | * TArraySubscription classes |
||||||||
5 | * |
||||||||
6 | * @author Brad Anderson <[email protected]> |
||||||||
7 | * @link https://github.com/pradosoft/prado |
||||||||
8 | * @license https://github.com/pradosoft/prado/blob/master/LICENSE |
||||||||
9 | */ |
||||||||
10 | |||||||||
11 | namespace Prado\Collections; |
||||||||
12 | |||||||||
13 | use Prado\Exceptions\TInvalidOperationException; |
||||||||
14 | use Prado\Exceptions\TInvalidDataValueException; |
||||||||
15 | use Prado\TPropertyValue; |
||||||||
16 | use Prado\Util\Helpers\TArrayHelper; |
||||||||
17 | use ArrayAccess; |
||||||||
18 | use WeakReference; |
||||||||
19 | |||||||||
20 | /** |
||||||||
21 | * TArraySubscription class. |
||||||||
22 | * |
||||||||
23 | * Given an array reference or ArrayAccess object, this class adds an item to an |
||||||||
24 | * array on {@see self::subscribe()} and removes the element of the array when the |
||||||||
25 | * instance is dereferenced or {@see self::unsubscribe()} is called. |
||||||||
26 | * |
||||||||
27 | * These are specific types that can be subscribed: PHP Array, Object implementing |
||||||||
28 | * ArrayAccess, TList and subclasses, and TMap and subclasses. A priority can be |
||||||||
29 | * specified for {@see \Prado\Collections\IPriorityCollection} instances. |
||||||||
30 | * |
||||||||
31 | * When an array is associative, the original element is saved and restored (with |
||||||||
32 | * its original priority). IWeakCollections retain their elements in their weakened |
||||||||
33 | * "storage" state. |
||||||||
34 | * |
||||||||
35 | * ```php |
||||||||
36 | * $map = new TPriorityMap(['key' => 'original value']); |
||||||||
37 | * |
||||||||
38 | * $subscription = new TArraySubscription($map, 'key', 'new value', priority: 5); |
||||||||
39 | * |
||||||||
40 | * $subscription->getIsSubscribed() === true; |
||||||||
41 | * $map['key'] === 'new value'; // @ priority = 5 |
||||||||
42 | * |
||||||||
43 | * $subscription->unsubscribe(); |
||||||||
44 | * |
||||||||
45 | * $subscription->getIsSubscribed() === false; |
||||||||
46 | * $map['key'] === 'original value'; // @ priority = default (10) |
||||||||
47 | * ``` |
||||||||
48 | * |
||||||||
49 | * When the TArraySubscription is dereferenced, the item is also automatically unsubscribed. |
||||||||
50 | * ```php |
||||||||
51 | * { |
||||||||
52 | * $list = []; |
||||||||
53 | * { |
||||||||
54 | * $subscription = new TArraySubscription($list, null, 'subscribed item', isAssociative: false); |
||||||||
55 | * $list[0] === 'subscribed item'; |
||||||||
56 | * array_splice($list, 0, 0, ['first item']); |
||||||||
57 | * $list[] = 'last item'; // ['first item', 'subscribed item', 'last item'] |
||||||||
58 | * ... |
||||||||
59 | * } // $subscription unsubscribes here, out of scope |
||||||||
60 | * $list[0] === 'first item'; |
||||||||
61 | * $list[1] === 'last item'; // count = 2 |
||||||||
62 | * } |
||||||||
63 | * ``` |
||||||||
64 | * |
||||||||
65 | * @author Brad Anderson <[email protected]> |
||||||||
66 | * @since 4.3.0 |
||||||||
67 | * @todo TComponent is too complex, TBaseObject for getters/setters. |
||||||||
68 | */ |
||||||||
69 | class TArraySubscription |
||||||||
70 | { |
||||||||
71 | use TPriorityPropertyTrait; |
||||||||
72 | |||||||||
73 | /** |
||||||||
74 | * @var null|array|ArrayAccess The array reference or ArrayAccess being subscribed to. |
||||||||
75 | */ |
||||||||
76 | private mixed $_array = null; |
||||||||
77 | |||||||||
78 | /** |
||||||||
79 | * @var null|int|string The key that the item is added to the array. |
||||||||
80 | */ |
||||||||
81 | private null|int|string $_key = null; |
||||||||
82 | |||||||||
83 | /** |
||||||||
84 | * @var mixed The item subscribing to the array. |
||||||||
85 | */ |
||||||||
86 | protected mixed $_item = null; |
||||||||
87 | |||||||||
88 | /** |
||||||||
89 | * @var ?string The class filtering the item for storage. This is populated when |
||||||||
90 | * the {@see self::getArray()} is an instanceOf {@see \Prado\Collections\ICollectionFilter}. |
||||||||
91 | */ |
||||||||
92 | protected ?string $_filterClass = null; |
||||||||
93 | |||||||||
94 | /** |
||||||||
95 | * @var null|bool|int Is the array an associative array. False for a "list" style array. |
||||||||
96 | * null for discovery of the style of array on subscribe. default true. |
||||||||
97 | */ |
||||||||
98 | protected null|bool|int $_isAssoc = true; |
||||||||
99 | |||||||||
100 | /** |
||||||||
101 | * @var bool Is the item inserted into the collection. |
||||||||
102 | */ |
||||||||
103 | private bool $_isSubscribed = false; |
||||||||
104 | |||||||||
105 | /** |
||||||||
106 | * @var ?bool Is the subscription replacing an item. |
||||||||
107 | */ |
||||||||
108 | private ?bool $_isReplacing = null; |
||||||||
109 | |||||||||
110 | /** |
||||||||
111 | * @var mixed The original item. |
||||||||
112 | */ |
||||||||
113 | private mixed $_originalItem = null; |
||||||||
114 | |||||||||
115 | /** |
||||||||
116 | * @var ?float The priority of the original item. |
||||||||
117 | */ |
||||||||
118 | private ?float $_originalPriority = null; |
||||||||
119 | |||||||||
120 | /** |
||||||||
121 | * Constructs the TArraySubscription. If there is an key or item then the item is |
||||||||
122 | * automatically subscribed to the array when $autoSubscribe is the default null. |
||||||||
123 | * When $autoSubscribe = true, the item is added regardless of a key and/or item |
||||||||
124 | * has a value. |
||||||||
125 | * @param mixed &$array The array to subscribe to, passed by reference. |
||||||||
126 | * Default null. |
||||||||
127 | * @param mixed $key The key of the subscribed item, default null for append the |
||||||||
128 | * item. Default null. |
||||||||
129 | * @param mixed $item The item to insert into the array at $key with $priority. |
||||||||
130 | * Default null. |
||||||||
131 | * @param null|float|int $priority The priority of the item for IPriorityCollection. |
||||||||
132 | * Default null. |
||||||||
133 | * @param null|bool|int $isAssociative Is the array an associative array. false is |
||||||||
134 | * the list from (0...n-1). When false, this will use `array_splice` to insert |
||||||||
135 | * the item. Default 1 for true except for TList. |
||||||||
136 | * @param bool $autoSubscribe Should the |
||||||||
137 | */ |
||||||||
138 | public function __construct(mixed &$array = null, mixed $key = null, mixed $item = null, null|int|float $priority = null, null|bool|int $isAssociative = 1, ?bool $autoSubscribe = null) |
||||||||
139 | { |
||||||||
140 | $this->setArray($array); |
||||||||
141 | $this->setKey($key); |
||||||||
142 | $this->setItem($item); |
||||||||
143 | $this->setPriority($priority); |
||||||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||||||
144 | $this->setIsAssociative($isAssociative); |
||||||||
145 | |||||||||
146 | //parent::__construct(); |
||||||||
147 | |||||||||
148 | if (($autoSubscribe === null && ($key !== null || $item !== null) || $autoSubscribe === true) && $this->getArray() !== null) { |
||||||||
0 ignored issues
–
show
|
|||||||||
149 | $this->subscribe(); |
||||||||
150 | } |
||||||||
151 | } |
||||||||
152 | |||||||||
153 | /** |
||||||||
154 | * Cleans up the instance on destruction. |
||||||||
155 | * If the item is subscribed to the array, the item is removed. |
||||||||
156 | */ |
||||||||
157 | public function __destruct() |
||||||||
158 | { |
||||||||
159 | $this->unsubscribe(); |
||||||||
160 | //parent::__destruct(); |
||||||||
161 | } |
||||||||
162 | |||||||||
163 | /** |
||||||||
164 | * Returns the collection to which the item is subscribed. |
||||||||
165 | * Be very careful with the returnad array as it is passed by reference and could change |
||||||||
166 | * the original variable to something other than an array. |
||||||||
167 | * ```php |
||||||||
168 | * $array = & $subscription->getArray(); |
||||||||
169 | * ... //use $array |
||||||||
170 | * // $array = null; // This will destroy the array being used originally. Avoid this. |
||||||||
171 | * unset($array); // This dereferences. |
||||||||
172 | * |
||||||||
173 | * // or, use a non pass-by-reference |
||||||||
174 | * $array = $subscription->getArray(); |
||||||||
175 | * $array = null; // ok. |
||||||||
176 | * ``` |
||||||||
177 | * @param bool $weak |
||||||||
178 | * @return array|ArrayAccess The subscribed array-collection, passed by reference. |
||||||||
179 | */ |
||||||||
180 | public function &getArray(bool $weak = false): array|ArrayAccess|WeakReference|null |
||||||||
181 | { |
||||||||
182 | if ($this->_array instanceof WeakReference) { |
||||||||
183 | if ($weak) { |
||||||||
184 | $collection = $this->_array; |
||||||||
185 | } else { |
||||||||
186 | $collection = $this->_array->get(); |
||||||||
187 | } |
||||||||
188 | } elseif (is_array($this->_array)) { |
||||||||
189 | $collection = &$this->_array; |
||||||||
190 | } elseif ($this->_array instanceof ArrayAccess) { |
||||||||
191 | $collection = $this->_array; |
||||||||
192 | } else { |
||||||||
193 | $collection = null; |
||||||||
194 | } |
||||||||
195 | return $collection; |
||||||||
196 | } |
||||||||
197 | |||||||||
198 | /** |
||||||||
199 | * Sets the array or ArrayAccess object. |
||||||||
200 | * @param null|array|ArrayAccess $value The array, passed by reference. |
||||||||
201 | * @throws TInvalidOperationException When setting during a subscription. |
||||||||
202 | * @throws TInvalidOperationException If the item is already subscribed. |
||||||||
203 | * @return static The current object. |
||||||||
204 | */ |
||||||||
205 | public function setArray(null|array|ArrayAccess &$value): static |
||||||||
206 | { |
||||||||
207 | if ($this->_isSubscribed) { |
||||||||
208 | throw new TInvalidOperationException('arraysubscription_no_change', 'Array'); |
||||||||
209 | } |
||||||||
210 | |||||||||
211 | unset($this->_array); |
||||||||
212 | if (is_object($value)) { |
||||||||
0 ignored issues
–
show
|
|||||||||
213 | $this->_array = WeakReference::create($value); |
||||||||
214 | } else { |
||||||||
215 | $this->_array = &$value; |
||||||||
216 | } |
||||||||
217 | |||||||||
218 | return $this; |
||||||||
219 | } |
||||||||
220 | |||||||||
221 | /** |
||||||||
222 | * If the item is subscribed and the key is null, the item key will be discovered |
||||||||
223 | * with the TList (by {@see \Prado\Collections\TList::indexOf()}) or array (by array_search). |
||||||||
224 | * @return null|int|string The key for the item subscription to the array. |
||||||||
225 | */ |
||||||||
226 | public function getKey(): null|int|string |
||||||||
227 | { |
||||||||
228 | $collection = &$this->getArray(); |
||||||||
229 | if ($this->_isSubscribed && $this->_key === null) { |
||||||||
230 | if ($collection instanceof TList) { |
||||||||
231 | $args = [$this->getItem()]; |
||||||||
232 | if ($collection instanceof IPriorityCollection) { |
||||||||
233 | $args[] = $this->getPriority(); |
||||||||
234 | } |
||||||||
235 | return ($index = $collection->indexOf(...$args)) === -1 ? null : $index; |
||||||||
0 ignored issues
–
show
The method
indexOf() does not exist on ArrayAccess . It seems like you code against a sub-type of ArrayAccess such as Prado\Collections\TList or Prado\Collections\TMap or Prado\Web\THttpSession or Prado\Web\THttpRequest or Prado\Caching\TCache .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() The method
indexOf() does not exist on WeakReference .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||||
236 | } elseif (is_array($collection)) { |
||||||||
237 | if (($key = array_search($this->getItem(), $collection, true)) === false) { |
||||||||
238 | return null; |
||||||||
239 | } |
||||||||
240 | return $key; |
||||||||
241 | } |
||||||||
242 | } |
||||||||
243 | return $this->_key; |
||||||||
244 | } |
||||||||
245 | |||||||||
246 | /** |
||||||||
247 | * @param mixed $value The key for the item subscription to the array. |
||||||||
248 | * @throws TInvalidOperationException If the item is already subscribed. |
||||||||
249 | */ |
||||||||
250 | public function setKey(mixed $value): static |
||||||||
251 | { |
||||||||
252 | if ($this->_isSubscribed) { |
||||||||
253 | throw new TInvalidOperationException('arraysubscription_no_change', 'Key'); |
||||||||
254 | } |
||||||||
255 | |||||||||
256 | if (is_bool($value) || is_float($value)) { |
||||||||
257 | $value = (int) $value; |
||||||||
258 | } |
||||||||
259 | $this->_key = $value; |
||||||||
260 | |||||||||
261 | return $this; |
||||||||
262 | } |
||||||||
263 | |||||||||
264 | /** |
||||||||
265 | * @param bool $unfiltered Should the item be unfiltered back from the stored format. |
||||||||
266 | * default false. |
||||||||
267 | * @return mixed The item subscribing to the array. |
||||||||
268 | */ |
||||||||
269 | public function getItem(bool $unfiltered = false): mixed |
||||||||
270 | { |
||||||||
271 | $item = $this->_item; |
||||||||
272 | |||||||||
273 | if (!$unfiltered && $this->_filterClass !== null) { |
||||||||
274 | $this->_filterClass::filterItemForOutput($item); |
||||||||
275 | } |
||||||||
276 | |||||||||
277 | return $item; |
||||||||
278 | } |
||||||||
279 | |||||||||
280 | /** |
||||||||
281 | * @param mixed $value The item subscribing to the array. |
||||||||
282 | * @throws TInvalidOperationException If the item is already subscribed. |
||||||||
283 | * @return static The current object. |
||||||||
284 | */ |
||||||||
285 | public function setItem(mixed $value): static |
||||||||
286 | { |
||||||||
287 | if ($this->_isSubscribed) { |
||||||||
288 | throw new TInvalidOperationException('arraysubscription_no_change', 'Item'); |
||||||||
289 | } |
||||||||
290 | |||||||||
291 | $this->_item = $value; |
||||||||
292 | |||||||||
293 | return $this; |
||||||||
294 | } |
||||||||
295 | |||||||||
296 | /** |
||||||||
297 | * This is on applicable to {@see \Prado\Collections\IPriorityCollection}. |
||||||||
298 | * @param ?numeric $value The priority of the item. |
||||||||
0 ignored issues
–
show
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. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||||||
299 | * @throws TInvalidOperationException If the item is already subscribed. |
||||||||
300 | * @return static The current object. |
||||||||
301 | */ |
||||||||
302 | public function setPriority($value): static |
||||||||
303 | { |
||||||||
304 | if ($this->_isSubscribed) { |
||||||||
305 | throw new TInvalidOperationException('arraysubscription_no_change', 'Priority'); |
||||||||
306 | } |
||||||||
307 | |||||||||
308 | if ($value === '') { |
||||||||
0 ignored issues
–
show
|
|||||||||
309 | $value = null; |
||||||||
310 | } |
||||||||
311 | if ($value !== null) { |
||||||||
312 | $value = TPropertyValue::ensureFloat($value); |
||||||||
313 | } |
||||||||
314 | $this->_priority = $value; |
||||||||
315 | |||||||||
316 | return $this; |
||||||||
317 | } |
||||||||
318 | |||||||||
319 | /** |
||||||||
320 | * Whether to add to the array by association or by splicing (for an ordered list). |
||||||||
321 | * @return null|null|bool Is the array associative; default true. false will treat the array |
||||||||
322 | * as a list from (0, ..., count() - 1). if null, where needed, the "list"ness |
||||||||
323 | * of the array will be determined by {@see \Prado\Util\Helpers\TArrayHelper::array_is_list()}. |
||||||||
324 | */ |
||||||||
325 | public function getIsAssociative(): null|bool|int |
||||||||
326 | { |
||||||||
327 | return $this->_isAssoc; |
||||||||
0 ignored issues
–
show
|
|||||||||
328 | } |
||||||||
329 | |||||||||
330 | /** |
||||||||
331 | * @param null|bool|int $value Is the array associative; default null. false will treat the array |
||||||||
332 | * as a list from (0, ..., count() - 1). if null, where needed, the "list"ness |
||||||||
333 | * of the array will be determined by {@see \Prado\Util\Helpers\TArrayHelper::array_is_list()}. |
||||||||
334 | * @throws TInvalidOperationException If the item is already subscribed. |
||||||||
335 | * @return static The current object. |
||||||||
336 | */ |
||||||||
337 | public function setIsAssociative(null|bool|int $value = null): static |
||||||||
338 | { |
||||||||
339 | if ($this->_isSubscribed) { |
||||||||
340 | throw new TInvalidOperationException('arraysubscription_no_change', 'Key'); |
||||||||
341 | } |
||||||||
342 | |||||||||
343 | $this->_isAssoc = $value; |
||||||||
344 | |||||||||
345 | return $this; |
||||||||
346 | } |
||||||||
347 | |||||||||
348 | /** |
||||||||
349 | * @return bool Is the item subscribed to the array. |
||||||||
350 | */ |
||||||||
351 | public function getIsSubscribed(): bool |
||||||||
352 | { |
||||||||
353 | return $this->_isSubscribed; |
||||||||
354 | } |
||||||||
355 | |||||||||
356 | /** |
||||||||
357 | * Places the item in the array at the key (and priority, where possible). |
||||||||
358 | * List based ArrayAccess must also implement \Countable as well. |
||||||||
359 | * @throws TInvalidDataValueException When the Array is an ArrayAccess (but not |
||||||||
360 | * TMap nor TList), the Array isAssociative, and key is null. |
||||||||
361 | * @return ?bool Was the subscription successful. If the item is already subscribed |
||||||||
362 | * this will return false. If the array is not an array, this returns null; |
||||||||
363 | */ |
||||||||
364 | public function subscribe(): ?bool |
||||||||
365 | { |
||||||||
366 | if ($this->_isSubscribed) { |
||||||||
367 | return false; |
||||||||
368 | } |
||||||||
369 | |||||||||
370 | $collection = &$this->getArray(); |
||||||||
371 | if (!is_array($collection) && !($collection instanceof ArrayAccess)) { |
||||||||
372 | return null; |
||||||||
373 | } |
||||||||
374 | |||||||||
375 | if (is_int($this->_isAssoc)) { |
||||||||
376 | $this->_isAssoc = !($collection instanceof TList); |
||||||||
377 | } |
||||||||
378 | |||||||||
379 | $this->_isReplacing = false; |
||||||||
380 | $key = $this->_key; |
||||||||
381 | |||||||||
382 | // @todo, PHPStan bug https://github.com/phpstan/phpstan/issues/9519 |
||||||||
383 | if ($collection instanceof TList || ($collection instanceof TMap)) { |
||||||||
384 | $this->_isAssoc = $collection instanceof TMap; |
||||||||
385 | if ($collection instanceof TList && $key !== null) { |
||||||||
386 | $priority = $collection->insertAt($key, $this->getItem()); |
||||||||
0 ignored issues
–
show
It seems like
$key can also be of type string ; however, parameter $index of Prado\Collections\TList::insertAt() does only seem to accept integer , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() Are you sure the assignment to
$priority is correct as $collection->insertAt($key, $this->getItem()) targeting Prado\Collections\TList::insertAt() seems to always return null.
This check looks for function or method calls that always return null and whose return value is assigned to a variable. class A
{
function getObject()
{
return null;
}
}
$a = new A();
$object = $a->getObject();
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||||||
387 | if ($collection instanceof IPriorityCollection) { |
||||||||
388 | $this->setPriority($priority); |
||||||||
389 | } |
||||||||
390 | $this->setKey(null); |
||||||||
391 | } else { |
||||||||
392 | $args = []; |
||||||||
393 | $item = $this->getItem(); |
||||||||
394 | if ($collection instanceof TMap) { |
||||||||
395 | if ($collection->contains($key)) { |
||||||||
396 | $this->_isReplacing = true; |
||||||||
397 | $this->_originalItem = $collection[$key]; |
||||||||
398 | |||||||||
399 | if ($collection instanceof IPriorityCollection) { |
||||||||
400 | $this->_originalPriority = $collection->priorityAt($key); |
||||||||
0 ignored issues
–
show
The method
priorityAt() does not exist on Prado\Collections\TMap . Since you implemented __call , consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||
401 | if ($item === null) { |
||||||||
402 | $this->setItem($item = $this->_originalItem); |
||||||||
403 | } |
||||||||
404 | } |
||||||||
405 | } |
||||||||
406 | array_push($args, $key); |
||||||||
407 | } |
||||||||
408 | array_push($args, $item); |
||||||||
409 | if ($collection instanceof IPriorityCollection) { |
||||||||
410 | if (($priority = $this->getPriority()) === null) { |
||||||||
411 | $this->setPriority($collection->getDefaultPriority()); |
||||||||
0 ignored issues
–
show
The method
getDefaultPriority() does not exist on Prado\Collections\TList . Since you implemented __call , consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() The method
getDefaultPriority() does not exist on Prado\Collections\TMap . Since you implemented __call , consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||
412 | } |
||||||||
413 | array_push($args, $priority); |
||||||||
414 | } |
||||||||
415 | |||||||||
416 | $key = $collection->add(...$args); |
||||||||
0 ignored issues
–
show
The call to
Prado\Collections\TMap::add() has too few arguments starting with value .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() $args is expanded, but the parameter $item of Prado\Collections\TList::add() does not expect variable arguments.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||
417 | |||||||||
418 | if ($collection instanceof TMap) { |
||||||||
419 | $this->setKey($key); |
||||||||
420 | } |
||||||||
421 | } |
||||||||
422 | } else { |
||||||||
423 | if ($collection instanceof ArrayAccess) { |
||||||||
424 | $this->_isAssoc = true; |
||||||||
425 | } elseif ($this->_isAssoc === null) { |
||||||||
426 | $this->_isAssoc = !TArrayHelper::array_is_list($collection); |
||||||||
427 | } |
||||||||
428 | if ($key === null && $this->_isAssoc) { |
||||||||
429 | if ($collection instanceof ArrayAccess) { |
||||||||
430 | throw new TInvalidDataValueException('arraysubscription_no_null_key'); |
||||||||
431 | } |
||||||||
432 | $collection[] = $this->getItem(); |
||||||||
433 | $this->setKey(array_key_last($collection)); |
||||||||
434 | } else { |
||||||||
435 | if ($key === null) { |
||||||||
436 | $key = count($collection); |
||||||||
0 ignored issues
–
show
It seems like
$collection can also be of type ArrayAccess ; however, parameter $value of count() does only seem to accept Countable|array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||
437 | } |
||||||||
438 | $offsetSet = $this->_isAssoc || !is_array($collection); |
||||||||
439 | if ($offsetSet || $key === count($collection)) { |
||||||||
440 | if ($offsetSet && (isset($collection[$key]) || is_array($collection) && array_key_exists($key, $collection))) { |
||||||||
441 | $this->_isReplacing = true; |
||||||||
442 | $this->_originalItem = $collection[$key]; |
||||||||
443 | } |
||||||||
444 | $collection[$key] = $this->getItem(); |
||||||||
445 | } else { |
||||||||
446 | if ($key < 0 && $key > count($collection)) { |
||||||||
447 | throw new TInvalidDataValueException('arraysubscription_index_invalid', $key, count($collection)); |
||||||||
448 | } |
||||||||
449 | array_splice($collection, $key, 0, [$this->getItem()]); |
||||||||
0 ignored issues
–
show
It seems like
$key can also be of type string ; however, parameter $offset of array_splice() does only seem to accept integer , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||
450 | } |
||||||||
451 | if (!$this->_isAssoc && is_array($collection)) { |
||||||||
452 | $this->setKey(null); |
||||||||
453 | } |
||||||||
454 | } |
||||||||
455 | } |
||||||||
456 | |||||||||
457 | if ($collection instanceof ICollectionFilter) { |
||||||||
458 | $this->_filterClass = $collection::class; |
||||||||
459 | $collection::filterItemForInput($this->_item); |
||||||||
460 | if ($this->_isReplacing) { |
||||||||
461 | $collection::filterItemForInput($this->_originalItem); |
||||||||
462 | } |
||||||||
463 | } |
||||||||
464 | |||||||||
465 | $this->_isSubscribed = true; |
||||||||
466 | |||||||||
467 | return true; |
||||||||
468 | } |
||||||||
469 | |||||||||
470 | /** |
||||||||
471 | * Removes the item from the array at the key (and priority, where possible). |
||||||||
472 | * @return ?bool Was the unsubscribe successful. null when the array is not the proper |
||||||||
473 | * type, and false if already unsubscribe. |
||||||||
474 | */ |
||||||||
475 | public function unsubscribe(): ?bool |
||||||||
476 | { |
||||||||
477 | if (!$this->_isSubscribed) { |
||||||||
478 | return false; |
||||||||
479 | } |
||||||||
480 | |||||||||
481 | $this->_isSubscribed = false; |
||||||||
482 | |||||||||
483 | if ($this->_filterClass !== null) { |
||||||||
484 | $this->_filterClass::filterItemForOutput($this->_item); |
||||||||
485 | |||||||||
486 | if ($this->_isReplacing) { |
||||||||
487 | $this->_filterClass::filterItemForOutput($this->_originalItem); |
||||||||
488 | } |
||||||||
489 | $this->_filterClass = null; |
||||||||
490 | } |
||||||||
491 | |||||||||
492 | $collection = &$this->getArray(); |
||||||||
493 | |||||||||
494 | if (!is_array($collection) && !($collection instanceof ArrayAccess)) { |
||||||||
495 | return null; |
||||||||
496 | } |
||||||||
497 | |||||||||
498 | if ($collection instanceof TList) { |
||||||||
499 | $args = [$this->getItem()]; |
||||||||
500 | if ($collection instanceof IPriorityCollection) { |
||||||||
501 | array_push($args, $this->getPriority()); |
||||||||
502 | } |
||||||||
503 | try { |
||||||||
504 | $collection->remove(...$args); |
||||||||
0 ignored issues
–
show
The method
remove() does not exist on ArrayAccess . It seems like you code against a sub-type of ArrayAccess such as Prado\Collections\TList or Prado\Collections\TMap or Prado\Web\THttpSession or Cassandra\Map or Prado\Web\THttpRequest or Prado\Caching\TCache .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||
505 | } catch (TInvalidDataValueException $e) { |
||||||||
506 | // if not found, continue. |
||||||||
507 | } |
||||||||
508 | } else { |
||||||||
509 | if ($this->_isAssoc || !is_array($collection)) { |
||||||||
510 | $key = $this->_key; |
||||||||
511 | if (isset($collection[$key]) || is_array($collection) && array_key_exists($key, $collection)) { |
||||||||
512 | $item = $collection[$key]; |
||||||||
513 | if ($item === $this->getItem()) { |
||||||||
514 | unset($collection[$key]); |
||||||||
515 | if ($this->_isReplacing && (!($collection instanceof IWeakCollection) || $this->_originalItem !== null)) { |
||||||||
516 | if ($collection instanceof TPriorityMap) { |
||||||||
517 | $collection->add($key, $this->_originalItem, $this->_originalPriority); |
||||||||
0 ignored issues
–
show
It seems like
$this->_originalPriority can also be of type double ; however, parameter $priority of Prado\Collections\TPriorityMap::add() does only seem to accept Prado\Collections\numeric|null , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||
518 | } else { |
||||||||
519 | $collection[$key] = $this->_originalItem; |
||||||||
520 | } |
||||||||
521 | } |
||||||||
522 | } |
||||||||
523 | } |
||||||||
524 | unset($this->_originalItem); |
||||||||
525 | unset($this->_originalPriority); |
||||||||
526 | $this->_isReplacing = null; |
||||||||
527 | } else { |
||||||||
528 | $key = array_search($this->getItem(), $collection, true); |
||||||||
529 | if ($key !== false) { |
||||||||
530 | array_splice($collection, $key, 1); |
||||||||
0 ignored issues
–
show
It seems like
$key can also be of type string ; however, parameter $offset of array_splice() does only seem to accept integer , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||
531 | } |
||||||||
532 | } |
||||||||
533 | } |
||||||||
534 | |||||||||
535 | return true; |
||||||||
536 | } |
||||||||
537 | |||||||||
538 | } |
||||||||
539 |