PluginProbe
Media Cloud Sync / 1.4.1
Media Cloud Sync v1.4.1
1.4.1 1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 All 35 releases
media-cloud-sync / includes / sdk / google / ramsey / collection / src / AbstractCollection.php

AbstractCollection.php in Media Cloud Sync 1.4.1, at includes/sdk/google/ramsey/collection/src/AbstractCollection.php

303 lines 10.9 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 <ben@benramsey.com>
10 * @license http://opensource.org/licenses/MIT MIT
11 */
12 declare (strict_types=1);
13 namespace Dudlewebs\WPMCS\GCP\Ramsey\Collection;
14
15 use Closure;
16 use Dudlewebs\WPMCS\GCP\Ramsey\Collection\Exception\CollectionMismatchException;
17 use Dudlewebs\WPMCS\GCP\Ramsey\Collection\Exception\InvalidArgumentException;
18 use Dudlewebs\WPMCS\GCP\Ramsey\Collection\Exception\InvalidPropertyOrMethod;
19 use Dudlewebs\WPMCS\GCP\Ramsey\Collection\Exception\NoSuchElementException;
20 use Dudlewebs\WPMCS\GCP\Ramsey\Collection\Exception\UnsupportedOperationException;
21 use Dudlewebs\WPMCS\GCP\Ramsey\Collection\Tool\TypeTrait;
22 use Dudlewebs\WPMCS\GCP\Ramsey\Collection\Tool\ValueExtractorTrait;
23 use Dudlewebs\WPMCS\GCP\Ramsey\Collection\Tool\ValueToStringTrait;
24 use function array_filter;
25 use function array_key_first;
26 use function array_key_last;
27 use function array_map;
28 use function array_merge;
29 use function array_reduce;
30 use function array_search;
31 use function array_udiff;
32 use function array_uintersect;
33 use function in_array;
34 use function is_int;
35 use function is_object;
36 use function spl_object_id;
37 use function sprintf;
38 use function usort;
39 /**
40 * This class provides a basic implementation of `CollectionInterface`, to
41 * minimize the effort required to implement this interface
42 *
43 * @template T
44 * @extends AbstractArray<T>
45 * @implements CollectionInterface<T>
46 */
47 abstract class AbstractCollection extends AbstractArray implements CollectionInterface
48 {
49 use TypeTrait;
50 use ValueToStringTrait;
51 use ValueExtractorTrait;
52 /**
53 * @throws InvalidArgumentException if $element is of the wrong type.
54 */
55 public function add(mixed $element) : bool
56 {
57 $this[] = $element;
58 return \true;
59 }
60 public function contains(mixed $element, bool $strict = \true) : bool
61 {
62 return in_array($element, $this->data, $strict);
63 }
64 /**
65 * @throws InvalidArgumentException if $element is of the wrong type.
66 */
67 public function offsetSet(mixed $offset, mixed $value) : void
68 {
69 if ($this->checkType($this->getType(), $value) === \false) {
70 throw new InvalidArgumentException('Value must be of type ' . $this->getType() . '; value is ' . $this->toolValueToString($value));
71 }
72 if ($offset === null) {
73 $this->data[] = $value;
74 } else {
75 $this->data[$offset] = $value;
76 }
77 }
78 public function remove(mixed $element) : bool
79 {
80 if (($position = array_search($element, $this->data, \true)) !== \false) {
81 unset($this[$position]);
82 return \true;
83 }
84 return \false;
85 }
86 /**
87 * @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist
88 * on the elements in this collection.
89 * @throws UnsupportedOperationException if unable to call column() on this
90 * collection.
91 *
92 * @inheritDoc
93 */
94 public function column(string $propertyOrMethod) : array
95 {
96 $temp = [];
97 foreach ($this->data as $item) {
98 $temp[] = $this->extractValue($item, $propertyOrMethod);
99 }
100 return $temp;
101 }
102 /**
103 * @return T
104 *
105 * @throws NoSuchElementException if this collection is empty.
106 */
107 public function first() : mixed
108 {
109 $firstIndex = array_key_first($this->data);
110 if ($firstIndex === null) {
111 throw new NoSuchElementException('Can\'t determine first item. Collection is empty');
112 }
113 return $this->data[$firstIndex];
114 }
115 /**
116 * @return T
117 *
118 * @throws NoSuchElementException if this collection is empty.
119 */
120 public function last() : mixed
121 {
122 $lastIndex = array_key_last($this->data);
123 if ($lastIndex === null) {
124 throw new NoSuchElementException('Can\'t determine last item. Collection is empty');
125 }
126 return $this->data[$lastIndex];
127 }
128 /**
129 * @return CollectionInterface<T>
130 *
131 * @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist
132 * on the elements in this collection.
133 * @throws UnsupportedOperationException if unable to call sort() on this
134 * collection.
135 */
136 public function sort(?string $propertyOrMethod = null, Sort $order = Sort::Ascending) : CollectionInterface
137 {
138 $collection = clone $this;
139 usort($collection->data, function (mixed $a, mixed $b) use($propertyOrMethod, $order) : int {
140 $aValue = $this->extractValue($a, $propertyOrMethod);
141 $bValue = $this->extractValue($b, $propertyOrMethod);
142 return ($aValue <=> $bValue) * ($order === Sort::Descending ? -1 : 1);
143 });
144 return $collection;
145 }
146 /**
147 * @param callable(T): bool $callback A callable to use for filtering elements.
148 *
149 * @return CollectionInterface<T>
150 */
151 public function filter(callable $callback) : CollectionInterface
152 {
153 $collection = clone $this;
154 $collection->data = array_merge([], array_filter($collection->data, $callback));
155 return $collection;
156 }
157 /**
158 * @return CollectionInterface<T>
159 *
160 * @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist
161 * on the elements in this collection.
162 * @throws UnsupportedOperationException if unable to call where() on this
163 * collection.
164 */
165 public function where(?string $propertyOrMethod, mixed $value) : CollectionInterface
166 {
167 return $this->filter(fn(mixed $item): bool => $this->extractValue($item, $propertyOrMethod) === $value);
168 }
169 /**
170 * @param callable(T): TCallbackReturn $callback A callable to apply to each
171 * item of the collection.
172 *
173 * @return CollectionInterface<TCallbackReturn>
174 *
175 * @template TCallbackReturn
176 */
177 public function map(callable $callback) : CollectionInterface
178 {
179 return new Collection('mixed', array_map($callback, $this->data));
180 }
181 /**
182 * @param callable(TCarry, T): TCarry $callback A callable to apply to each
183 * item of the collection to reduce it to a single value.
184 * @param TCarry $initial This is the initial value provided to the callback.
185 *
186 * @return TCarry
187 *
188 * @template TCarry
189 */
190 public function reduce(callable $callback, mixed $initial) : mixed
191 {
192 return array_reduce($this->data, $callback, $initial);
193 }
194 /**
195 * @param CollectionInterface<T> $other The collection to check for divergent
196 * items.
197 *
198 * @return CollectionInterface<T>
199 *
200 * @throws CollectionMismatchException if the compared collections are of
201 * differing types.
202 */
203 public function diff(CollectionInterface $other) : CollectionInterface
204 {
205 $this->compareCollectionTypes($other);
206 $diffAtoB = array_udiff($this->data, $other->toArray(), $this->getComparator());
207 $diffBtoA = array_udiff($other->toArray(), $this->data, $this->getComparator());
208 $collection = clone $this;
209 $collection->data = array_merge($diffAtoB, $diffBtoA);
210 return $collection;
211 }
212 /**
213 * @param CollectionInterface<T> $other The collection to check for
214 * intersecting items.
215 *
216 * @return CollectionInterface<T>
217 *
218 * @throws CollectionMismatchException if the compared collections are of
219 * differing types.
220 */
221 public function intersect(CollectionInterface $other) : CollectionInterface
222 {
223 $this->compareCollectionTypes($other);
224 $collection = clone $this;
225 $collection->data = array_uintersect($this->data, $other->toArray(), $this->getComparator());
226 return $collection;
227 }
228 /**
229 * @param CollectionInterface<T> ...$collections The collections to merge.
230 *
231 * @return CollectionInterface<T>
232 *
233 * @throws CollectionMismatchException if unable to merge any of the given
234 * collections or items within the given collections due to type
235 * mismatch errors.
236 */
237 public function merge(CollectionInterface ...$collections) : CollectionInterface
238 {
239 $mergedCollection = clone $this;
240 foreach ($collections as $index => $collection) {
241 if (!$collection instanceof static) {
242 throw new CollectionMismatchException(sprintf('Collection with index %d must be of type %s', $index, static::class));
243 }
244 // When using generics (Collection.php, Set.php, etc),
245 // we also need to make sure that the internal types match each other
246 if ($this->getUniformType($collection) !== $this->getUniformType($this)) {
247 throw new CollectionMismatchException(sprintf('Collection items in collection with index %d must be of type %s', $index, $this->getType()));
248 }
249 foreach ($collection as $key => $value) {
250 if (is_int($key)) {
251 $mergedCollection[] = $value;
252 } else {
253 $mergedCollection[$key] = $value;
254 }
255 }
256 }
257 return $mergedCollection;
258 }
259 /**
260 * @param CollectionInterface<T> $other
261 *
262 * @throws CollectionMismatchException
263 */
264 private function compareCollectionTypes(CollectionInterface $other) : void
265 {
266 if (!$other instanceof static) {
267 throw new CollectionMismatchException('Collection must be of type ' . static::class);
268 }
269 // When using generics (Collection.php, Set.php, etc),
270 // we also need to make sure that the internal types match each other
271 if ($this->getUniformType($other) !== $this->getUniformType($this)) {
272 throw new CollectionMismatchException('Collection items must be of type ' . $this->getType());
273 }
274 }
275 private function getComparator() : Closure
276 {
277 return function (mixed $a, mixed $b) : int {
278 // If the two values are object, we convert them to unique scalars.
279 // If the collection contains mixed values (unlikely) where some are objects
280 // and some are not, we leave them as they are.
281 // The comparator should still work and the result of $a < $b should
282 // be consistent but unpredictable since not documented.
283 if (is_object($a) && is_object($b)) {
284 $a = spl_object_id($a);
285 $b = spl_object_id($b);
286 }
287 return $a === $b ? 0 : ($a < $b ? 1 : -1);
288 };
289 }
290 /**
291 * @param CollectionInterface<mixed> $collection
292 */
293 private function getUniformType(CollectionInterface $collection) : string
294 {
295 return match ($collection->getType()) {
296 'integer' => 'int',
297 'boolean' => 'bool',
298 'double' => 'float',
299 default => $collection->getType(),
300 };
301 }
302 }
303