PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 3.0.1
Defender Security – Malware Scanner, Login Security & Firewall v3.0.1
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / vendor / ramsey / collection / src / AbstractCollection.php

AbstractCollection.php in Defender Security – Malware Scanner, Login Security & Firewall 3.0.1, at vendor/ramsey/collection/src/AbstractCollection.php

317 lines 8.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * This file is part of the ramsey/collection library
5 *
6 * For the full copyright and license information, please view the LICENSE
7 * file that was distributed with this source code.
8 *
9 * @copyright Copyright (c) Ben Ramsey <[email protected]>
10 * @license http://opensource.org/licenses/MIT MIT
11 */
12
13 declare(strict_types=1);
14
15 namespace Ramsey\Collection;
16
17 use Closure;
18 use Ramsey\Collection\Exception\CollectionMismatchException;
19 use Ramsey\Collection\Exception\InvalidArgumentException;
20 use Ramsey\Collection\Exception\InvalidSortOrderException;
21 use Ramsey\Collection\Exception\OutOfBoundsException;
22 use Ramsey\Collection\Tool\TypeTrait;
23 use Ramsey\Collection\Tool\ValueExtractorTrait;
24 use Ramsey\Collection\Tool\ValueToStringTrait;
25
26 use function array_filter;
27 use function array_map;
28 use function array_merge;
29 use function array_search;
30 use function array_udiff;
31 use function array_uintersect;
32 use function current;
33 use function end;
34 use function in_array;
35 use function reset;
36 use function sprintf;
37 use function unserialize;
38 use function usort;
39
40 /**
41 * This class provides a basic implementation of `CollectionInterface`, to
42 * minimize the effort required to implement this interface
43 *
44 * @template T
45 * @template-extends AbstractArray<T>
46 * @template-implements CollectionInterface<T>
47 */
48 abstract class AbstractCollection extends AbstractArray implements CollectionInterface
49 {
50 use TypeTrait;
51 use ValueToStringTrait;
52 use ValueExtractorTrait;
53
54 /**
55 * @inheritDoc
56 */
57 public function add($element): bool
58 {
59 $this[] = $element;
60
61 return true;
62 }
63
64 /**
65 * @inheritDoc
66 */
67 public function contains($element, bool $strict = true): bool
68 {
69 return in_array($element, $this->data, $strict);
70 }
71
72 /**
73 * @inheritDoc
74 */
75 public function offsetSet($offset, $value): void
76 {
77 if ($this->checkType($this->getType(), $value) === false) {
78 throw new InvalidArgumentException(
79 'Value must be of type ' . $this->getType() . '; value is '
80 . $this->toolValueToString($value)
81 );
82 }
83
84 if ($offset === null) {
85 $this->data[] = $value;
86 } else {
87 $this->data[$offset] = $value;
88 }
89 }
90
91 /**
92 * @inheritDoc
93 */
94 public function remove($element): bool
95 {
96 if (($position = array_search($element, $this->data, true)) !== false) {
97 unset($this->data[$position]);
98
99 return true;
100 }
101
102 return false;
103 }
104
105 /**
106 * @inheritDoc
107 */
108 public function column(string $propertyOrMethod): array
109 {
110 $temp = [];
111
112 foreach ($this->data as $item) {
113 /** @var mixed $value */
114 $value = $this->extractValue($item, $propertyOrMethod);
115
116 /** @psalm-suppress MixedAssignment */
117 $temp[] = $value;
118 }
119
120 return $temp;
121 }
122
123 /**
124 * @inheritDoc
125 */
126 public function first()
127 {
128 if ($this->isEmpty()) {
129 throw new OutOfBoundsException('Can\'t determine first item. Collection is empty');
130 }
131
132 reset($this->data);
133
134 /** @var T $first */
135 $first = current($this->data);
136
137 return $first;
138 }
139
140 /**
141 * @inheritDoc
142 */
143 public function last()
144 {
145 if ($this->isEmpty()) {
146 throw new OutOfBoundsException('Can\'t determine last item. Collection is empty');
147 }
148
149 /** @var T $item */
150 $item = end($this->data);
151 reset($this->data);
152
153 return $item;
154 }
155
156 public function sort(string $propertyOrMethod, string $order = self::SORT_ASC): CollectionInterface
157 {
158 if (!in_array($order, [self::SORT_ASC, self::SORT_DESC], true)) {
159 throw new InvalidSortOrderException('Invalid sort order given: ' . $order);
160 }
161
162 $collection = clone $this;
163
164 usort(
165 $collection->data,
166 /**
167 * @param T $a
168 * @param T $b
169 */
170 function ($a, $b) use ($propertyOrMethod, $order): int {
171 /** @var mixed $aValue */
172 $aValue = $this->extractValue($a, $propertyOrMethod);
173
174 /** @var mixed $bValue */
175 $bValue = $this->extractValue($b, $propertyOrMethod);
176
177 return ($aValue <=> $bValue) * ($order === self::SORT_DESC ? -1 : 1);
178 }
179 );
180
181 return $collection;
182 }
183
184 public function filter(callable $callback): CollectionInterface
185 {
186 $collection = clone $this;
187 $collection->data = array_merge([], array_filter($collection->data, $callback));
188
189 return $collection;
190 }
191
192 /**
193 * {@inheritdoc}
194 */
195 public function where(string $propertyOrMethod, $value): CollectionInterface
196 {
197 return $this->filter(function ($item) use ($propertyOrMethod, $value) {
198 /** @var mixed $accessorValue */
199 $accessorValue = $this->extractValue($item, $propertyOrMethod);
200
201 return $accessorValue === $value;
202 });
203 }
204
205 public function map(callable $callback): CollectionInterface
206 {
207 return new Collection('mixed', array_map($callback, $this->data));
208 }
209
210 public function diff(CollectionInterface $other): CollectionInterface
211 {
212 $this->compareCollectionTypes($other);
213
214 $diffAtoB = array_udiff($this->data, $other->toArray(), $this->getComparator());
215 $diffBtoA = array_udiff($other->toArray(), $this->data, $this->getComparator());
216
217 /** @var array<array-key, T> $diff */
218 $diff = array_merge($diffAtoB, $diffBtoA);
219
220 $collection = clone $this;
221 $collection->data = $diff;
222
223 return $collection;
224 }
225
226 public function intersect(CollectionInterface $other): CollectionInterface
227 {
228 $this->compareCollectionTypes($other);
229
230 /** @var array<array-key, T> $intersect */
231 $intersect = array_uintersect($this->data, $other->toArray(), $this->getComparator());
232
233 $collection = clone $this;
234 $collection->data = $intersect;
235
236 return $collection;
237 }
238
239 public function merge(CollectionInterface ...$collections): CollectionInterface
240 {
241 $temp = [$this->data];
242
243 foreach ($collections as $index => $collection) {
244 if (!$collection instanceof static) {
245 throw new CollectionMismatchException(
246 sprintf('Collection with index %d must be of type %s', $index, static::class)
247 );
248 }
249
250 // When using generics (Collection.php, Set.php, etc),
251 // we also need to make sure that the internal types match each other
252 if ($collection->getType() !== $this->getType()) {
253 throw new CollectionMismatchException(
254 sprintf('Collection items in collection with index %d must be of type %s', $index, $this->getType())
255 );
256 }
257
258 $temp[] = $collection->toArray();
259 }
260
261 $merge = array_merge(...$temp);
262
263 $collection = clone $this;
264 $collection->data = $merge;
265
266 return $collection;
267 }
268
269 /**
270 * @inheritDoc
271 */
272 public function unserialize($serialized): void
273 {
274 /** @var array<array-key, T> $data */
275 $data = unserialize($serialized, ['allowed_classes' => [$this->getType()]]);
276
277 $this->data = $data;
278 }
279
280 /**
281 * @param CollectionInterface<T> $other
282 */
283 private function compareCollectionTypes(CollectionInterface $other): void
284 {
285 if (!$other instanceof static) {
286 throw new CollectionMismatchException('Collection must be of type ' . static::class);
287 }
288
289 // When using generics (Collection.php, Set.php, etc),
290 // we also need to make sure that the internal types match each other
291 if ($other->getType() !== $this->getType()) {
292 throw new CollectionMismatchException('Collection items must be of type ' . $this->getType());
293 }
294 }
295
296 private function getComparator(): Closure
297 {
298 return /**
299 * @param T $a
300 * @param T $b
301 */
302 function ($a, $b): int {
303 // If the two values are object, we convert them to unique scalars.
304 // If the collection contains mixed values (unlikely) where some are objects
305 // and some are not, we leave them as they are.
306 // The comparator should still work and the result of $a < $b should
307 // be consistent but unpredictable since not documented.
308 if (is_object($a) && is_object($b)) {
309 $a = spl_object_id($a);
310 $b = spl_object_id($b);
311 }
312
313 return $a === $b ? 0 : ($a < $b ? 1 : -1);
314 };
315 }
316 }
317