PluginProbe
Media Cloud Sync / 1.0.3
Media Cloud Sync v1.0.3
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 1.3.0 All 34 releases
media-cloud-sync / includes / sdk / google / ramsey / collection / src / AbstractCollection.php

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

272 lines 9.2 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\Ramsey\Collection;
14
15 use Closure;
16 use Dudlewebs\WPMCS\Ramsey\Collection\Exception\CollectionMismatchException;
17 use Dudlewebs\WPMCS\Ramsey\Collection\Exception\InvalidArgumentException;
18 use Dudlewebs\WPMCS\Ramsey\Collection\Exception\InvalidSortOrderException;
19 use Dudlewebs\WPMCS\Ramsey\Collection\Exception\OutOfBoundsException;
20 use Dudlewebs\WPMCS\Ramsey\Collection\Tool\TypeTrait;
21 use Dudlewebs\WPMCS\Ramsey\Collection\Tool\ValueExtractorTrait;
22 use Dudlewebs\WPMCS\Ramsey\Collection\Tool\ValueToStringTrait;
23 use function array_filter;
24 use function array_map;
25 use function array_merge;
26 use function array_search;
27 use function array_udiff;
28 use function array_uintersect;
29 use function current;
30 use function end;
31 use function in_array;
32 use function is_int;
33 use function is_object;
34 use function reset;
35 use function spl_object_id;
36 use function sprintf;
37 use function unserialize;
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 * @inheritDoc
54 */
55 public function add($element): bool
56 {
57 $this[] = $element;
58 return \true;
59 }
60 /**
61 * @inheritDoc
62 */
63 public function contains($element, bool $strict = \true): bool
64 {
65 return in_array($element, $this->data, $strict);
66 }
67 /**
68 * @inheritDoc
69 */
70 public function offsetSet($offset, $value): void
71 {
72 if ($this->checkType($this->getType(), $value) === \false) {
73 throw new InvalidArgumentException('Value must be of type ' . $this->getType() . '; value is ' . $this->toolValueToString($value));
74 }
75 if ($offset === null) {
76 $this->data[] = $value;
77 } else {
78 $this->data[$offset] = $value;
79 }
80 }
81 /**
82 * @inheritDoc
83 */
84 public function remove($element): bool
85 {
86 if (($position = array_search($element, $this->data, \true)) !== \false) {
87 unset($this[$position]);
88 return \true;
89 }
90 return \false;
91 }
92 /**
93 * @inheritDoc
94 */
95 public function column(string $propertyOrMethod): array
96 {
97 $temp = [];
98 foreach ($this->data as $item) {
99 /** @var mixed $value */
100 $value = $this->extractValue($item, $propertyOrMethod);
101 /** @psalm-suppress MixedAssignment */
102 $temp[] = $value;
103 }
104 return $temp;
105 }
106 /**
107 * @inheritDoc
108 */
109 public function first()
110 {
111 if ($this->isEmpty()) {
112 throw new OutOfBoundsException('Can\'t determine first item. Collection is empty');
113 }
114 reset($this->data);
115 /** @var T $first */
116 $first = current($this->data);
117 return $first;
118 }
119 /**
120 * @inheritDoc
121 */
122 public function last()
123 {
124 if ($this->isEmpty()) {
125 throw new OutOfBoundsException('Can\'t determine last item. Collection is empty');
126 }
127 /** @var T $item */
128 $item = end($this->data);
129 reset($this->data);
130 return $item;
131 }
132 public function sort(string $propertyOrMethod, string $order = self::SORT_ASC): CollectionInterface
133 {
134 if (!in_array($order, [self::SORT_ASC, self::SORT_DESC], \true)) {
135 throw new InvalidSortOrderException('Invalid sort order given: ' . $order);
136 }
137 $collection = clone $this;
138 usort(
139 $collection->data,
140 /**
141 * @param T $a
142 * @param T $b
143 */
144 function ($a, $b) use ($propertyOrMethod, $order): int {
145 /** @var mixed $aValue */
146 $aValue = $this->extractValue($a, $propertyOrMethod);
147 /** @var mixed $bValue */
148 $bValue = $this->extractValue($b, $propertyOrMethod);
149 return ($aValue <=> $bValue) * ($order === self::SORT_DESC ? -1 : 1);
150 }
151 );
152 return $collection;
153 }
154 public function filter(callable $callback): CollectionInterface
155 {
156 $collection = clone $this;
157 $collection->data = array_merge([], array_filter($collection->data, $callback));
158 return $collection;
159 }
160 /**
161 * {@inheritdoc}
162 */
163 public function where(string $propertyOrMethod, $value): CollectionInterface
164 {
165 return $this->filter(function ($item) use ($propertyOrMethod, $value) {
166 /** @var mixed $accessorValue */
167 $accessorValue = $this->extractValue($item, $propertyOrMethod);
168 return $accessorValue === $value;
169 });
170 }
171 public function map(callable $callback): CollectionInterface
172 {
173 return new Collection('mixed', array_map($callback, $this->data));
174 }
175 public function diff(CollectionInterface $other): CollectionInterface
176 {
177 $this->compareCollectionTypes($other);
178 $diffAtoB = array_udiff($this->data, $other->toArray(), $this->getComparator());
179 $diffBtoA = array_udiff($other->toArray(), $this->data, $this->getComparator());
180 /** @var array<array-key, T> $diff */
181 $diff = array_merge($diffAtoB, $diffBtoA);
182 $collection = clone $this;
183 $collection->data = $diff;
184 return $collection;
185 }
186 public function intersect(CollectionInterface $other): CollectionInterface
187 {
188 $this->compareCollectionTypes($other);
189 /** @var array<array-key, T> $intersect */
190 $intersect = array_uintersect($this->data, $other->toArray(), $this->getComparator());
191 $collection = clone $this;
192 $collection->data = $intersect;
193 return $collection;
194 }
195 public function merge(CollectionInterface ...$collections): CollectionInterface
196 {
197 $mergedCollection = clone $this;
198 foreach ($collections as $index => $collection) {
199 if (!$collection instanceof static) {
200 throw new CollectionMismatchException(sprintf('Collection with index %d must be of type %s', $index, static::class));
201 }
202 // When using generics (Collection.php, Set.php, etc),
203 // we also need to make sure that the internal types match each other
204 if ($this->getUniformType($collection) !== $this->getUniformType($this)) {
205 throw new CollectionMismatchException(sprintf('Collection items in collection with index %d must be of type %s', $index, $this->getType()));
206 }
207 foreach ($collection as $key => $value) {
208 if (is_int($key)) {
209 $mergedCollection[] = $value;
210 } else {
211 $mergedCollection[$key] = $value;
212 }
213 }
214 }
215 return $mergedCollection;
216 }
217 /**
218 * @inheritDoc
219 */
220 public function unserialize($serialized): void
221 {
222 /** @var array<array-key, T> $data */
223 $data = unserialize($serialized, ['allowed_classes' => [$this->getType()]]);
224 $this->data = $data;
225 }
226 /**
227 * @param CollectionInterface<T> $other
228 */
229 private function compareCollectionTypes(CollectionInterface $other): void
230 {
231 if (!$other instanceof static) {
232 throw new CollectionMismatchException('Collection must be of type ' . static::class);
233 }
234 // When using generics (Collection.php, Set.php, etc),
235 // we also need to make sure that the internal types match each other
236 if ($this->getUniformType($other) !== $this->getUniformType($this)) {
237 throw new CollectionMismatchException('Collection items must be of type ' . $this->getType());
238 }
239 }
240 private function getComparator(): Closure
241 {
242 return function ($a, $b): int {
243 // If the two values are object, we convert them to unique scalars.
244 // If the collection contains mixed values (unlikely) where some are objects
245 // and some are not, we leave them as they are.
246 // The comparator should still work and the result of $a < $b should
247 // be consistent but unpredictable since not documented.
248 if (is_object($a) && is_object($b)) {
249 $a = spl_object_id($a);
250 $b = spl_object_id($b);
251 }
252 return $a === $b ? 0 : ($a < $b ? 1 : -1);
253 };
254 }
255 /**
256 * @param CollectionInterface<mixed> $collection
257 */
258 private function getUniformType(CollectionInterface $collection): string
259 {
260 switch ($collection->getType()) {
261 case 'integer':
262 return 'int';
263 case 'boolean':
264 return 'bool';
265 case 'double':
266 return 'float';
267 default:
268 return $collection->getType();
269 }
270 }
271 }
272