From 4d232686860a4020c38ed12be38dabe51c352f79 Mon Sep 17 00:00:00 2001 From: Valithor Obsidion Date: Tue, 19 Nov 2024 15:49:17 -0500 Subject: [PATCH] Abstract Collection class into a Trait & Interface --- src/Discord/Helpers/Collection.php | 465 +------------------ src/Discord/Helpers/CollectionInterface.php | 51 +++ src/Discord/Helpers/CollectionTrait.php | 471 ++++++++++++++++++++ 3 files changed, 524 insertions(+), 463 deletions(-) create mode 100644 src/Discord/Helpers/CollectionInterface.php create mode 100644 src/Discord/Helpers/CollectionTrait.php diff --git a/src/Discord/Helpers/Collection.php b/src/Discord/Helpers/Collection.php index b1d631a53..8f92909ee 100644 --- a/src/Discord/Helpers/Collection.php +++ b/src/Discord/Helpers/Collection.php @@ -11,474 +11,13 @@ namespace Discord\Helpers; -use ArrayAccess; -use ArrayIterator; -use Countable; -use IteratorAggregate; -use JsonSerializable; -use Traversable; - /** * Collection of items. Inspired by Laravel Collections. * * @since 5.0.0 No longer extends Laravel's BaseCollection * @since 4.0.0 */ -class Collection implements ArrayAccess, JsonSerializable, IteratorAggregate, Countable +class Collection implements CollectionInterface { - /** - * The collection discriminator. - * - * @var ?string - */ - protected $discrim; - - /** - * The items contained in the collection. - * - * @var array - */ - protected $items; - - /** - * Class type allowed into the collection. - * - * @var string - */ - protected $class; - - /** - * Create a new collection. - * - * @param array $items - * @param ?string $discrim - * @param string|null $class - */ - public function __construct(array $items = [], ?string $discrim = 'id', ?string $class = null) - { - $this->items = $items; - $this->discrim = $discrim; - $this->class = $class; - } - - /** - * Creates a collection from an array. - * - * @param array $items - * @param ?string $discrim - * @param string|null $class - * - * @return static - */ - public static function from(array $items = [], ?string $discrim = 'id', ?string $class = null) - { - return new static($items, $discrim, $class); - } - - /** - * Creates a collection for a class. - * - * @param string $class - * @param ?string $discrim - * - * @return static - */ - public static function for(string $class, ?string $discrim = 'id') - { - return new static([], $discrim, $class); - } - - /** - * Gets an item from the collection. - * - * @param string $discrim - * @param mixed $key - * - * @return mixed - */ - public function get(string $discrim, $key) - { - if ($discrim == $this->discrim && isset($this->items[$key])) { - return $this->items[$key]; - } - - foreach ($this->items as $item) { - if (is_array($item) && isset($item[$discrim]) && $item[$discrim] == $key) { - return $item; - } elseif (is_object($item) && $item->{$discrim} == $key) { - return $item; - } - } - - return null; - } - - /** - * Sets a value in the collection. - * - * @param mixed $offset - * @param mixed $value - */ - public function set($offset, $value) - { - // Don't insert elements that are not of type class. - if (null !== $this->class && ! ($value instanceof $this->class)) { - return; - } - - $this->offsetSet($offset, $value); - } - - /** - * Pulls an item from the collection. - * - * @param mixed $key - * @param mixed $default - * - * @return mixed - */ - public function pull($key, $default = null) - { - if (isset($this->items[$key])) { - $default = $this->items[$key]; - unset($this->items[$key]); - } - - return $default; - } - - /** - * Fills an array of items into the collection. - * - * @param array $items - * - * @return Collection - */ - public function fill(array $items): Collection - { - foreach ($items as $item) { - $this->pushItem($item); - } - - return $this; - } - - /** - * Pushes items to the collection. - * - * @param mixed ...$items - * - * @return Collection - */ - public function push(...$items): Collection - { - foreach ($items as $item) { - $this->pushItem($item); - } - - return $this; - } - - /** - * Pushes a single item to the collection. - * - * @param mixed $item - * - * @return Collection - */ - public function pushItem($item): Collection - { - if (null === $this->discrim) { - $this->items[] = $item; - - return $this; - } - - if (null !== $this->class && ! ($item instanceof $this->class)) { - return $this; - } - - if (is_array($item)) { - $this->items[$item[$this->discrim]] = $item; - } elseif (is_object($item)) { - $this->items[$item->{$this->discrim}] = $item; - } - - return $this; - } - - /** - * Counts the amount of objects in the collection. - * - * @return int - */ - public function count(): int - { - return count($this->items); - } - - /** - * Returns the first element of the collection. - * - * @return mixed - */ - public function first() - { - foreach ($this->items as $item) { - return $item; - } - - return null; - } - - /** - * Returns the last element of the collection. - * - * @return mixed - */ - public function last() - { - $last = end($this->items); - - if ($last !== false) { - reset($this->items); - - return $last; - } - - return null; - } - - /** - * If the collection has an offset. - * - * @param mixed $offset - * - * @return bool - */ - public function isset($offset): bool - { - return $this->offsetExists($offset); - } - - /** - * Checks if the array has multiple offsets. - * - * @param string|int ...$keys - * - * @return bool - */ - public function has(...$keys): bool - { - foreach ($keys as $key) { - if (! isset($this->items[$key])) { - return false; - } - } - - return true; - } - - /** - * Runs a filter callback over the collection and returns a new collection - * based on the response of the callback. - * - * @param callable $callback - * - * @return Collection - */ - public function filter(callable $callback): Collection - { - $collection = new Collection([], $this->discrim, $this->class); - - foreach ($this->items as $item) { - if ($callback($item)) { - $collection->push($item); - } - } - - return $collection; - } - - /** - * Runs a filter callback over the collection and returns the first item - * where the callback returns `true` when given the item. - * - * @param callable $callback - * - * @return mixed `null` if no items returns `true` when called in the `$callback`. - */ - public function find(callable $callback) - { - foreach ($this->items as $item) { - if ($callback($item)) { - return $item; - } - } - - return null; - } - - /** - * Clears the collection. - */ - public function clear(): void - { - $this->items = []; - } - - /** - * Runs a callback over the collection and creates a new collection. - * - * @param callable $callback - * - * @return Collection - */ - public function map(callable $callback): Collection - { - $keys = array_keys($this->items); - $values = array_map($callback, array_values($this->items)); - - return new Collection(array_combine($keys, $values), $this->discrim, $this->class); - } - - /** - * Merges another collection into this collection. - * - * @param Collection $collection - * - * @return Collection - */ - public function merge(Collection $collection): Collection - { - $this->items = array_merge($this->items, $collection->toArray()); - - return $this; - } - - /** - * Converts the collection to an array. - * - * @return array - */ - public function toArray() - { - return $this->items; - } - - /** - * If the collection has an offset. - * - * @param mixed $offset - * - * @return bool - */ - public function offsetExists($offset): bool - { - return isset($this->items[$offset]); - } - - /** - * Gets an item from the collection. - * - * @param mixed $offset - * - * @return mixed - */ - #[\ReturnTypeWillChange] - public function offsetGet($offset) - { - return $this->items[$offset] ?? null; - } - - /** - * Sets an item into the collection. - * - * @param mixed $offset - * @param mixed $value - */ - public function offsetSet($offset, $value): void - { - $this->items[$offset] = $value; - } - - /** - * Unsets an index from the collection. - * - * @param mixed $offset - */ - public function offsetUnset($offset): void - { - unset($this->items[$offset]); - } - - /** - * Returns the string representation of the collection. - * - * @return string - */ - public function serialize(): string - { - return json_encode($this->items); - } - - /** - * Returns the string representation of the collection. - * - * @return array - */ - public function __serialize(): array - { - return $this->items; - } - - /** - * Unserializes the collection. - * - * @param string $serialized - */ - public function unserialize(string $serialized): void - { - $this->items = json_decode($serialized); - } - - /** - * Unserializes the collection. - * - * @param array $data - */ - public function __unserialize(array $data): void - { - $this->items = $data; - } - - /** - * Serializes the object to a value that can be serialized natively by json_encode(). - * - * @return array - */ - public function jsonSerialize(): array - { - return $this->items; - } - - /** - * Returns an iterator for the collection. - * - * @return Traversable - */ - public function getIterator(): Traversable - { - return new ArrayIterator($this->items); - } - - /** - * Returns an item that will be displayed for debugging. - * - * @return array - */ - public function __debugInfo(): array - { - return $this->items; - } + use CollectionTrait; } diff --git a/src/Discord/Helpers/CollectionInterface.php b/src/Discord/Helpers/CollectionInterface.php new file mode 100644 index 000000000..4be68808d --- /dev/null +++ b/src/Discord/Helpers/CollectionInterface.php @@ -0,0 +1,51 @@ + + * + * This file is subject to the MIT license that is bundled + * with this source code in the LICENSE.md file. + */ + +namespace Discord\Helpers; + +use ArrayAccess; +use Countable; +use IteratorAggregate; +use JsonSerializable; +use Traversable; + +interface CollectionInterface extends ArrayAccess, JsonSerializable, IteratorAggregate, Countable +{ + public function get(string $discrim, $key); + public function set($offset, $value); + public function pull($key, $default = null); + public function fill(array $items): static; + public function push(...$items): static; + public function pushItem($item): static; + public function count(): int; + public function first(); + public function last(); + public function isset($offset): bool; + public function has(...$keys): bool; + public function filter(callable $callback): static; + public function find(callable $callback); + public function clear(): void; + public function map(callable $callback): static; + public function merge(Collection $collection): static; + public function toArray(); + public function offsetExists($offset): bool; + #[\ReturnTypeWillChange] + public function offsetGet($offset); + public function offsetSet($offset, $value): void; + public function offsetUnset($offset): void; + public function serialize(): string; + public function __serialize(): array; + public function unserialize(string $serialized): void; + public function __unserialize(array $data): void; + public function jsonSerialize(): array; + public function getIterator(): Traversable; + public function __debugInfo(): array; +} diff --git a/src/Discord/Helpers/CollectionTrait.php b/src/Discord/Helpers/CollectionTrait.php new file mode 100644 index 000000000..46ff530df --- /dev/null +++ b/src/Discord/Helpers/CollectionTrait.php @@ -0,0 +1,471 @@ + + * + * This file is subject to the MIT license that is bundled + * with this source code in the LICENSE.md file. + */ + +namespace Discord\Helpers; + +trait CollectionTrait +{ + /** + * The collection discriminator. + * + * @var ?string + */ + protected $discrim; + + /** + * The items contained in the collection. + * + * @var array + */ + protected $items; + + /** + * Class type allowed into the collection. + * + * @var string + */ + protected $class; + + /** + * Create a new static. + * + * @param array $items + * @param ?string $discrim + * @param string|null $class + */ + public function __construct(array $items = [], ?string $discrim = 'id', ?string $class = null) + { + $this->items = $items; + $this->discrim = $discrim; + $this->class = $class; + } + + /** + * Creates a collection from an array. + * + * @param array $items + * @param ?string $discrim + * @param string|null $class + * + * @return static + */ + public static function from(array $items = [], ?string $discrim = 'id', ?string $class = null) + { + return new static($items, $discrim, $class); + } + + /** + * Creates a collection for a class. + * + * @param string $class + * @param ?string $discrim + * + * @return static + */ + public static function for(string $class, ?string $discrim = 'id') + { + return new static([], $discrim, $class); + } + + /** + * Gets an item from the collection. + * + * @param string $discrim + * @param mixed $key + * + * @return mixed + */ + public function get(string $discrim, $key) + { + if ($discrim == $this->discrim && isset($this->items[$key])) { + return $this->items[$key]; + } + + foreach ($this->items as $item) { + if (is_array($item) && isset($item[$discrim]) && $item[$discrim] == $key) { + return $item; + } elseif (is_object($item) && $item->{$discrim} == $key) { + return $item; + } + } + + return null; + } + + /** + * Sets a value in the collection. + * + * @param mixed $offset + * @param mixed $value + */ + public function set($offset, $value) + { + // Don't insert elements that are not of type class. + if (null !== $this->class && ! ($value instanceof $this->class)) { + return; + } + + $this->offsetSet($offset, $value); + } + + /** + * Pulls an item from the collection. + * + * @param mixed $key + * @param mixed $default + * + * @return mixed + */ + public function pull($key, $default = null) + { + if (isset($this->items[$key])) { + $default = $this->items[$key]; + unset($this->items[$key]); + } + + return $default; + } + + /** + * Fills an array of items into the collection. + * + * @param array $items + * + * @return static + */ + public function fill(array $items): static + { + foreach ($items as $item) { + $this->pushItem($item); + } + + return $this; + } + + /** + * Pushes items to the collection. + * + * @param mixed ...$items + * + * @return static + */ + public function push(...$items): static + { + foreach ($items as $item) { + $this->pushItem($item); + } + + return $this; + } + + /** + * Pushes a single item to the collection. + * + * @param mixed $item + * + * @return static + */ + public function pushItem($item): static + { + if (null === $this->discrim) { + $this->items[] = $item; + + return $this; + } + + if (null !== $this->class && ! ($item instanceof $this->class)) { + return $this; + } + + if (is_array($item)) { + $this->items[$item[$this->discrim]] = $item; + } elseif (is_object($item)) { + $this->items[$item->{$this->discrim}] = $item; + } + + return $this; + } + + /** + * Counts the amount of objects in the collection. + * + * @return int + */ + public function count(): int + { + return count($this->items); + } + + /** + * Returns the first element of the collection. + * + * @return mixed + */ + public function first() + { + foreach ($this->items as $item) { + return $item; + } + + return null; + } + + /** + * Returns the last element of the collection. + * + * @return mixed + */ + public function last() + { + $last = end($this->items); + + if ($last !== false) { + reset($this->items); + + return $last; + } + + return null; + } + + /** + * If the collection has an offset. + * + * @param mixed $offset + * + * @return bool + */ + public function isset($offset): bool + { + return $this->offsetExists($offset); + } + + /** + * Checks if the array has multiple offsets. + * + * @param string|int ...$keys + * + * @return bool + */ + public function has(...$keys): bool + { + foreach ($keys as $key) { + if (! isset($this->items[$key])) { + return false; + } + } + + return true; + } + + /** + * Runs a filter callback over the collection and returns a new static + * based on the response of the callback. + * + * @param callable $callback + * + * @return static + */ + public function filter(callable $callback): static + { + $collection = new static([], $this->discrim, $this->class); + + foreach ($this->items as $item) { + if ($callback($item)) { + $collection->push($item); + } + } + + return $collection; + } + + /** + * Runs a filter callback over the collection and returns the first item + * where the callback returns `true` when given the item. + * + * @param callable $callback + * + * @return mixed `null` if no items returns `true` when called in the `$callback`. + */ + public function find(callable $callback) + { + foreach ($this->items as $item) { + if ($callback($item)) { + return $item; + } + } + + return null; + } + + /** + * Clears the collection. + */ + public function clear(): void + { + $this->items = []; + } + + /** + * Runs a callback over the collection and creates a new static. + * + * @param callable $callback + * + * @return static + */ + public function map(callable $callback): static + { + $keys = array_keys($this->items); + $values = array_map($callback, array_values($this->items)); + + return new static(array_combine($keys, $values), $this->discrim, $this->class); + } + + /** + * Merges another collection into this collection. + * + * @param Collection $collection + * + * @return static + */ + public function merge(Collection $collection): static + { + $this->items = array_merge($this->items, $collection->toArray()); + + return $this; + } + + /** + * Converts the collection to an array. + * + * @return array + */ + public function toArray() + { + return $this->items; + } + + /** + * If the collection has an offset. + * + * @param mixed $offset + * + * @return bool + */ + public function offsetExists($offset): bool + { + return isset($this->items[$offset]); + } + + /** + * Gets an item from the collection. + * + * @param mixed $offset + * + * @return mixed + */ + #[\ReturnTypeWillChange] + public function offsetGet($offset) + { + return $this->items[$offset] ?? null; + } + + /** + * Sets an item into the collection. + * + * @param mixed $offset + * @param mixed $value + */ + public function offsetSet($offset, $value): void + { + $this->items[$offset] = $value; + } + + /** + * Unsets an index from the collection. + * + * @param mixed $offset + */ + public function offsetUnset($offset): void + { + unset($this->items[$offset]); + } + + /** + * Returns the string representation of the collection. + * + * @return string + */ + public function serialize(): string + { + return json_encode($this->items); + } + + /** + * Returns the string representation of the collection. + * + * @return array + */ + public function __serialize(): array + { + return $this->items; + } + + /** + * Unserializes the collection. + * + * @param string $serialized + */ + public function unserialize(string $serialized): void + { + $this->items = json_decode($serialized); + } + + /** + * Unserializes the collection. + * + * @param array $data + */ + public function __unserialize(array $data): void + { + $this->items = $data; + } + + /** + * Serializes the object to a value that can be serialized natively by json_encode(). + * + * @return array + */ + public function jsonSerialize(): array + { + return $this->items; + } + + /** + * Returns an iterator for the collection. + * + * @return \Traversable + */ + public function getIterator(): \Traversable + { + return new \ArrayIterator($this->items); + } + + /** + * Returns an item that will be displayed for debugging. + * + * @return array + */ + public function __debugInfo(): array + { + return $this->items; + } +}