From 62cb15e8810d90d2675bcaf4933c57fa1014da37 Mon Sep 17 00:00:00 2001 From: Valithor Obsidion Date: Tue, 24 Dec 2024 11:10:57 -0500 Subject: [PATCH 01/14] (BC) Separation of AbstractRepository into Trait and Interface (#1269) --- src/Discord/Repository/AbstractRepository.php | 719 +--------------- .../AbstractRepositoryInterface.php | 64 ++ .../Repository/AbstractRepositoryTrait.php | 802 ++++++++++++++++++ 3 files changed, 868 insertions(+), 717 deletions(-) create mode 100644 src/Discord/Repository/AbstractRepositoryInterface.php create mode 100644 src/Discord/Repository/AbstractRepositoryTrait.php diff --git a/src/Discord/Repository/AbstractRepository.php b/src/Discord/Repository/AbstractRepository.php index bf526514c..e6dd14dd9 100755 --- a/src/Discord/Repository/AbstractRepository.php +++ b/src/Discord/Repository/AbstractRepository.php @@ -11,21 +11,8 @@ namespace Discord\Repository; -use Discord\Discord; -use Discord\Factory\Factory; use Discord\Helpers\CacheWrapper; use Discord\Helpers\Collection; -use Discord\Helpers\LegacyCacheWrapper; -use Discord\Http\Endpoint; -use Discord\Http\Http; -use Discord\Parts\Part; -use React\Promise\PromiseInterface; -use Traversable; -use WeakReference; - -use function Discord\nowait; -use function React\Promise\reject; -use function React\Promise\resolve; /** * Repositories provide a way to store and update parts on the Discord server. @@ -40,707 +27,5 @@ */ abstract class AbstractRepository extends Collection { - /** - * The discriminator. - * - * @var string Discriminator. - */ - protected $discrim = 'id'; - - /** - * The HTTP client. - * - * @var Http Client. - */ - protected $http; - - /** - * The parts factory. - * - * @var Factory Parts factory. - */ - protected $factory; - - /** - * Endpoints for interacting with the Discord servers. - * - * @var array Endpoints. - */ - protected $endpoints = []; - - /** - * Variables that are related to the repository. - * - * @var array Variables. - */ - protected $vars = []; - - /** - * @var CacheWrapper - */ - protected $cache; - - /** - * AbstractRepository constructor. - * - * @param Discord $discord - * @param array $vars An array of variables used for the endpoint. - */ - public function __construct(Discord $discord, array $vars = []) - { - $this->http = $discord->getHttpClient(); - $this->factory = $discord->getFactory(); - $this->vars = $vars; - if ($cacheConfig = $discord->getCacheConfig(static::class)) { - $this->cache = new CacheWrapper($discord, $cacheConfig, $this->items, $this->class, $this->vars); - } else { - $this->cache = new LegacyCacheWrapper($discord, $this->items, $this->class); - } - - parent::__construct([], $this->discrim, $this->class); - } - - /** - * Freshens the repository cache. - * - * @param array $queryparams Query string params to add to the request (no validation) - * - * @return PromiseInterface - * - * @throws \Exception - */ - public function freshen(array $queryparams = []): PromiseInterface - { - if (! isset($this->endpoints['all'])) { - return reject(new \Exception('You cannot freshen this repository.')); - } - - $endpoint = new Endpoint($this->endpoints['all']); - $endpoint->bindAssoc($this->vars); - - foreach ($queryparams as $query => $param) { - $endpoint->addQuery($query, $param); - } - - return $this->http->get($endpoint)->then(function ($response) { - foreach ($this->items as $offset => $value) { - if ($value === null) { - unset($this->items[$offset]); - } elseif (! ($this->items[$offset] instanceof WeakReference)) { - $this->items[$offset] = WeakReference::create($value); - } - $this->cache->delete($offset); - } - - return $this->cacheFreshen($response); - }); - } - - /** - * @param object $response - * - * @return PromiseInterface - */ - protected function cacheFreshen($response): PromiseInterface - { - foreach ($response as $value) { - $value = array_merge($this->vars, (array) $value); - $part = $this->factory->create($this->class, $value, true); - $items[$part->{$this->discrim}] = $part; - } - - if (empty($items)) { - return resolve($this); - } - - return $this->cache->setMultiple($items)->then(fn ($success) => $this); - } - - /** - * Builds a new, empty part. - * - * @param array|object $attributes The attributes for the new part. - * @param bool $created - * - * @return Part The new part. - * - * @throws \Exception - */ - public function create(array|object $attributes = [], bool $created = false): Part - { - $attributes = array_merge((array) $attributes, $this->vars); - - return $this->factory->part($this->class, $attributes, $created); - } - - /** - * Attempts to save a part to the Discord servers. - * - * @param Part $part The part to save. - * @param string|null $reason Reason for Audit Log (if supported). - * - * @return PromiseInterface - * - * @throws \Exception - */ - public function save(Part $part, ?string $reason = null): PromiseInterface - { - if ($part->created) { - if (! isset($this->endpoints['update'])) { - return reject(new \Exception('You cannot update this part.')); - } - - $method = 'patch'; - $endpoint = new Endpoint($this->endpoints['update']); - $endpoint->bindAssoc(array_merge($part->getRepositoryAttributes(), $this->vars)); - $attributes = $part->getUpdatableAttributes(); - } else { - if (! isset($this->endpoints['create'])) { - return reject(new \Exception('You cannot create this part.')); - } - - $method = 'post'; - $endpoint = new Endpoint($this->endpoints['create']); - $endpoint->bindAssoc(array_merge($part->getRepositoryAttributes(), $this->vars)); - $attributes = $part->getCreatableAttributes(); - } - - $headers = []; - if (isset($reason)) { - $headers['X-Audit-Log-Reason'] = $reason; - } - - return $this->http->{$method}($endpoint, $attributes, $headers)->then(function ($response) use ($method, $part) { - switch ($method) { - case 'patch': // Update old part - $part->fill((array) $response); - $part->created = true; - return $this->cache->set($part->{$this->discrim}, $part)->then(fn ($success) => $part); - default: // Create new part - $newPart = $this->factory->create($this->class, (array) $response, true); - $newPart->created = true; - return $this->cache->set($newPart->{$this->discrim}, $this->factory->create($this->class, (array) $response, true))->then(fn ($success) => $newPart); - } - }); - } - - /** - * Attempts to delete a part on the Discord servers. - * - * @param Part|string $part The part to delete. - * @param string|null $reason Reason for Audit Log (if supported). - * - * @return PromiseInterface - * - * @throws \Exception - */ - public function delete($part, ?string $reason = null): PromiseInterface - { - if (! isset($part)) { - return reject(new \Exception('You cannot delete a non-existent part.')); - } - - if (! ($part instanceof Part)) { - $part = $this->factory->part($this->class, [$this->discrim => $part], true); - } - - if (! $part->created) { - return reject(new \Exception('You cannot delete a non-existent part.')); - } - - if (! isset($this->endpoints['delete'])) { - return reject(new \Exception('You cannot delete this part.')); - } - - $endpoint = new Endpoint($this->endpoints['delete']); - $endpoint->bindAssoc(array_merge($part->getRepositoryAttributes(), $this->vars)); - - $headers = []; - if (isset($reason)) { - $headers['X-Audit-Log-Reason'] = $reason; - } - - return $this->http->delete($endpoint, null, $headers)->then(function ($response) use (&$part) { - if ($response) { - $part->fill((array) $response); - } - $part->created = false; - - return $this->cache->delete($part->{$this->discrim})->then(fn ($success) => $part); - }); - } - - /** - * Returns a part with fresh values. - * - * @param Part $part The part to get fresh values. - * @param array $queryparams Query string params to add to the request (no validation) - * - * @return PromiseInterface - * - * @throws \Exception - */ - public function fresh(Part $part, array $queryparams = []): PromiseInterface - { - if (! $part->created) { - return reject(new \Exception('You cannot get a non-existent part.')); - } - - if (! isset($this->endpoints['get'])) { - return reject(new \Exception('You cannot get this part.')); - } - - $endpoint = new Endpoint($this->endpoints['get']); - $endpoint->bindAssoc(array_merge($part->getRepositoryAttributes(), $this->vars)); - - foreach ($queryparams as $query => $param) { - $endpoint->addQuery($query, $param); - } - - return $this->http->get($endpoint)->then(function ($response) use (&$part) { - $part->fill((array) $response); - - return $this->cache->set($part->{$this->discrim}, $part)->then(fn ($success) => $part); - }); - } - - /** - * Gets a part from the repository or Discord servers. - * - * @param string $id The ID to search for. - * @param bool $fresh Whether we should skip checking the cache. - * - * @throws \Exception - * - * @return PromiseInterface - */ - public function fetch(string $id, bool $fresh = false): PromiseInterface - { - if (! $fresh) { - if (isset($this->items[$id])) { - $part = $this->items[$id]; - if ($part instanceof WeakReference) { - $part = $part->get(); - } - - if ($part) { - $this->items[$id] = $part; - - return resolve($part); - } - } else { - return $this->cache->get($id)->then(function ($part) use ($id) { - if ($part === null) { - return $this->fetch($id, true); - } - - return $part; - }); - } - } - - if (! isset($this->endpoints['get'])) { - return reject(new \Exception('You cannot get this part.')); - } - - $part = $this->factory->part($this->class, [$this->discrim => $id]); - $endpoint = new Endpoint($this->endpoints['get']); - $endpoint->bindAssoc(array_merge($part->getRepositoryAttributes(), $this->vars)); - - return $this->http->get($endpoint)->then(function ($response) use ($part, $id) { - $part->created = true; - $part->fill(array_merge($this->vars, (array) $response)); - - return $this->cache->set($id, $part)->then(fn ($success) => $part); - }); - } - - /** - * Gets a part from the repository. - * - * @param string $discrim - * @param mixed $key - * - * @return Part|null - */ - public function get(string $discrim, $key) - { - if ($key === null) { - return null; - } - - if ($discrim == $this->discrim) { - if ($item = $this->offsetGet($key)) { - return $item; - } - - // Attempt to get resolved value if promise is resolved without waiting - return nowait($this->cache->get($key)); - } - - foreach ($this->items as $offset => $item) { - if ($item = $this->offsetGet($offset)) { - if ($item->{$discrim} == $key) { - return $item; - } - continue; - } - - $resolved = nowait($this->cache->get($offset)); - if ($resolved !== null) { - return $resolved; - } - break; - } - - return null; - } - - /** - * Attempts to get from memory first otherwise load from cache. - * - * @internal - * - * @param string|int $offset - * - * @return PromiseInterface - */ - public function cacheGet($offset): PromiseInterface - { - return resolve($this->offsetGet($offset) ?? $this->cache->get($offset)); - } - - /** - * Sets a part in the repository. - * - * @param string|int $offset - * @param Part $value - */ - public function set($offset, $value) - { - // Don't insert elements that are not of type class. - if (! is_a($value, $this->class)) { - return; - } - - $this->cache->set($offset, $value); - $this->items[$offset] = $value; - } - - /** - * Pulls a part from the repository. - * - * @deprecated 10.0.0 Use async `$repository->cachePull()` - * - * @param string|int $key - * @param mixed $default - * - * @return Part|mixed - */ - public function pull($key, $default = null) - { - if ($item = $this->offsetGet($key)) { - $default = $item; - unset($this->items[$key]); - $this->cache->delete($key); - } - - return $default; - } - - /** - * Pulls an item from cache. - * - * @internal - * - * @param string|int $key - * @param ?Part $default - * - * @return PromiseInterface - */ - public function cachePull($key, $default = null): PromiseInterface - { - return $this->cacheGet($key)->then(fn ($item) => ($item === null) ? $default : $this->cache->delete($key)->then(fn ($success) => $item)); - } - - /** - * Pushes a single item to the repository. - * - * @deprecated 10.0.0 Use async `$repository->cache->set()` - * This method is deprecated for userland code but can still be used internally within the library. - * - * @param Part $item - * - * @return $this - */ - public function pushItem($item): self - { - if (is_a($item, $this->class)) { - $key = $item->{$this->discrim}; - $this->items[$key] = $item; - $this->cache->set($key, $item); - } - - return $this; - } - - /** - * Returns the first cached part. - * - * @return Part|null - */ - public function first() - { - foreach ($this->items as $offset => $item) { - if ($item instanceof WeakReference) { - if (! $item = $item->get()) { - // Attempt to get resolved value if promise is resolved without waiting - $item = nowait($this->cache->get($offset)); - } - } - - if ($item) { - return $item; - } - } - - return null; - } - - /** - * Returns the last cached part. - * - * @return Part|null - */ - public function last() - { - $items = array_reverse($this->items, true); - - foreach ($items as $offset => $item) { - if ($item instanceof WeakReference) { - if (! $item = $item->get()) { - // Attempt to get resolved value if promise is resolved without waiting - $item = nowait($this->cache->get($offset)); - } - } - - if ($item) { - return $item; - } - } - - return null; - } - - /** - * Checks if the array has an object. - * - * @deprecated 10.0.0 Use async `$repository->cache->has()` - * - * @param string|int ...$keys - * - * @return bool - */ - public function has(...$keys): bool - { - foreach ($keys as $key) { - if (! isset($this->items[$key]) || nowait($this->cache->has($key)) === false) { - return false; - } - } - - return true; - } - - /** - * Runs a filter callback over the repository 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 $offset => $item) { - if ($item instanceof WeakReference) { - if (! $item = $item->get()) { - // Attempt to get resolved value if promise is resolved without waiting - $item = nowait($this->cache->get($offset)); - } - } - - if ($item === null) { - continue; - } - - if ($callback($item)) { - $collection->push($item); - } - } - - return $collection; - } - - /** - * Runs a filter callback over the repository and returns the first part - * where the callback returns `true` when given the part. - * - * @param callable $callback - * - * @return Part|null `null` if no items returns `true` when called in the callback. - */ - public function find(callable $callback) - { - foreach ($this->getIterator() as $item) { - if ($item === null) { - continue; - } - - if ($callback($item)) { - return $item; - } - } - - return null; - } - - /** - * Clears the repository. - * - * @deprecated 10.0.0 Use async `$repository->cache->clear()` - */ - public function clear(): void - { - // Set items null but keep the keys to be removed on prune - $this->items = array_fill_keys(array_keys($this->items), null); - } - - /** - * Converts the weak caches to array. - * - * @return array - */ - public function toArray(): array - { - $items = []; - - foreach ($this->items as $offset => $item) { - if ($item instanceof WeakReference) { - $item = $item->get(); - } - $items[$offset] = $item; - } - - return $items; - } - - /** - * Get the keys of the items. - * - * @return int[]|string[] - */ - public function keys(): array - { - return array_keys($this->items); - } - - /** - * If the repository has an offset. - * - * @deprecated 10.0.0 Use async `$repository->cache->has()` - * This method is deprecated for userland code but can still be used internally within the library. - * - * @param string|int $offset - * - * @return bool - */ - public function offsetExists($offset): bool - { - return parent::offsetExists($offset); - } - - /** - * Gets a part from the repository. - * - * @deprecated 10.0.0 Use async `$repository->cacheGet()` or sync `$repository->get()` - * This method is deprecated for userland code but can still be used internally within the library. - * - * @param string|int $offset - * - * @return Part|null - */ - public function offsetGet($offset) - { - $item = parent::offsetGet($offset); - - if ($item instanceof WeakReference) { - $item = $item->get(); - } - - if ($item) { - return $this->items[$offset] = $item; - } - - return null; - } - - /** - * Sets a part into the repository. - * - * @deprecated 10.0.0 Use async `$repository->cache->set()` - * - * @param string|int $offset - * @param ?Part $value - */ - public function offsetSet($offset, $value): void - { - parent::offsetSet($offset, $value); - } - - /** - * Unsets an index from the repository. - * - * @deprecated 10.0.0 Use async `$repository->cache->delete()` - * - * @param string|int $offset - */ - public function offsetUnset($offset): void - { - parent::offsetUnset($offset); - } - - /** - * {@inheritDoc} - */ - public function jsonSerialize(): array - { - return $this->toArray(); - } - - /** - * Returns an iterator for the cache. - * - * @return Traversable - */ - public function &getIterator(): Traversable - { - foreach ($this->items as $offset => &$item) { - if ($item instanceof WeakReference) { - // Attempt to get resolved value if promise is resolved without waiting - $item = $item->get() ?? nowait($this->cache->get($offset)); - } - - yield $offset => $item; - } - } - - public function __get(string $key) - { - if (in_array($key, ['discrim', 'cache'])) { - return $this->$key; - } - } -} + use AbstractRepositoryTrait; +} \ No newline at end of file diff --git a/src/Discord/Repository/AbstractRepositoryInterface.php b/src/Discord/Repository/AbstractRepositoryInterface.php new file mode 100644 index 000000000..b821a64de --- /dev/null +++ b/src/Discord/Repository/AbstractRepositoryInterface.php @@ -0,0 +1,64 @@ + + * + * This file is subject to the MIT license that is bundled + * with this source code in the LICENSE.md file. + */ + +namespace Discord\Repository; + +use Discord\Helpers\CollectionInterface; +use Discord\Discord; +use Discord\Helpers\Collection; +use Discord\Parts\Part; +use React\Promise\PromiseInterface; +use Traversable; + +interface AbstractRepositoryInterface extends CollectionInterface +{ + public function __construct(Discord $discord, array $vars = []); + public function freshen(array $queryparams = []): PromiseInterface; + public function create(array|object $attributes = [], bool $created = false): Part; + public function save(Part $part, ?string $reason = null): PromiseInterface; + public function delete($part, ?string $reason = null): PromiseInterface; + public function fresh(Part $part, array $queryparams = []): PromiseInterface; + public function fetch(string $id, bool $fresh = false): PromiseInterface; + public function get(string $discrim, $key); + public function cacheGet($offset): PromiseInterface; + public function set($offset, $value); + public function pull($key, $default = null); + public function cachePull($key, $default = null): PromiseInterface; + public function pushItem($item): self; + public function first(); + public function last(); + public function has(...$keys): bool; + public function filter(callable $callback): Collection; + public function find(callable $callback); + public function clear(): void; + public function toArray(): array; + public function keys(): array; + public function offsetExists($offset): bool; + #[\ReturnTypeWillChange] + public function offsetGet($offset); + public function offsetSet($offset, $value): void; + public function offsetUnset($offset): void; + public function jsonSerialize(): array; + public function &getIterator(): Traversable; + public function __get(string $key); + + // Methods imported from CollectionTrait + public function fill(array $items): static; + public function push(...$items): static; + public function isset($offset): bool; + public function map(callable $callback): static; + public function merge($collection): static; + public function serialize(): string; + public function __serialize(): array; + public function unserialize(string $serialized): void; + public function __unserialize(array $data): void; + public function __debugInfo(): array; +} diff --git a/src/Discord/Repository/AbstractRepositoryTrait.php b/src/Discord/Repository/AbstractRepositoryTrait.php new file mode 100644 index 000000000..679e5cc35 --- /dev/null +++ b/src/Discord/Repository/AbstractRepositoryTrait.php @@ -0,0 +1,802 @@ + + * + * This file is subject to the MIT license that is bundled + * with this source code in the LICENSE.md file. + */ + +namespace Discord\Repository; + +use Discord\Discord; +use Discord\Factory\Factory; +use Discord\Helpers\CacheWrapper; +use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; +use Discord\Helpers\CollectionTrait; +use Discord\Helpers\LegacyCacheWrapper; +use Discord\Http\Endpoint; +use Discord\Http\Http; +use Discord\Parts\Part; +use React\Promise\PromiseInterface; +use Traversable; +use WeakReference; + +use function Discord\nowait; +use function React\Promise\reject; +use function React\Promise\resolve; + +trait AbstractRepositoryTrait +{ + use CollectionTrait + { + get as get; + fill as fill; + push as push; + isset as isset; + map as map; + merge as merge; + serialize as serialize; + __serialize as __serialize; + unserialize as unserialize; + __unserialize as __unserialize; + __debugInfo as __debugInfo; + + // 'Parent' methods + __construct as __Collection____construct; + freshen as __Collection__freshen; + create as __Collection__create; + save as __Collection__save; + delete as __Collection__delete; + fresh as __Collection__fresh; + fetch as __Collection__fetch; + get as __Collection__get; + cacheGet as __Collection__cacheGet; + set as __Collection__set; + pull as __Collection__pull; + cachePull as __Collection__cachePull; + pushItem as __Collection__pushItem; + first as __Collection__first; + last as __Collection__last; + has as __Collection__has; + filter as __Collection__filter; + find as __Collection__find; + clear as __Collection__clear; + toArray as __Collection__toArray; + keys as __Collection__keys; + offsetExists as __Collection__offsetExists; + offsetGet as __Collection__offsetGet; + offsetSet as __Collection__offsetSet; + offsetUnset as __Collection__offsetUnset; + jsonSerialize as __Collection__jsonSerialize; + getIterator as __Collection__getIterator; + __get as __Collection____get; + } + /** + * The collection discriminator. + * + * @var string Discriminator. + */ + protected $discrim = 'id'; + + /** + * The items contained in the collection. + * + * @var array + */ + protected $items = []; + + /** + * Class type allowed into the collection. + * + * @var string + */ + protected $class; + + /** + * The HTTP client. + * + * @var Http Client. + */ + protected $http; + + /** + * The parts factory. + * + * @var Factory Parts factory. + */ + protected $factory; + + /** + * Endpoints for interacting with the Discord servers. + * + * @var array Endpoints. + */ + protected $endpoints = []; + + /** + * Variables that are related to the repository. + * + * @var array Variables. + */ + protected $vars = []; + + /** + * @var CacheWrapper + */ + protected $cache; + + /** + * AbstractRepository constructor. + * + * @param Discord $discord + * @param array $vars An array of variables used for the endpoint. + */ + public function __construct(Discord $discord, array $vars = []) + { + $this->http = $discord->getHttpClient(); + $this->factory = $discord->getFactory(); + $this->vars = $vars; + if ($cacheConfig = $discord->getCacheConfig(static::class)) { + $this->cache = new CacheWrapper($discord, $cacheConfig, $this->items, $this->class, $this->vars); + } else { + $this->cache = new LegacyCacheWrapper($discord, $this->items, $this->class); + } + } + + /** + * Freshens the repository cache. + * + * @param array $queryparams Query string params to add to the request (no validation) + * + * @return PromiseInterface + * + * @throws \Exception + */ + public function freshen(array $queryparams = []): PromiseInterface + { + if (! isset($this->endpoints['all'])) { + return reject(new \Exception('You cannot freshen this repository.')); + } + + $endpoint = new Endpoint($this->endpoints['all']); + $endpoint->bindAssoc($this->vars); + + foreach ($queryparams as $query => $param) { + $endpoint->addQuery($query, $param); + } + + return $this->http->get($endpoint)->then(function ($response) { + foreach ($this->items as $offset => $value) { + if ($value === null) { + unset($this->items[$offset]); + } elseif (! ($this->items[$offset] instanceof WeakReference)) { + $this->items[$offset] = WeakReference::create($value); + } + $this->cache->delete($offset); + } + + return $this->cacheFreshen($response); + }); + } + + /** + * @param object $response + * + * @return PromiseInterface + */ + protected function cacheFreshen($response): PromiseInterface + { + foreach ($response as $value) { + $value = array_merge($this->vars, (array) $value); + $part = $this->factory->create($this->class, $value, true); + $items[$part->{$this->discrim}] = $part; + } + + if (empty($items)) { + return resolve($this); + } + + return $this->cache->setMultiple($items)->then(fn ($success) => $this); + } + + /** + * Builds a new, empty part. + * + * @param array|object $attributes The attributes for the new part. + * @param bool $created + * + * @return Part The new part. + * + * @throws \Exception + */ + public function create(array|object $attributes = [], bool $created = false): Part + { + $attributes = array_merge((array) $attributes, $this->vars); + + return $this->factory->part($this->class, $attributes, $created); + } + + /** + * Attempts to save a part to the Discord servers. + * + * @param Part $part The part to save. + * @param string|null $reason Reason for Audit Log (if supported). + * + * @return PromiseInterface + * + * @throws \Exception + */ + public function save(Part $part, ?string $reason = null): PromiseInterface + { + if ($part->created) { + if (! isset($this->endpoints['update'])) { + return reject(new \Exception('You cannot update this part.')); + } + + $method = 'patch'; + $endpoint = new Endpoint($this->endpoints['update']); + $endpoint->bindAssoc(array_merge($part->getRepositoryAttributes(), $this->vars)); + $attributes = $part->getUpdatableAttributes(); + } else { + if (! isset($this->endpoints['create'])) { + return reject(new \Exception('You cannot create this part.')); + } + + $method = 'post'; + $endpoint = new Endpoint($this->endpoints['create']); + $endpoint->bindAssoc(array_merge($part->getRepositoryAttributes(), $this->vars)); + $attributes = $part->getCreatableAttributes(); + } + + $headers = []; + if (isset($reason)) { + $headers['X-Audit-Log-Reason'] = $reason; + } + + return $this->http->{$method}($endpoint, $attributes, $headers)->then(function ($response) use ($method, $part) { + switch ($method) { + case 'patch': // Update old part + $part->fill((array) $response); + $part->created = true; + return $this->cache->set($part->{$this->discrim}, $part)->then(fn ($success) => $part); + default: // Create new part + $newPart = $this->factory->create($this->class, (array) $response, true); + $newPart->created = true; + return $this->cache->set($newPart->{$this->discrim}, $this->factory->create($this->class, (array) $response, true))->then(fn ($success) => $newPart); + } + }); + } + + /** + * Attempts to delete a part on the Discord servers. + * + * @param Part|string $part The part to delete. + * @param string|null $reason Reason for Audit Log (if supported). + * + * @return PromiseInterface + * + * @throws \Exception + */ + public function delete($part, ?string $reason = null): PromiseInterface + { + if (! isset($part)) { + return reject(new \Exception('You cannot delete a non-existent part.')); + } + + if (! ($part instanceof Part)) { + $part = $this->factory->part($this->class, [$this->discrim => $part], true); + } + + if (! $part->created) { + return reject(new \Exception('You cannot delete a non-existent part.')); + } + + if (! isset($this->endpoints['delete'])) { + return reject(new \Exception('You cannot delete this part.')); + } + + $endpoint = new Endpoint($this->endpoints['delete']); + $endpoint->bindAssoc(array_merge($part->getRepositoryAttributes(), $this->vars)); + + $headers = []; + if (isset($reason)) { + $headers['X-Audit-Log-Reason'] = $reason; + } + + return $this->http->delete($endpoint, null, $headers)->then(function ($response) use (&$part) { + if ($response) { + $part->fill((array) $response); + } + $part->created = false; + + return $this->cache->delete($part->{$this->discrim})->then(fn ($success) => $part); + }); + } + + /** + * Returns a part with fresh values. + * + * @param Part $part The part to get fresh values. + * @param array $queryparams Query string params to add to the request (no validation) + * + * @return PromiseInterface + * + * @throws \Exception + */ + public function fresh(Part $part, array $queryparams = []): PromiseInterface + { + if (! $part->created) { + return reject(new \Exception('You cannot get a non-existent part.')); + } + + if (! isset($this->endpoints['get'])) { + return reject(new \Exception('You cannot get this part.')); + } + + $endpoint = new Endpoint($this->endpoints['get']); + $endpoint->bindAssoc(array_merge($part->getRepositoryAttributes(), $this->vars)); + + foreach ($queryparams as $query => $param) { + $endpoint->addQuery($query, $param); + } + + return $this->http->get($endpoint)->then(function ($response) use (&$part) { + $part->fill((array) $response); + + return $this->cache->set($part->{$this->discrim}, $part)->then(fn ($success) => $part); + }); + } + + /** + * Gets a part from the repository or Discord servers. + * + * @param string $id The ID to search for. + * @param bool $fresh Whether we should skip checking the cache. + * + * @throws \Exception + * + * @return PromiseInterface + */ + public function fetch(string $id, bool $fresh = false): PromiseInterface + { + if (! $fresh) { + if (isset($this->items[$id])) { + $part = $this->items[$id]; + if ($part instanceof WeakReference) { + $part = $part->get(); + } + + if ($part) { + $this->items[$id] = $part; + + return resolve($part); + } + } else { + return $this->cache->get($id)->then(function ($part) use ($id) { + if ($part === null) { + return $this->fetch($id, true); + } + + return $part; + }); + } + } + + if (! isset($this->endpoints['get'])) { + return reject(new \Exception('You cannot get this part.')); + } + + $part = $this->factory->part($this->class, [$this->discrim => $id]); + $endpoint = new Endpoint($this->endpoints['get']); + $endpoint->bindAssoc(array_merge($part->getRepositoryAttributes(), $this->vars)); + + return $this->http->get($endpoint)->then(function ($response) use ($part, $id) { + $part->created = true; + $part->fill(array_merge($this->vars, (array) $response)); + + return $this->cache->set($id, $part)->then(fn ($success) => $part); + }); + } + + /** + * Gets a part from the repository. + * + * @param string $discrim + * @param mixed $key + * + * @return Part|null + */ + public function get(string $discrim, $key) + { + if ($key === null) { + return null; + } + + if ($discrim == $this->discrim) { + if ($item = $this->offsetGet($key)) { + return $item; + } + + // Attempt to get resolved value if promise is resolved without waiting + return nowait($this->cache->get($key)); + } + + foreach ($this->items as $offset => $item) { + if ($item = $this->offsetGet($offset)) { + if ($item->{$discrim} == $key) { + return $item; + } + continue; + } + + $resolved = nowait($this->cache->get($offset)); + if ($resolved !== null) { + return $resolved; + } + break; + } + + return null; + } + + /** + * Attempts to get from memory first otherwise load from cache. + * + * @internal + * + * @param string|int $offset + * + * @return PromiseInterface + */ + public function cacheGet($offset): PromiseInterface + { + return resolve($this->offsetGet($offset) ?? $this->cache->get($offset)); + } + + /** + * Sets a part in the repository. + * + * @param string|int $offset + * @param Part $value + */ + public function set($offset, $value) + { + // Don't insert elements that are not of type class. + if (! is_a($value, $this->class)) { + return; + } + + $this->cache->set($offset, $value); + $this->items[$offset] = $value; + } + + /** + * Pulls a part from the repository. + * + * @deprecated 10.0.0 Use async `$repository->cachePull()` + * + * @param string|int $key + * @param mixed $default + * + * @return Part|mixed + */ + public function pull($key, $default = null) + { + if ($item = $this->offsetGet($key)) { + $default = $item; + unset($this->items[$key]); + $this->cache->delete($key); + } + + return $default; + } + + /** + * Pulls an item from cache. + * + * @internal + * + * @param string|int $key + * @param ?Part $default + * + * @return PromiseInterface + */ + public function cachePull($key, $default = null): PromiseInterface + { + return $this->cacheGet($key)->then(fn ($item) => ($item === null) ? $default : $this->cache->delete($key)->then(fn ($success) => $item)); + } + + /** + * Pushes a single item to the repository. + * + * @deprecated 10.0.0 Use async `$repository->cache->set()` + * This method is deprecated for userland code but can still be used internally within the library. + * + * @param Part $item + * + * @return $this + */ + public function pushItem($item): self + { + if (is_a($item, $this->class)) { + $key = $item->{$this->discrim}; + $this->items[$key] = $item; + $this->cache->set($key, $item); + } + + return $this; + } + + /** + * Returns the first cached part. + * + * @return Part|null + */ + public function first() + { + foreach ($this->items as $offset => $item) { + if ($item instanceof WeakReference) { + if (! $item = $item->get()) { + // Attempt to get resolved value if promise is resolved without waiting + $item = nowait($this->cache->get($offset)); + } + } + + if ($item) { + return $item; + } + } + + return null; + } + + /** + * Returns the last cached part. + * + * @return Part|null + */ + public function last() + { + $items = array_reverse($this->items, true); + + foreach ($items as $offset => $item) { + if ($item instanceof WeakReference) { + if (! $item = $item->get()) { + // Attempt to get resolved value if promise is resolved without waiting + $item = nowait($this->cache->get($offset)); + } + } + + if ($item) { + return $item; + } + } + + return null; + } + + /** + * Checks if the array has an object. + * + * @deprecated 10.0.0 Use async `$repository->cache->has()` + * + * @param string|int ...$keys + * + * @return bool + */ + public function has(...$keys): bool + { + foreach ($keys as $key) { + if (! isset($this->items[$key]) || nowait($this->cache->has($key)) === false) { + return false; + } + } + + return true; + } + + /** + * Runs a filter callback over the repository and returns a new collection + * based on the response of the callback. + * + * @param callable $callback + * + * @return CollectionInterface + */ + public function filter(callable $callback): CollectionInterface + { + $collection = new Collection([], $this->discrim, $this->class); + + foreach ($this->items as $offset => $item) { + if ($item instanceof WeakReference) { + if (! $item = $item->get()) { + // Attempt to get resolved value if promise is resolved without waiting + $item = nowait($this->cache->get($offset)); + } + } + + if ($item === null) { + continue; + } + + if ($callback($item)) { + $collection->push($item); + } + } + + return $collection; + } + + /** + * Runs a filter callback over the repository and returns the first part + * where the callback returns `true` when given the part. + * + * @param callable $callback + * + * @return Part|null `null` if no items returns `true` when called in the callback. + */ + public function find(callable $callback) + { + foreach ($this->getIterator() as $item) { + if ($item === null) { + continue; + } + + if ($callback($item)) { + return $item; + } + } + + return null; + } + + /** + * Clears the repository. + * + * @deprecated 10.0.0 Use async `$repository->cache->clear()` + */ + public function clear(): void + { + // Set items null but keep the keys to be removed on prune + $this->items = array_fill_keys(array_keys($this->items), null); + } + + /** + * Converts the weak caches to array. + * + * @return array + */ + public function toArray(): array + { + $items = []; + + foreach ($this->items as $offset => $item) { + if ($item instanceof WeakReference) { + $item = $item->get(); + } + $items[$offset] = $item; + } + + return $items; + } + + /** + * Get the keys of the items. + * + * @return int[]|string[] + */ + public function keys(): array + { + return array_keys($this->items); + } + + /** + * If the repository has an offset. + * + * @deprecated 10.0.0 Use async `$repository->cache->has()` + * This method is deprecated for userland code but can still be used internally within the library. + * + * @param string|int $offset + * + * @return bool + */ + public function offsetExists($offset): bool + { + return $this->__CollectionoffsetExists($offset); + } + + /** + * Gets a part from the repository. + * + * @deprecated 10.0.0 Use async `$repository->cacheGet()` or sync `$repository->get()` + * This method is deprecated for userland code but can still be used internally within the library. + * + * @param string|int $offset + * + * @return Part|null + */ + public function offsetGet($offset) + { + $item = $this->__CollectionoffsetGet($offset); + + if ($item instanceof WeakReference) { + $item = $item->get(); + } + + if ($item) { + return $this->items[$offset] = $item; + } + + return null; + } + + /** + * Sets a part into the repository. + * + * @deprecated 10.0.0 Use async `$repository->cache->set()` + * + * @param string|int $offset + * @param ?Part $value + */ + public function offsetSet($offset, $value): void + { + $this->__CollectionoffsetSet($offset, $value); + } + + /** + * Unsets an index from the repository. + * + * @deprecated 10.0.0 Use async `$repository->cache->delete()` + * + * @param string|int $offset + */ + public function offsetUnset($offset): void + { + $this->__CollectionoffsetUnset($offset); + } + + /** + * {@inheritDoc} + */ + public function jsonSerialize(): array + { + return $this->toArray(); + } + + /** + * Returns an iterator for the cache. + * + * @return Traversable + */ + public function &getIterator(): Traversable + { + foreach ($this->items as $offset => &$item) { + if ($item instanceof WeakReference) { + // Attempt to get resolved value if promise is resolved without waiting + $item = $item->get() ?? nowait($this->cache->get($offset)); + } + + yield $offset => $item; + } + } + + public function __get(string $key) + { + if (in_array($key, ['discrim', 'cache'])) { + return $this->$key; + } + } + + public function __call($name, $arguments) + { + if (method_exists(CollectionTrait::class, $name)) { + return (new CollectionTrait)->$name(...$arguments); + } + + throw new \BadMethodCallException("Method {$name} does not exist."); + } +} From 0191774a5aa21cdaa2ef19295099df975addb123 Mon Sep 17 00:00:00 2001 From: Valithor Obsidion Date: Tue, 24 Dec 2024 11:15:18 -0500 Subject: [PATCH 02/14] Dropin collection enhancement (#1270) * getCollectionClass method and config support * Implement getCollectionClass --- src/Discord/Builders/CommandAttributes.php | 2 +- .../Builders/Components/SelectMenu.php | 4 +- src/Discord/Discord.php | 41 ++++-- src/Discord/Helpers/RegisteredCommand.php | 2 +- src/Discord/Parts/Channel/Channel.php | 31 ++--- src/Discord/Parts/Channel/Message.php | 117 +++++++++--------- src/Discord/Parts/Channel/Poll.php | 2 +- src/Discord/Parts/Channel/Poll/PollAnswer.php | 6 +- src/Discord/Parts/Channel/Reaction.php | 10 +- src/Discord/Parts/Embed/Embed.php | 10 +- src/Discord/Parts/Guild/AuditLog/AuditLog.php | 70 +++++------ src/Discord/Parts/Guild/AuditLog/Entry.php | 8 +- .../Parts/Guild/AutoModeration/Rule.php | 26 ++-- .../Parts/Guild/CommandPermissions.php | 10 +- src/Discord/Parts/Guild/Emoji.php | 11 +- src/Discord/Parts/Guild/Guild.php | 20 +-- src/Discord/Parts/Guild/ScheduledEvent.php | 6 +- src/Discord/Parts/Guild/WelcomeScreen.php | 10 +- .../Parts/Interactions/Command/Command.php | 8 +- .../Parts/Interactions/Command/Option.php | 18 +-- .../Parts/Interactions/Interaction.php | 4 +- .../Parts/Interactions/Request/Component.php | 10 +- .../Interactions/Request/InteractionData.php | 18 +-- .../Parts/Interactions/Request/Option.php | 10 +- .../Parts/Interactions/Request/Resolved.php | 50 ++++---- src/Discord/Parts/Thread/Thread.php | 14 +-- src/Discord/Parts/User/Member.php | 18 +-- .../Parts/WebSockets/PresenceUpdate.php | 18 +-- src/Discord/Repository/AbstractRepository.php | 18 ++- .../Repository/Channel/ThreadRepository.php | 12 +- src/Discord/Voice/VoiceClient.php | 6 +- .../WebSockets/Events/GuildEmojisUpdate.php | 6 +- .../WebSockets/Events/GuildStickersUpdate.php | 6 +- .../WebSockets/Events/MessageDeleteBulk.php | 4 +- .../WebSockets/Events/ThreadListSync.php | 4 +- tests/Parts/Channel/ChannelTest.php | 2 +- .../Channel/Message/EmptyMessageTest.php | 2 +- 37 files changed, 325 insertions(+), 289 deletions(-) diff --git a/src/Discord/Builders/CommandAttributes.php b/src/Discord/Builders/CommandAttributes.php index 877dca08f..fd33d17b4 100644 --- a/src/Discord/Builders/CommandAttributes.php +++ b/src/Discord/Builders/CommandAttributes.php @@ -29,7 +29,7 @@ * @property ?string[]|null $name_localizations Localization dictionary for the name field. Values follow the same restrictions as name. * @property ?string $description 1-100 character description for CHAT_INPUT commands, empty string for USER and MESSAGE commands. * @property ?string[]|null $description_localizations Localization dictionary for the description field. Values follow the same restrictions as description. - * @property \Discord\Helpers\Collection|Option[]|null $options The parameters for the command, max 25. Only for Slash command (CHAT_INPUT). + * @property \Discord\Helpers\CollectionInterface|Option[]|null $options The parameters for the command, max 25. Only for Slash command (CHAT_INPUT). * @property ?string $default_member_permissions Set of permissions represented as a bit set. * @property bool|null $dm_permission Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. * @property ?bool $default_permission Whether the command is enabled by default when the app is added to a guild. SOON DEPRECATED. diff --git a/src/Discord/Builders/Components/SelectMenu.php b/src/Discord/Builders/Components/SelectMenu.php index 54cb29098..70289930e 100644 --- a/src/Discord/Builders/Components/SelectMenu.php +++ b/src/Discord/Builders/Components/SelectMenu.php @@ -12,7 +12,7 @@ namespace Discord\Builders\Components; use Discord\Discord; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Interactions\Interaction; use Discord\WebSockets\Event; use React\Promise\PromiseInterface; @@ -350,7 +350,7 @@ public function setListener(?callable $callback, Discord $discord, bool $oneOff if (empty($this->options)) { $response = $callback($interaction); } else { - $options = Collection::for(Option::class, null); + $options = ($this->discord->getCollectionClass())::for(Option::class, null); foreach ($this->options as $option) { if (in_array($option->getValue(), $interaction->data->values)) { diff --git a/src/Discord/Discord.php b/src/Discord/Discord.php index 30782df04..7a6360cbc 100644 --- a/src/Discord/Discord.php +++ b/src/Discord/Discord.php @@ -15,6 +15,8 @@ use Discord\Factory\Factory; use Discord\Helpers\BigInt; use Discord\Helpers\CacheConfig; +use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Helpers\RegisteredCommand; use Discord\Http\Drivers\React; use Discord\Http\Endpoint; @@ -331,6 +333,13 @@ class Discord */ protected $cacheConfig; + /** + * The collection class. + * + * @var string + */ + protected $collectionClass; + /** * The Client class. * @@ -375,6 +384,10 @@ public function __construct(array $options = []) if ($cacheConfig = $this->getCacheConfig()) { $this->logger->warning('Attached experimental CacheInterface: '.get_class($cacheConfig->interface)); } + $this->collectionClass = $options['collection']; + if ($this->collectionClass !== Collection::class) { + $this->logger->warning("Attached experimental CollectionClass: {$this->collectionClass}"); + } $connector = new SocketConnector($options['socket_options'], $this->loop); $this->wsFactory = new Connector($this->loop, $connector); @@ -1409,6 +1422,7 @@ protected function resolveOptions(array $options = []): array 'socket_options', 'dnsConfig', 'cache', + 'collection', ]) ->setDefaults([ 'logger' => null, @@ -1419,6 +1433,7 @@ protected function resolveOptions(array $options = []): array 'intents' => Intents::getDefaultIntents(), 'socket_options' => [], 'cache' => [AbstractRepository::class => null], // use LegacyCacheWrapper + 'collection' => [Collection::class => null], ]) ->setAllowedTypes('token', 'string') ->setAllowedTypes('logger', ['null', LoggerInterface::class]) @@ -1431,17 +1446,9 @@ protected function resolveOptions(array $options = []): array ->setAllowedTypes('socket_options', 'array') ->setAllowedTypes('dnsConfig', ['string', \React\Dns\Config\Config::class]) ->setAllowedTypes('cache', ['array', CacheConfig::class, \React\Cache\CacheInterface::class, \Psr\SimpleCache\CacheInterface::class]) - ->setNormalizer('cache', function ($options, $value) { - if (! is_array($value)) { - if (! ($value instanceof CacheConfig)) { - $value = new CacheConfig($value); - } - - return [AbstractRepository::class => $value]; - } - - return $value; - }); + ->setNormalizer('cache', fn($options, $value) => is_array($value) ? $value : [AbstractRepository::class => $value instanceof CacheConfig ? $value : new CacheConfig($value)]) + ->setAllowedTypes('collection', ['string', 'null']) + ->setAllowedValues('collection', fn($value) => $value === null || (class_exists($value) && isset(class_implements($value)[CollectionInterface::class]))); $options = $resolver->resolve($options); @@ -1615,6 +1622,18 @@ public function getCacheConfig($repository_class = AbstractRepository::class) return $this->cacheConfig[$repository_class]; } + /** + * Gets the collection configuration. + * + * @param string $collection_class Collection class name. + * + * @return string The class name of the collection, which implements CollectionInterface + */ + public function getCollectionClass() + { + return $this->collectionClass; + } + /** * Handles dynamic get calls to the client. * diff --git a/src/Discord/Helpers/RegisteredCommand.php b/src/Discord/Helpers/RegisteredCommand.php index 2378addfd..3207d9f10 100644 --- a/src/Discord/Helpers/RegisteredCommand.php +++ b/src/Discord/Helpers/RegisteredCommand.php @@ -90,7 +90,7 @@ public function __construct(Discord $discord, string $name, ?callable $callback */ public function execute(array $options, Interaction $interaction): bool { - $params = Collection::for(Option::class, 'name'); + $params = ($this->discord->getCollectionClass())::for(Option::class, 'name'); foreach ($options as $option) { if (isset($this->subCommands[$option->name])) { diff --git a/src/Discord/Parts/Channel/Channel.php b/src/Discord/Parts/Channel/Channel.php index 507db9a41..4e6792b03 100644 --- a/src/Discord/Parts/Channel/Channel.php +++ b/src/Discord/Parts/Channel/Channel.php @@ -14,7 +14,7 @@ use Carbon\Carbon; use Discord\Builders\MessageBuilder; use Discord\Exceptions\InvalidOverwriteException; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Embed\Embed; use Discord\Parts\Guild\Guild; use Discord\Parts\Guild\Role; @@ -70,7 +70,7 @@ * @property int|null $bitrate The bitrate of the channel. Only for voice channels. * @property int|null $user_limit The user limit of the channel. Max 99 for voice channels and 10000 for stage channels (0 refers to no limit). * @property int|null $rate_limit_per_user Amount of seconds a user has to wait before sending a new message (slow mode). - * @property Collection|User[] $recipients A collection of all the recipients in the channel. Only for DM or group channels. + * @property CollectionInterface|User[] $recipients A collection of all the recipients in the channel. Only for DM or group channels. * @property-read User|null $recipient The first recipient of the channel. Only for DM or group channels. * @property-read string|null $recipient_id The ID of the recipient of the channel, if it is a DM channel. * @property ?string|null $icon Icon hash. @@ -84,7 +84,7 @@ * @property int|null $default_auto_archive_duration Default duration for newly created threads, in minutes, to automatically archive the thread after recent activity, can be set to: 60, 1440, 4320, 10080. * @property string|null $permissions Computed permissions for the invoking user in the channel, including overwrites, only included when part of the resolved data received on an application command interaction. * @property int|null $flags Channel flags combined as a bitfield. - * @property Collection|Tag[] $available_tags Set of tags that can be used in a forum channel, limited to 20. + * @property CollectionInterface|Tag[] $available_tags Set of tags that can be used in a forum channel, limited to 20. * @property ?Reaction|null $default_reaction_emoji Emoji to show in the add reaction button on a thread in a forum channel. * @property int|null $default_thread_rate_limit_per_user The initial rate_limit_per_user to set on newly created threads in a forum channel. this field is copied to the thread at creation time and does not live update. * @property ?int|null $default_sort_order The default sort order type used to order posts in forum channels. @@ -251,11 +251,11 @@ protected function getRecipientIdAttribute(): ?string /** * Gets the recipients attribute. * - * @return Collection A collection of recipients. + * @return CollectionInterface A collection of recipients. */ - protected function getRecipientsAttribute(): Collection + protected function getRecipientsAttribute(): CollectionInterface { - $recipients = Collection::for(User::class); + $recipients = ($this->discord->getCollectionClass())::for(User::class); foreach ($this->attributes['recipients'] ?? [] as $recipient) { $recipients->pushItem($this->discord->users->get('id', $recipient->id) ?: $this->factory->part(User::class, (array) $recipient, true)); @@ -295,13 +295,13 @@ protected function getLastPinTimestampAttribute(): ?Carbon * * @link https://discord.com/developers/docs/resources/channel#get-pinned-messages * - * @return PromiseInterface> + * @return PromiseInterface> */ public function getPinnedMessages(): PromiseInterface { return $this->http->get(Endpoint::bind(Endpoint::CHANNEL_PINS, $this->id)) ->then(function ($responses) { - $messages = Collection::for(Message::class); + $messages = ($this->discord->getCollectionClass())::for(Message::class); foreach ($responses as $response) { $messages->pushItem($this->messages->get('id', $response->id) ?: $this->messages->create($response, true)); @@ -736,7 +736,7 @@ public function limitDelete(int $value, ?string $reason = null): PromiseInterfac * Or also missing `connect` permission for text in voice. * @throws \RangeException * - * @return PromiseInterface> + * @return PromiseInterface> * @todo Make it in a trait along with Thread */ public function getMessageHistory(array $options = []): PromiseInterface @@ -781,7 +781,7 @@ public function getMessageHistory(array $options = []): PromiseInterface } return $this->http->get($endpoint)->then(function ($responses) { - $messages = Collection::for(Message::class); + $messages = ($this->discord->getCollectionClass())::for(Message::class); foreach ($responses as $response) { $messages->pushItem($this->messages->get('id', $response->id) ?: $this->messages->create($response, true)); @@ -925,13 +925,13 @@ protected function getPermissionOverwritesAttribute(): ?array /** * Gets the available tags attribute. * - * @return Collection|Tag[] Available forum tags. + * @return CollectionInterface|Tag[] Available forum tags. * * @since 7.4.0 */ - protected function getAvailableTagsAttribute(): Collection + protected function getAvailableTagsAttribute(): CollectionInterface { - $available_tags = Collection::for(Tag::class); + $available_tags = ($this->discord->getCollectionClass())::for(Tag::class); foreach ($this->attributes['available_tags'] ?? [] as $available_tag) { $available_tags->pushItem($this->createOf(Tag::class, $available_tag)); @@ -1267,12 +1267,13 @@ public function broadcastTyping(): PromiseInterface * @param int $options['time'] Time in milliseconds until the collector finishes or false. * @param int $options['limit'] The amount of messages allowed or false. * - * @return PromiseInterface> + * @return PromiseInterface> */ public function createMessageCollector(callable $filter, array $options = []): PromiseInterface { $deferred = new Deferred(); - $messages = new Collection([], null, null); + /** @var CollectionInterface $messages An instance of the collection class implementing CollectionInterface.*/ + $messages = new ($this->discord->getCollectionClass())([], null, null); $timer = null; $options = array_merge([ diff --git a/src/Discord/Parts/Channel/Message.php b/src/Discord/Parts/Channel/Message.php index ebe1485c7..a0883e0eb 100644 --- a/src/Discord/Parts/Channel/Message.php +++ b/src/Discord/Parts/Channel/Message.php @@ -13,7 +13,7 @@ use Carbon\Carbon; use Discord\Builders\MessageBuilder; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Channel\Poll; use Discord\Parts\Embed\Embed; use Discord\Parts\Guild\Emoji; @@ -45,39 +45,39 @@ * * @since 2.0.0 * - * @property string $id The unique identifier of the message. - * @property string $channel_id The unique identifier of the channel that the message was sent in. - * @property-read Channel|Thread $channel The channel that the message was sent in. - * @property User|null $author The author of the message. Will be a webhook if sent from one. - * @property-read string|null $user_id The user id of the author. - * @property string $content The content of the message if it is a normal message. - * @property Carbon $timestamp A timestamp of when the message was sent. - * @property Carbon|null $edited_timestamp A timestamp of when the message was edited, or null. - * @property bool $tts Whether the message was sent as a text-to-speech message. - * @property bool $mention_everyone Whether the message contained an @everyone mention. - * @property Collection|User[] $mentions A collection of the users mentioned in the message. - * @property Collection|Role[] $mention_roles A collection of roles that were mentioned in the message. - * @property Collection|Channel[] $mention_channels Collection of mentioned channels. - * @property Collection|Attachment[] $attachments Collection of attachment objects. - * @property Collection|Embed[] $embeds A collection of embed objects. - * @property ReactionRepository $reactions Collection of reactions on the message. - * @property string|null $nonce A randomly generated string that provides verification for the client. Not required. - * @property bool $pinned Whether the message is pinned to the channel. - * @property string|null $webhook_id ID of the webhook that made the message, if any. - * @property int $type The type of message. - * @property object|null $activity Current message activity. Requires rich presence. - * @property object|null $application Application of message. Requires rich presence. - * @property string|null $application_id If the message is a response to an Interaction, this is the id of the interaction's application. - * @property object|null $message_reference Message that is referenced by this message. - * @property int|null $flags Message flags. - * @property Message|null $referenced_message The message that is referenced in a reply. - * @property MessageInteraction|null $interaction Sent if the message is a response to an Interaction. - * @property Thread|null $thread The thread that was started from this message, includes thread member object. - * @property Collection|Component[]|null $components Sent if the message contains components like buttons, action rows, or other interactive components. - * @property Collection|Sticker[]|null $sticker_items Stickers attached to the message. - * @property int|null $position A generally increasing integer (there may be gaps or duplicates) that represents the approximate position of the message in a thread, it can be used to estimate the relative position of the message in a thread in company with `total_message_sent` on parent thread. - * @property object|null $role_subscription_data Data of the role subscription purchase or renewal that prompted this `ROLE_SUBSCRIPTION_PURCHASE` message. - * @property Poll|null $poll The poll attached to the message. + * @property string $id The unique identifier of the message. + * @property string $channel_id The unique identifier of the channel that the message was sent in. + * @property-read Channel|Thread $channel The channel that the message was sent in. + * @property User|null $author The author of the message. Will be a webhook if sent from one. + * @property-read string|null $user_id The user id of the author. + * @property string $content The content of the message if it is a normal message. + * @property Carbon $timestamp A timestamp of when the message was sent. + * @property Carbon|null $edited_timestamp A timestamp of when the message was edited, or null. + * @property bool $tts Whether the message was sent as a text-to-speech message. + * @property bool $mention_everyone Whether the message contained an @everyone mention. + * @property CollectionInterface|User[] $mentions A collection of the users mentioned in the message. + * @property CollectionInterface|Role[] $mention_roles A collection of roles that were mentioned in the message. + * @property CollectionInterface|Channel[] $mention_channels Collection of mentioned channels. + * @property CollectionInterface|Attachment[] $attachments Collection of attachment objects. + * @property CollectionInterface|Embed[] $embeds A collection of embed objects. + * @property ReactionRepository $reactions Collection of reactions on the message. + * @property string|null $nonce A randomly generated string that provides verification for the client. Not required. + * @property bool $pinned Whether the message is pinned to the channel. + * @property string|null $webhook_id ID of the webhook that made the message, if any. + * @property int $type The type of message. + * @property object|null $activity Current message activity. Requires rich presence. + * @property object|null $application Application of message. Requires rich presence. + * @property string|null $application_id If the message is a response to an Interaction, this is the id of the interaction's application. + * @property object|null $message_reference Message that is referenced by this message. + * @property int|null $flags Message flags. + * @property Message|null $referenced_message The message that is referenced in a reply. + * @property MessageInteraction|null $interaction Sent if the message is a response to an Interaction. + * @property Thread|null $thread The thread that was started from this message, includes thread member object. + * @property CollectionInterface|Component[]|null $components Sent if the message contains components like buttons, action rows, or other interactive components. + * @property CollectionInterface|Sticker[]|null $sticker_items Stickers attached to the message. + * @property int|null $position A generally increasing integer (there may be gaps or duplicates) that represents the approximate position of the message in a thread, it can be used to estimate the relative position of the message in a thread in company with `total_message_sent` on parent thread. + * @property object|null $role_subscription_data Data of the role subscription purchase or renewal that prompted this `ROLE_SUBSCRIPTION_PURCHASE` message. + * @property Poll|null $poll The poll attached to the message. * * @property-read bool $crossposted Message has been crossposted. * @property-read bool $is_crosspost Message is a crosspost from another channel. @@ -334,11 +334,11 @@ protected function getSuppressNotificationsAttribute(): bool /** * Gets the mention_channels attribute. * - * @return Collection|Channel[] + * @return CollectionInterface|Channel[] */ - protected function getMentionChannelsAttribute(): Collection + protected function getMentionChannelsAttribute(): CollectionInterface { - $collection = Collection::for(Channel::class); + $collection = ($this->discord->getCollectionClass())::for(Channel::class); if (preg_match_all('/<#([0-9]*)>/', $this->content, $matches)) { foreach ($matches[1] as $channelId) { @@ -358,11 +358,11 @@ protected function getMentionChannelsAttribute(): Collection /** * Returns any attached files. * - * @return Collection|Attachment[] Attachment objects. + * @return CollectionInterface|Attachment[] Attachment objects. */ - protected function getAttachmentsAttribute(): Collection + protected function getAttachmentsAttribute(): CollectionInterface { - $attachments = Collection::for(Attachment::class); + $attachments = ($this->discord->getCollectionClass())::for(Attachment::class); foreach ($this->attributes['attachments'] ?? [] as $attachment) { $attachments->pushItem($this->createOf(Attachment::class, $attachment)); @@ -490,11 +490,12 @@ protected function getGuildAttribute(): ?Guild /** * Returns the mention_roles attribute. * - * @return Collection The roles that were mentioned. null role only contains the ID in the collection. + * @return CollectionInterface The roles that were mentioned. null role only contains the ID in the collection. */ - protected function getMentionRolesAttribute(): Collection + protected function getMentionRolesAttribute(): CollectionInterface { - $roles = new Collection(); + /** @var CollectionInterface $roles An instance of the collection class implementing CollectionInterface.*/ + $roles = new ($this->discord->getCollectionClass())(); if (empty($this->attributes['mention_roles'])) { return $roles; @@ -514,11 +515,11 @@ protected function getMentionRolesAttribute(): Collection /** * Returns the mention attribute. * - * @return Collection|User[] The users that were mentioned. + * @return CollectionInterface|User[] The users that were mentioned. */ - protected function getMentionsAttribute(): Collection + protected function getMentionsAttribute(): CollectionInterface { - $users = Collection::for(User::class); + $users = ($this->discord->getCollectionClass())::for(User::class); foreach ($this->attributes['mentions'] ?? [] as $mention) { $users->pushItem($this->discord->users->get('id', $mention->id) ?: $this->factory->part(User::class, (array) $mention, true)); @@ -581,11 +582,12 @@ protected function getMemberAttribute(): ?Member /** * Returns the embed attribute. * - * @return Collection A collection of embeds. + * @return CollectionInterface A collection of embeds. */ - protected function getEmbedsAttribute(): Collection + protected function getEmbedsAttribute(): CollectionInterface { - $embeds = new Collection([], null); + /** @var CollectionInterface $embeds An instance of the collection class implementing CollectionInterface.*/ + $embeds = new ($this->discord->getCollectionClass())([], null); foreach ($this->attributes['embeds'] ?? [] as $embed) { $embeds->pushItem($this->createOf(Embed::class, $embed)); @@ -681,15 +683,15 @@ protected function getEditedTimestampAttribute(): ?Carbon /** * Returns the components attribute. * - * @return Collection|Component[]|null + * @return CollectionInterface|Component[]|null */ - protected function getComponentsAttribute(): ?Collection + protected function getComponentsAttribute(): ?CollectionInterface { if (! isset($this->attributes['components'])) { return null; } - $components = Collection::for(Component::class, null); + $components = ($this->discord->getCollectionClass())::for(Component::class, null); foreach ($this->attributes['components'] as $component) { $components->pushItem($this->createOf(Component::class, $component)); @@ -701,15 +703,15 @@ protected function getComponentsAttribute(): ?Collection /** * Returns the sticker_items attribute. * - * @return Collection|Sticker[]|null Partial stickers. + * @return CollectionInterface|Sticker[]|null Partial stickers. */ - protected function getStickerItemsAttribute(): ?Collection + protected function getStickerItemsAttribute(): ?CollectionInterface { if (! isset($this->attributes['sticker_items']) && ! in_array($this->type, [self::TYPE_DEFAULT, self::TYPE_REPLY])) { return null; } - $sticker_items = Collection::for(Sticker::class); + $sticker_items = ($this->discord->getCollectionClass())::for(Sticker::class); foreach ($this->attributes['sticker_items'] ?? [] as $sticker) { $sticker_items->pushItem($this->factory->part(Sticker::class, (array) $sticker, true)); @@ -1077,12 +1079,13 @@ public function delete(): PromiseInterface * @param int $options['time'] Time in milliseconds until the collector finishes or false. * @param int $options['limit'] The amount of reactions allowed or false. * - * @return PromiseInterface> + * @return PromiseInterface> */ public function createReactionCollector(callable $filter, array $options = []): PromiseInterface { $deferred = new Deferred(); - $reactions = new Collection([], null, null); + /** @var CollectionInterface $reactions An instance of the collection class implementing CollectionInterface.*/ + $reactions = new ($this->discord->getCollectionClass())([], null, null); $timer = null; $options = array_merge([ diff --git a/src/Discord/Parts/Channel/Poll.php b/src/Discord/Parts/Channel/Poll.php index 6420e5242..2f3e07b12 100644 --- a/src/Discord/Parts/Channel/Poll.php +++ b/src/Discord/Parts/Channel/Poll.php @@ -12,7 +12,7 @@ namespace Discord\Parts\Channel; use Carbon\Carbon; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Http\Endpoint; use Discord\Parts\Channel\Poll\PollAnswer; use Discord\Parts\Channel\Poll\PollMedia; diff --git a/src/Discord/Parts/Channel/Poll/PollAnswer.php b/src/Discord/Parts/Channel/Poll/PollAnswer.php index 2bfc021a5..b70f525c7 100644 --- a/src/Discord/Parts/Channel/Poll/PollAnswer.php +++ b/src/Discord/Parts/Channel/Poll/PollAnswer.php @@ -11,7 +11,7 @@ namespace Discord\Parts\Channel\Poll; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Http\Endpoint; use Discord\Parts\Channel\Channel; use Discord\Parts\Channel\Message; @@ -140,7 +140,7 @@ protected function getGuildAttribute(): ?Guild * * @throws \OutOfRangeException * - * @return PromiseInterface + * @return PromiseInterface */ public function getVoters(array $options = []): PromiseInterface { @@ -162,7 +162,7 @@ public function getVoters(array $options = []): PromiseInterface return $this->http->get($query) ->then(function ($response) { - $users = Collection::for(User::class); + $users = ($this->discord->getCollectionClass())::for(User::class); foreach ($response->users ?? [] as $user) { if (! $part = $this->discord->users->get('id', $user->id)) { diff --git a/src/Discord/Parts/Channel/Reaction.php b/src/Discord/Parts/Channel/Reaction.php index e1a13ff5a..762a46bcc 100644 --- a/src/Discord/Parts/Channel/Reaction.php +++ b/src/Discord/Parts/Channel/Reaction.php @@ -11,7 +11,7 @@ namespace Discord\Parts\Channel; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Http\Endpoint; use Discord\Parts\Guild\Emoji; use Discord\Parts\Guild\Guild; @@ -139,7 +139,7 @@ protected function getIdAttribute(): string * * @link https://discord.com/developers/docs/resources/channel#get-reactions * - * @return PromiseInterface + * @return PromiseInterface */ public function getUsers(array $options = []): PromiseInterface { @@ -161,7 +161,7 @@ public function getUsers(array $options = []): PromiseInterface return $this->http->get($query) ->then(function ($response) { - $users = Collection::for(User::class); + $users = ($this->discord->getCollectionClass())::for(User::class); foreach ((array) $response as $user) { if (! $part = $this->discord->users->get('id', $user->id)) { @@ -182,11 +182,11 @@ public function getUsers(array $options = []): PromiseInterface * * @see Message::getUsers() * - * @return PromiseInterface + * @return PromiseInterface */ public function getAllUsers(): PromiseInterface { - $response = Collection::for(User::class); + $response = ($this->discord->getCollectionClass())::for(User::class); $getUsers = function ($after = null) use (&$getUsers, $response) { $options = ['limit' => 100]; if ($after != null) { diff --git a/src/Discord/Parts/Embed/Embed.php b/src/Discord/Parts/Embed/Embed.php index 811635a39..5af6c67e7 100644 --- a/src/Discord/Parts/Embed/Embed.php +++ b/src/Discord/Parts/Embed/Embed.php @@ -12,7 +12,7 @@ namespace Discord\Parts\Embed; use Carbon\Carbon; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Channel\Attachment; use Discord\Parts\Part; use function Discord\poly_strlen; @@ -36,7 +36,7 @@ * @property-read Video|null $video The video of the embed. * @property-read object|null $provider The provider of the embed. * @property Author|null $author The author of the embed. - * @property Collection|Field[] $fields A collection of embed fields. + * @property CollectionInterface|Field[] $fields A collection of embed fields. */ class Embed extends Part { @@ -135,11 +135,11 @@ protected function getAuthorAttribute(): Author /** * Gets the fields attribute. * - * @return Collection|Field[] + * @return CollectionInterfaceInterface|Field[] */ - protected function getFieldsAttribute(): Collection + protected function getFieldsAttribute(): CollectionInterface { - $fields = Collection::for(Field::class, null); + $fields = ($this->discord->getCollectionClass())::for(Field::class, null); if (! array_key_exists('fields', $this->attributes)) { return $fields; diff --git a/src/Discord/Parts/Guild/AuditLog/AuditLog.php b/src/Discord/Parts/Guild/AuditLog/AuditLog.php index 1cba91e8a..f787eb954 100644 --- a/src/Discord/Parts/Guild/AuditLog/AuditLog.php +++ b/src/Discord/Parts/Guild/AuditLog/AuditLog.php @@ -11,7 +11,7 @@ namespace Discord\Parts\Guild\AuditLog; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Channel\Webhook; use Discord\Parts\Guild\AutoModeration\Rule; use Discord\Parts\Guild\Guild; @@ -30,14 +30,14 @@ * * @since 5.1.0 * - * @property Collection|Command[] $application_commands List of application commands referenced in the audit log. - * @property Collection|Entry[] $audit_log_entries List of audit log entries. - * @property Collection|Rule[] $auto_moderation_rules List of auto moderation rules referenced in the audit log. - * @property Collection|ScheduledEvent[] $guild_scheduled_events List of guild scheduled events referenced in the audit log. - * @property Collection|Integration[] $integrations List of partial integration objects. - * @property Collection|Thread[] $threads List of threads referenced in the audit log. - * @property Collection|User[] $users List of users referenced in the audit log. - * @property Collection|Webhook[] $webhooks List of webhooks referenced in the audit log. + * @property CollectionInterface|Command[] $application_commands List of application commands referenced in the audit log. + * @property CollectionInterface|Entry[] $audit_log_entries List of audit log entries. + * @property CollectionInterface|Rule[] $auto_moderation_rules List of auto moderation rules referenced in the audit log. + * @property CollectionInterface|ScheduledEvent[] $guild_scheduled_events List of guild scheduled events referenced in the audit log. + * @property CollectionInterface|Integration[] $integrations List of partial integration objects. + * @property CollectionInterface|Thread[] $threads List of threads referenced in the audit log. + * @property CollectionInterface|User[] $users List of users referenced in the audit log. + * @property CollectionInterface|Webhook[] $webhooks List of webhooks referenced in the audit log. * * @property string $guild_id * @property-read Guild|null $guild @@ -74,11 +74,11 @@ protected function getGuildAttribute(): ?Guild /** * Returns a collection of application commands found in the audit log. * - * @return Collection|Command[] + * @return CollectionInterfaceInterface|Command[] */ - protected function getApplicationCommandsAttribute(): Collection + protected function getApplicationCommandsAttribute(): CollectionInterface { - $collection = Collection::for(Command::class); + $collection = ($this->discord->getCollectionClass())::for(Command::class); foreach ($this->attributes['application_commands'] ?? [] as $application_commands) { $collection->pushItem($this->factory->part(Command::class, (array) $application_commands, true)); @@ -90,11 +90,11 @@ protected function getApplicationCommandsAttribute(): Collection /** * Returns a collection of audit log entries. * - * @return Collection|Entry[] + * @return CollectionInterfaceInterface|Entry[] */ - protected function getAuditLogEntriesAttribute(): Collection + protected function getAuditLogEntriesAttribute(): CollectionInterface { - $collection = Collection::for(Entry::class); + $collection = ($this->discord->getCollectionClass())::for(Entry::class); foreach ($this->attributes['audit_log_entries'] ?? [] as $entry) { $collection->pushItem($this->createOf(Entry::class, $entry)); @@ -106,11 +106,11 @@ protected function getAuditLogEntriesAttribute(): Collection /** * Returns a collection of auto moderation rules found in the audit log. * - * @return Collection|Rule[] + * @return CollectionInterfaceInterface|Rule[] */ - protected function getAutoModerationRulesAttribute(): Collection + protected function getAutoModerationRulesAttribute(): CollectionInterface { - $collection = Collection::for(Rule::class); + $collection = ($this->discord->getCollectionClass())::for(Rule::class); foreach ($this->attributes['auto_moderation_rules'] ?? [] as $rule) { $collection->pushItem($this->factory->part(Rule::class, (array) $rule, true)); @@ -122,11 +122,11 @@ protected function getAutoModerationRulesAttribute(): Collection /** * Returns a collection of guild scheduled events found in the audit log. * - * @return Collection|ScheduledEvent[] + * @return CollectionInterfaceInterface|ScheduledEvent[] */ - protected function getGuildScheduledEventsAttribute(): Collection + protected function getGuildScheduledEventsAttribute(): CollectionInterface { - $collection = Collection::for(ScheduledEvent::class); + $collection = ($this->discord->getCollectionClass())::for(ScheduledEvent::class); foreach ($this->attributes['guild_scheduled_events'] ?? [] as $scheduled_event) { $collection->pushItem($this->factory->part(ScheduledEvent::class, (array) $scheduled_event, true)); @@ -140,11 +140,11 @@ protected function getGuildScheduledEventsAttribute(): Collection * * @link https://discord.com/developers/docs/resources/audit-log#audit-log-object-example-partial-integration-object * - * @return Collection|Integration[] + * @return CollectionInterfaceInterface|Integration[] */ - protected function getIntegrationsAttribute(): Collection + protected function getIntegrationsAttribute(): CollectionInterface { - $collection = Collection::for(Integration::class); + $collection = ($this->discord->getCollectionClass())::for(Integration::class); foreach ($this->attributes['integrations'] ?? [] as $integration) { $collection->pushItem($this->factory->part(Integration::class, (array) $integration, true)); @@ -156,11 +156,11 @@ protected function getIntegrationsAttribute(): Collection /** * Returns a collection of threads found in the audit log. * - * @return Collection|Thread[] + * @return CollectionInterfaceInterface|Thread[] */ - protected function getThreadsAttribute(): Collection + protected function getThreadsAttribute(): CollectionInterface { - $collection = Collection::for(Thread::class); + $collection = ($this->discord->getCollectionClass())::for(Thread::class); foreach ($this->attributes['threads'] ?? [] as $thread) { $collection->pushItem($this->factory->part(Thread::class, (array) $thread, true)); @@ -172,11 +172,11 @@ protected function getThreadsAttribute(): Collection /** * Returns a collection of users found in the audit log. * - * @return Collection|User[] + * @return CollectionInterfaceInterface|User[] */ - protected function getUsersAttribute(): Collection + protected function getUsersAttribute(): CollectionInterface { - $collection = Collection::for(User::class); + $collection = ($this->discord->getCollectionClass())::for(User::class); foreach ($this->attributes['users'] ?? [] as $user) { $collection->pushItem($this->discord->users->get('id', $user->id) ?: $this->factory->part(User::class, (array) $user, true)); @@ -188,11 +188,11 @@ protected function getUsersAttribute(): Collection /** * Returns a collection of webhooks found in the audit log. * - * @return Collection|Webhook[] + * @return CollectionInterfaceInterface|Webhook[] */ - protected function getWebhooksAttribute(): Collection + protected function getWebhooksAttribute(): CollectionInterface { - $collection = Collection::for(Webhook::class); + $collection = ($this->discord->getCollectionClass())::for(Webhook::class); foreach ($this->attributes['webhooks'] ?? [] as $webhook) { $collection->pushItem($this->factory->part(Webhook::class, (array) $webhook, true)); @@ -208,9 +208,9 @@ protected function getWebhooksAttribute(): Collection * * @throws \InvalidArgumentException * - * @return Collection|Entry[] + * @return CollectionInterfaceInterface|Entry[] */ - public function searchByType(int $action_type): Collection + public function searchByType(int $action_type): CollectionInterface { $types = array_values((new ReflectionClass(Entry::class))->getConstants()); diff --git a/src/Discord/Parts/Guild/AuditLog/Entry.php b/src/Discord/Parts/Guild/AuditLog/Entry.php index 70ccc9979..f2a483142 100644 --- a/src/Discord/Parts/Guild/AuditLog/Entry.php +++ b/src/Discord/Parts/Guild/AuditLog/Entry.php @@ -11,7 +11,7 @@ namespace Discord\Parts\Guild\AuditLog; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Part; use Discord\Parts\User\User; @@ -121,11 +121,11 @@ protected function getUserAttribute(): ?User * * @link https://discord.com/developers/docs/resources/audit-log#audit-log-change-object * - * @return Collection + * @return CollectionInterface */ - protected function getChangesAttribute(): Collection + protected function getChangesAttribute(): CollectionInterface { - return new Collection($this->attributes['changes'] ?? [], 'key', null); + return new ($this->discord->getCollectionClass())($this->attributes['changes'] ?? [], 'key', null); } /** diff --git a/src/Discord/Parts/Guild/AutoModeration/Rule.php b/src/Discord/Parts/Guild/AutoModeration/Rule.php index 935f3e277..a79202490 100644 --- a/src/Discord/Parts/Guild/AutoModeration/Rule.php +++ b/src/Discord/Parts/Guild/AutoModeration/Rule.php @@ -11,7 +11,7 @@ namespace Discord\Parts\Guild\AutoModeration; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Channel\Channel; use Discord\Parts\Guild\Guild; use Discord\Parts\Guild\Role; @@ -39,10 +39,10 @@ * @property int $event_type The rule event type. * @property int $trigger_type The rule trigger type. * @property object $trigger_metadata The rule trigger metadata (may contain `keyword_filter`, `regex_patterns`, `presets`, `allow_list`, `mention_total_limit` and `mention_raid_protection_enabled`). - * @property Collection|Action[] $actions The actions which will execute when the rule is triggered. + * @property CollectionInterface|Action[] $actions The actions which will execute when the rule is triggered. * @property bool $enabled Whether the rule is enabled. - * @property Collection|?Role[] $exempt_roles The role ids that should not be affected by the rule (Maximum of 20). - * @property Collection|?Channel[] $exempt_channels The channel ids that should not be affected by the rule (Maximum of 50). + * @property CollectionInterface|?Role[] $exempt_roles The role ids that should not be affected by the rule (Maximum of 20). + * @property CollectionInterface|?Channel[] $exempt_channels The channel ids that should not be affected by the rule (Maximum of 50). */ class Rule extends Part { @@ -98,11 +98,11 @@ protected function getCreatorAttribute(): ?User /** * Returns the actions attribute. * - * @return Collection|Action[] A collection of actions. + * @return CollectionInterfaceInterface|Action[] A collection of actions. */ - protected function getActionsAttribute(): Collection + protected function getActionsAttribute(): CollectionInterface { - $actions = Collection::for(Action::class, null); + $actions = ($this->discord->getCollectionClass())::for(Action::class, null); foreach ($this->attributes['actions'] as $action) { $actions->pushItem($this->createOf(Action::class, $action)); @@ -114,11 +114,11 @@ protected function getActionsAttribute(): Collection /** * Returns the exempt roles attribute. * - * @return Collection|?Role[] A collection of roles exempt from the rule. + * @return CollectionInterfaceInterface|?Role[] A collection of roles exempt from the rule. */ - protected function getExemptRolesAttribute(): Collection + protected function getExemptRolesAttribute(): CollectionInterface { - $roles = new Collection(); + $roles = new ($this->discord->getCollectionClass())(); if (empty($this->attributes['exempt_roles'])) { return $roles; @@ -138,11 +138,11 @@ protected function getExemptRolesAttribute(): Collection /** * Returns the exempt channels attribute. * - * @return Collection|?Channel[] A collection of channels exempt from the rule. + * @return CollectionInterfaceInterface|?Channel[] A collection of channels exempt from the rule. */ - protected function getExemptChannelsAttribute(): Collection + protected function getExemptChannelsAttribute(): CollectionInterface { - $channels = new Collection(); + $channels = new ($this->discord->getCollectionClass())(); if (empty($this->attributes['exempt_channels'])) { return $channels; diff --git a/src/Discord/Parts/Guild/CommandPermissions.php b/src/Discord/Parts/Guild/CommandPermissions.php index 7d297419b..4b8405c36 100644 --- a/src/Discord/Parts/Guild/CommandPermissions.php +++ b/src/Discord/Parts/Guild/CommandPermissions.php @@ -12,7 +12,7 @@ namespace Discord\Parts\Guild; use Discord\Helpers\BigInt; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Interactions\Command\Permission; use Discord\Parts\Part; @@ -28,7 +28,7 @@ * @property string $application_id The id of the application the command belongs to. * @property string $guild_id The id of the guild. * @property-read Guild|null $guild - * @property Collection|Permission[] $permissions The permissions for the command in the guild. + * @property CollectionInterface|Permission[] $permissions The permissions for the command in the guild. */ class CommandPermissions extends Part { @@ -55,11 +55,11 @@ protected function getGuildAttribute(): ?Guild /** * Gets the permissions attribute. * - * @return Collection|Permission[] A collection of permissions. + * @return CollectionInterfaceInterface|Permission[] A collection of permissions. */ - protected function getPermissionsAttribute(): Collection + protected function getPermissionsAttribute(): CollectionInterface { - $permissions = Collection::for(Permission::class); + $permissions = ($this->discord->getCollectionClass())::for(Permission::class); foreach ($this->attributes['permissions'] ?? [] as $permission) { $permissions->pushItem($this->factory->part(Permission::class, (array) $permission, true)); diff --git a/src/Discord/Parts/Guild/Emoji.php b/src/Discord/Parts/Guild/Emoji.php index b353ee11b..20ce6d6af 100644 --- a/src/Discord/Parts/Guild/Emoji.php +++ b/src/Discord/Parts/Guild/Emoji.php @@ -11,7 +11,7 @@ namespace Discord\Parts\Guild; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Part; use Discord\Parts\User\User; use Stringable; @@ -25,7 +25,7 @@ * * @property ?string $id The identifier for the emoji. * @property string $name The name of the emoji. - * @property Collection|Role[] $roles The roles that are allowed to use the emoji. + * @property CollectionInterface|Role[] $roles The roles that are allowed to use the emoji. * @property User|null $user User that created this emoji. * @property bool|null $require_colons Whether the emoji requires colons to be triggered. * @property bool|null $managed Whether this emoji is managed by a role. @@ -67,11 +67,12 @@ protected function getGuildAttribute(): ?Guild /** * Returns the roles attribute. * - * @return Collection A collection of roles for the emoji. + * @return CollectionInterface A collection of roles for the emoji. */ - protected function getRolesAttribute(): Collection + protected function getRolesAttribute(): CollectionInterface { - $roles = new Collection(); + /** @var CollectionInterface $roles An instance of the collection class implementing CollectionInterface.*/ + $roles = new ($this->discord->getCollectionClass())(); if (empty($this->attributes['roles'])) { return $roles; diff --git a/src/Discord/Parts/Guild/Guild.php b/src/Discord/Parts/Guild/Guild.php index 215bd8a76..f39c7740e 100644 --- a/src/Discord/Parts/Guild/Guild.php +++ b/src/Discord/Parts/Guild/Guild.php @@ -13,7 +13,7 @@ use Carbon\Carbon; use Discord\Exceptions\FileNotFoundException; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Helpers\Multipart; use Discord\Http\Endpoint; use Discord\Http\Exceptions\NoPermissionsException; @@ -305,7 +305,7 @@ class Guild extends Part /** * An array of valid regions. * - * @var Collection|null + * @var CollectionInterface|null */ protected $regions; @@ -423,7 +423,7 @@ protected function setStickersAttribute(?array $stickers): void * * @throws NoPermissionsException Missing manage_guild permission. * - * @return PromiseInterface + * @return PromiseInterface */ public function getInvites(): PromiseInterface { @@ -433,7 +433,7 @@ public function getInvites(): PromiseInterface } return $this->http->get(Endpoint::bind(Endpoint::GUILD_INVITES, $this->id))->then(function ($response) { - $invites = Collection::for(Invite::class, 'code'); + $invites = ($this->discord->getCollectionClass())::for(Invite::class, 'code'); foreach ($response as $invite) { $invite = $this->factory->part(Invite::class, (array) $invite, true); @@ -568,11 +568,11 @@ protected function getSplashHashAttribute(): ?string * * @deprecated 10.0.0 Use `$channel->stage_instances` * - * @return Collection|StageInstance[] + * @return CollectionInterfaceInterface|StageInstance[] */ - protected function getStageInstancesAttribute(): Collection + protected function getStageInstancesAttribute(): CollectionInterface { - $stage_instances = Collection::for(StageInstance::class); + $stage_instances = ($this->discord->getCollectionClass())::for(StageInstance::class); if ($channels = $this->channels) { /** @var Channel */ @@ -753,7 +753,7 @@ public function getVoiceRegions(): PromiseInterface } return $this->http->get('voice/regions')->then(function ($regions) { - $regions = new Collection($regions); + $regions = new ($this->discord->getCollectionClass())($regions); $this->regions = $regions; @@ -1155,7 +1155,7 @@ public function updateRolePositions(array $roles): PromiseInterface * @param string|null $options['query'] Query string to match username(s) and nickname(s) against * @param int|null $options['limit'] How many entries are returned (default 1, minimum 1, maximum 1000) * - * @return PromiseInterface + * @return PromiseInterface */ public function searchMembers(array $options): PromiseInterface { @@ -1176,7 +1176,7 @@ public function searchMembers(array $options): PromiseInterface $endpoint->addQuery('limit', $options['limit']); return $this->http->get($endpoint)->then(function ($responses) { - $members = Collection::for(Member::class); + $members = ($this->discord->getCollectionClass())::for(Member::class); foreach ($responses as $response) { if (! $member = $this->members->get('id', $response->user->id)) { diff --git a/src/Discord/Parts/Guild/ScheduledEvent.php b/src/Discord/Parts/Guild/ScheduledEvent.php index 49b571776..e4e3811ff 100644 --- a/src/Discord/Parts/Guild/ScheduledEvent.php +++ b/src/Discord/Parts/Guild/ScheduledEvent.php @@ -12,7 +12,7 @@ namespace Discord\Parts\Guild; use Carbon\Carbon; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Http\Endpoint; use Discord\Parts\Channel\Channel; use Discord\Parts\Part; @@ -97,7 +97,7 @@ class ScheduledEvent extends Part * * @throws \RangeException * - * @return PromiseInterface> + * @return PromiseInterface> */ public function getUsers(array $options): PromiseInterface { @@ -126,7 +126,7 @@ public function getUsers(array $options): PromiseInterface } return $this->http->get($endpoint)->then(function ($responses) { - $users = new Collection(); + $users = new ($this->discord->getCollectionClass())(); $guild = $this->guild; diff --git a/src/Discord/Parts/Guild/WelcomeScreen.php b/src/Discord/Parts/Guild/WelcomeScreen.php index 3ea37c850..b53938b14 100644 --- a/src/Discord/Parts/Guild/WelcomeScreen.php +++ b/src/Discord/Parts/Guild/WelcomeScreen.php @@ -11,7 +11,7 @@ namespace Discord\Parts\Guild; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Part; /** @@ -22,7 +22,7 @@ * @since 7.0.0 * * @property ?string $description The server description shown in the welcome screen. - * @property Collection|WelcomeChannel[] $welcome_channels The channels shown in the welcome screen, up to 5. + * @property CollectionInterface|WelcomeChannel[] $welcome_channels The channels shown in the welcome screen, up to 5. */ class WelcomeScreen extends Part { @@ -37,11 +37,11 @@ class WelcomeScreen extends Part /** * Returns the Welcome Channels of the Welcome Screen. * - * @return Collection|WelcomeChannel[] The channels of welcome screen. + * @return CollectionInterfaceInterface|WelcomeChannel[] The channels of welcome screen. */ - protected function getWelcomeChannelsAttribute(): Collection + protected function getWelcomeChannelsAttribute(): CollectionInterface { - $collection = Collection::for(WelcomeChannel::class, null); + $collection = ($this->discord->getCollectionClass())::for(WelcomeChannel::class, null); foreach ($this->attributes['welcome_channels'] ?? [] as $welcome_channel) { $collection->pushItem($this->createOf(WelcomeChannel::class, $welcome_channel)); diff --git a/src/Discord/Parts/Interactions/Command/Command.php b/src/Discord/Parts/Interactions/Command/Command.php index 139bc83b8..c50591862 100644 --- a/src/Discord/Parts/Interactions/Command/Command.php +++ b/src/Discord/Parts/Interactions/Command/Command.php @@ -11,7 +11,7 @@ namespace Discord\Parts\Interactions\Command; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Guild\Guild; use Discord\Parts\Part; use Stringable; @@ -79,15 +79,15 @@ protected function getApplicationIdAttribute(): string /** * Gets the options attribute. * - * @return Collection|Option[]|null A collection of options. + * @return CollectionInterfaceInterface|Option[]|null A collection of options. */ - protected function getOptionsAttribute(): ?Collection + protected function getOptionsAttribute(): ?CollectionInterface { if (! isset($this->attributes['options']) && (isset($this->type) && $this->type != self::CHAT_INPUT)) { return null; } - $options = Collection::for(Option::class, null); + $options = ($this->discord->getCollectionClass())::for(Option::class, null); foreach ($this->attributes['options'] ?? [] as $option) { $options->pushItem($this->createOf(Option::class, $option)); diff --git a/src/Discord/Parts/Interactions/Command/Option.php b/src/Discord/Parts/Interactions/Command/Option.php index 6900ff6be..6648365e7 100644 --- a/src/Discord/Parts/Interactions/Command/Option.php +++ b/src/Discord/Parts/Interactions/Command/Option.php @@ -11,7 +11,7 @@ namespace Discord\Parts\Interactions\Command; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Part; use function Discord\poly_strlen; @@ -29,8 +29,8 @@ * @property string $description 1-100 character description. * @property ?string[]|null $description_localizations Localization dictionary for the description field. Values follow the same restrictions as description. * @property bool|null $required If the parameter is required or optional--default false. - * @property Collection|Choice[]|null $choices Choices for STRING, INTEGER, and NUMBER types for the user to pick from, max 25. Only for slash commands. - * @property Collection|Option[] $options Sub-options if applicable. + * @property CollectionInterface|Choice[]|null $choices Choices for STRING, INTEGER, and NUMBER types for the user to pick from, max 25. Only for slash commands. + * @property CollectionInterface|Option[] $options Sub-options if applicable. * @property array|null $channel_types If the option is a channel type, the channels shown will be restricted to these types. * @property int|float|null $min_value If the option is an INTEGER or NUMBER type, the minimum value permitted. * @property int|float|null $max_value If the option is an INTEGER or NUMBER type, the maximum value permitted. @@ -75,15 +75,15 @@ class Option extends Part /** * Gets the choices attribute. * - * @return Collection|Choice[]|null A collection of choices. + * @return CollectionInterfaceInterface|Choice[]|null A collection of choices. */ - protected function getChoicesAttribute(): ?Collection + protected function getChoicesAttribute(): ?CollectionInterface { if (! isset($this->attributes['choices']) && ! in_array($this->type, [self::STRING, self::INTEGER, self::NUMBER])) { return null; } - $choices = Collection::for(Choice::class, null); + $choices = ($this->discord->getCollectionClass())::for(Choice::class, null); foreach ($this->attributes['choices'] ?? [] as $choice) { $choices->pushItem($this->createOf(Choice::class, $choice)); @@ -95,11 +95,11 @@ protected function getChoicesAttribute(): ?Collection /** * Gets the options attribute. * - * @return Collection|Option[] A collection of options. + * @return CollectionInterfaceInterface|Option[] A collection of options. */ - protected function getOptionsAttribute(): Collection + protected function getOptionsAttribute(): CollectionInterface { - $options = Collection::for(Option::class, null); + $options = ($this->discord->getCollectionClass())::for(Option::class, null); foreach ($this->attributes['options'] ?? [] as $option) { $options->pushItem($this->createOf(Option::class, $option)); diff --git a/src/Discord/Parts/Interactions/Interaction.php b/src/Discord/Parts/Interactions/Interaction.php index 0def5a361..132b9b1e4 100644 --- a/src/Discord/Parts/Interactions/Interaction.php +++ b/src/Discord/Parts/Interactions/Interaction.php @@ -13,7 +13,7 @@ use Discord\Builders\Components\Component; use Discord\Builders\MessageBuilder; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Helpers\Multipart; use Discord\Http\Endpoint; use Discord\Parts\Channel\Channel; @@ -610,7 +610,7 @@ public function showModal(string $title, string $custom_id, array $components, ? if ($submit) { $listener = function (Interaction $interaction) use ($custom_id, $submit, &$listener) { if ($interaction->type == self::TYPE_MODAL_SUBMIT && $interaction->data->custom_id == $custom_id) { - $components = Collection::for(RequestComponent::class, 'custom_id'); + $components = ($this->discord->getCollectionClass())::for(RequestComponent::class, 'custom_id'); foreach ($interaction->data->components as $actionrow) { if ($actionrow->type == Component::TYPE_ACTION_ROW) { foreach ($actionrow->components as $component) { diff --git a/src/Discord/Parts/Interactions/Request/Component.php b/src/Discord/Parts/Interactions/Request/Component.php index a6a7a8a8d..9150f12ce 100644 --- a/src/Discord/Parts/Interactions/Request/Component.php +++ b/src/Discord/Parts/Interactions/Request/Component.php @@ -12,7 +12,7 @@ namespace Discord\Parts\Interactions\Request; use Discord\Builders\Components\Component as ComponentBuilder; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Guild\Emoji; use Discord\Parts\Part; @@ -36,7 +36,7 @@ * @property string|null $placeholder Custom placeholder text if nothing is selected; max 150 characters. (Select Menus, Text Inputs) * @property int|null $min_values The minimum number of items that must be chosen; default 1, min 0, max 25. (Select Menus) * @property int|null $max_values The maximum number of items that can be chosen; default 1, max 25. (Select Menus) - * @property Collection|Component[]|null $components A list of child components. (Action Rows) + * @property CollectionInterface|Component[]|null $components A list of child components. (Action Rows) * @property int|null $min_length Minimum input length for a text input. (Text Inputs) * @property int|null $max_length Maximum input length for a text input. (Text Inputs) * @property bool|null $required Whether this component is required to be filled; defaults to `true` (Text Inputs) @@ -69,15 +69,15 @@ class Component extends Part /** * Gets the sub-components of the component. * - * @return Collection|Component[]|null $components + * @return CollectionInterfaceInterface|Component[]|null $components */ - protected function getComponentsAttribute(): ?Collection + protected function getComponentsAttribute(): ?CollectionInterface { if (! isset($this->attributes['components']) && $this->type != ComponentBuilder::TYPE_ACTION_ROW) { return null; } - $components = Collection::for(Component::class, null); + $components = ($this->discord->getCollectionClass())::for(Component::class, null); foreach ($this->attributes['components'] ?? [] as $component) { $components->pushItem($this->createOf(Component::class, $component)); diff --git a/src/Discord/Parts/Interactions/Request/InteractionData.php b/src/Discord/Parts/Interactions/Request/InteractionData.php index b18a2e367..de6aee0a9 100644 --- a/src/Discord/Parts/Interactions/Request/InteractionData.php +++ b/src/Discord/Parts/Interactions/Request/InteractionData.php @@ -11,7 +11,7 @@ namespace Discord\Parts\Interactions\Request; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Interactions\Command\Command; use Discord\Parts\Part; @@ -26,13 +26,13 @@ * @property string $name Name of the invoked command. * @property int $type The type of the invoked command. * @property Resolved|null $resolved Resolved users, members, roles and channels that are relevant. - * @property Collection|Option[]|null $options Parameters and values from the user. + * @property CollectionInterface|Option[]|null $options Parameters and values from the user. * @property string|null $guild_id ID of the guild internally passed from Interaction or ID of the guild the command belongs to. * @property string|null $target_id ID the of user or message targeted by a user or message command. * @property string|null $custom_id Custom ID the component was created for. (Only for Message Component & Modal) * @property int|null $component_type Type of the component. (Only for Message Component) * @property string[]|null $values Values selected in a select menu. (Only for Message Component) - * @property Collection|Component[]|null $components The values submitted by the user. (Only for Modal) + * @property CollectionInterface|Component[]|null $components The values submitted by the user. (Only for Modal) */ class InteractionData extends Part { @@ -58,15 +58,15 @@ class InteractionData extends Part /** * Gets the options of the interaction. * - * @return Collection|Option[]|null $options + * @return CollectionInterfaceInterface|Option[]|null $options */ - protected function getOptionsAttribute(): ?Collection + protected function getOptionsAttribute(): ?CollectionInterface { if (! isset($this->attributes['options']) && $this->type != Command::CHAT_INPUT) { return null; } - $options = Collection::for(Option::class, 'name'); + $options = ($this->discord->getCollectionClass())::for(Option::class, 'name'); foreach ($this->attributes['options'] ?? [] as $option) { $options->pushItem($this->createOf(Option::class, $option)); @@ -78,15 +78,15 @@ protected function getOptionsAttribute(): ?Collection /** * Gets the components of the interaction. * - * @return Collection|Component[]|null $components + * @return CollectionInterfaceInterface|Component[]|null $components */ - protected function getComponentsAttribute(): ?Collection + protected function getComponentsAttribute(): ?CollectionInterface { if (! isset($this->attributes['components'])) { return null; } - $components = Collection::for(Component::class, null); + $components = ($this->discord->getCollectionClass())::for(Component::class, null); foreach ($this->attributes['components'] as $component) { $components->pushItem($this->createOf(Component::class, $component)); diff --git a/src/Discord/Parts/Interactions/Request/Option.php b/src/Discord/Parts/Interactions/Request/Option.php index 05e561280..9a23d936e 100644 --- a/src/Discord/Parts/Interactions/Request/Option.php +++ b/src/Discord/Parts/Interactions/Request/Option.php @@ -11,7 +11,7 @@ namespace Discord\Parts\Interactions\Request; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Interactions\Command\Option as CommandOption; use Discord\Parts\Part; @@ -25,7 +25,7 @@ * @property string $name Name of the parameter. * @property int $type Type of the option. * @property string|int|float|bool|null $value Value of the option resulting from user input. - * @property Collection|Option[]|null $options Present if this option is a group or subcommand. + * @property CollectionInterface|Option[]|null $options Present if this option is a group or subcommand. * @property bool|null $focused `true` if this option is the currently focused option for autocomplete. */ class Option extends Part @@ -44,15 +44,15 @@ class Option extends Part /** * Gets the options of the interaction. * - * @return Collection|Option[]|null $options + * @return CollectionInterfaceInterface|Option[]|null $options */ - protected function getOptionsAttribute(): ?Collection + protected function getOptionsAttribute(): ?CollectionInterface { if (! isset($this->attributes['options']) && ! in_array($this->type, [CommandOption::SUB_COMMAND, CommandOption::SUB_COMMAND_GROUP])) { return null; } - $options = Collection::for(Option::class, 'name'); + $options = ($this->discord->getCollectionClass())::for(Option::class, 'name'); foreach ($this->attributes['options'] ?? [] as $option) { $options->pushItem($this->createOf(Option::class, $option)); diff --git a/src/Discord/Parts/Interactions/Request/Resolved.php b/src/Discord/Parts/Interactions/Request/Resolved.php index 12f7ce7fb..e9cde45eb 100644 --- a/src/Discord/Parts/Interactions/Request/Resolved.php +++ b/src/Discord/Parts/Interactions/Request/Resolved.php @@ -11,7 +11,7 @@ namespace Discord\Parts\Interactions\Request; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Channel\Attachment; use Discord\Parts\Channel\Channel; use Discord\Parts\Channel\Message; @@ -28,12 +28,12 @@ * * @since 7.0.0 * - * @property Collection|User[]|null $users The ids and User objects. - * @property Collection|Member[]|null $members The ids and partial Member objects. - * @property Collection|Role[]|null $roles The ids and Role objects. - * @property Collection|Channel[]|Thread[]|null $channels The ids and partial Channel objects. - * @property Collection|Message[]|null $messages The ids and partial Message objects. - * @property Collection|Attachment[]|null $attachments The ids and partial Attachment objects. + * @property CollectionInterface|User[]|null $users The ids and User objects. + * @property CollectionInterface|Member[]|null $members The ids and partial Member objects. + * @property CollectionInterface|Role[]|null $roles The ids and Role objects. + * @property CollectionInterface|Channel[]|Thread[]|null $channels The ids and partial Channel objects. + * @property CollectionInterface|Message[]|null $messages The ids and partial Message objects. + * @property CollectionInterface|Attachment[]|null $attachments The ids and partial Attachment objects. * * @property string|null $guild_id ID of the guild internally passed from Interaction. */ @@ -62,15 +62,15 @@ class Resolved extends Part /** * Returns a collection of resolved users. * - * @return Collection|User[]|null Map of Snowflakes to user objects + * @return CollectionInterfaceInterface|User[]|null Map of Snowflakes to user objects */ - protected function getUsersAttribute(): ?Collection + protected function getUsersAttribute(): ?CollectionInterface { if (! isset($this->attributes['users'])) { return null; } - $collection = Collection::for(User::class); + $collection = ($this->discord->getCollectionClass())::for(User::class); foreach ($this->attributes['users'] as $snowflake => $user) { $collection->pushItem($this->discord->users->get('id', $snowflake) ?: $this->factory->part(User::class, (array) $user, true)); @@ -84,15 +84,15 @@ protected function getUsersAttribute(): ?Collection * * Partial Member objects are missing user, deaf and mute fields * - * @return Collection|Member[]|null Map of Snowflakes to partial member objects + * @return CollectionInterfaceInterface|Member[]|null Map of Snowflakes to partial member objects */ - protected function getMembersAttribute(): ?Collection + protected function getMembersAttribute(): ?CollectionInterface { if (! isset($this->attributes['members'])) { return null; } - $collection = Collection::for(Member::class); + $collection = ($this->discord->getCollectionClass())::for(Member::class); foreach ($this->attributes['members'] as $snowflake => $member) { if ($guild = $this->discord->guilds->get('id', $this->guild_id)) { @@ -113,15 +113,15 @@ protected function getMembersAttribute(): ?Collection /** * Returns a collection of resolved roles. * - * @return Collection|Role[]|null Map of Snowflakes to role objects + * @return CollectionInterfaceInterface|Role[]|null Map of Snowflakes to role objects */ - protected function getRolesAttribute(): ?Collection + protected function getRolesAttribute(): ?CollectionInterface { if (! isset($this->attributes['roles'])) { return null; } - $collection = Collection::for(Role::class); + $collection = ($this->discord->getCollectionClass())::for(Role::class); foreach ($this->attributes['roles'] as $snowflake => $role) { if ($guild = $this->discord->guilds->get('id', $this->guild_id)) { @@ -143,15 +143,15 @@ protected function getRolesAttribute(): ?Collection * * Partial Channel objects only have id, name, type and permissions fields. Threads will also have thread_metadata and parent_id fields. * - * @return Collection|Channel[]|Thread[]|null Map of Snowflakes to partial channel objects + * @return CollectionInterfaceInterface|Channel[]|Thread[]|null Map of Snowflakes to partial channel objects */ - protected function getChannelsAttribute(): ?Collection + protected function getChannelsAttribute(): ?CollectionInterface { if (! isset($this->attributes['channels'])) { return null; } - $collection = new Collection(); + $collection = new ($this->discord->getCollectionClass())(); foreach ($this->attributes['channels'] as $snowflake => $channel) { if ($guild = $this->discord->guilds->get('id', $this->guild_id)) { @@ -175,15 +175,15 @@ protected function getChannelsAttribute(): ?Collection /** * Returns a collection of resolved messages. * - * @return Collection|Message[]|null Map of Snowflakes to partial messages objects + * @return CollectionInterfaceInterface|Message[]|null Map of Snowflakes to partial messages objects */ - protected function getMessagesAttribute(): ?Collection + protected function getMessagesAttribute(): ?CollectionInterface { if (! isset($this->attributes['messages'])) { return null; } - $collection = Collection::for(Message::class); + $collection = ($this->discord->getCollectionClass())::for(Message::class); foreach ($this->attributes['messages'] as $snowflake => $message) { if ($guild = $this->discord->guilds->get('id', $this->guild_id)) { @@ -201,15 +201,15 @@ protected function getMessagesAttribute(): ?Collection /** * Returns a collection of resolved attachments. * - * @return Collection|Attachment[]|null Map of Snowflakes to attachments objects + * @return CollectionInterfaceInterface|Attachment[]|null Map of Snowflakes to attachments objects */ - protected function getAttachmentsAttribute(): ?Collection + protected function getAttachmentsAttribute(): ?CollectionInterface { if (! isset($this->attributes['attachments'])) { return null; } - $attachments = Collection::for(Attachment::class); + $attachments = ($this->discord->getCollectionClass())::for(Attachment::class); foreach ($this->attributes['attachments'] as $attachment) { $attachments->pushItem($this->factory->part(Attachment::class, (array) $attachment, true)); diff --git a/src/Discord/Parts/Thread/Thread.php b/src/Discord/Parts/Thread/Thread.php index 044d5e605..2580940ae 100644 --- a/src/Discord/Parts/Thread/Thread.php +++ b/src/Discord/Parts/Thread/Thread.php @@ -13,7 +13,7 @@ use Carbon\Carbon; use Discord\Builders\MessageBuilder; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Http\Endpoint; use Discord\Http\Exceptions\NoPermissionsException; use Discord\Parts\Channel\Channel; @@ -462,7 +462,7 @@ public function setAutoArchiveDuration(int $duration, ?string $reason = null): P * * @link https://discord.com/developers/docs/resources/channel#get-pinned-messages * - * @return PromiseInterface> + * @return PromiseInterface> * * @todo Make it in a trait along with Channel */ @@ -470,7 +470,7 @@ public function getPinnedMessages(): PromiseInterface { return $this->http->get(Endpoint::bind(Endpoint::CHANNEL_PINS, $this->id)) ->then(function ($responses) { - $messages = Collection::for(Message::class); + $messages = ($this->discord->getCollectionClass())::for(Message::class); foreach ($responses as $response) { $messages->pushItem($this->messages->get('id', $response->id) ?: $this->messages->create($response, true)); @@ -546,7 +546,7 @@ public function deleteMessages($messages, ?string $reason = null): PromiseInterf * @param string|Message|null $options['after'] Get messages after this message ID. * @param int|null $options['limit'] Max number of messages to return (1-100). Defaults to 50. * - * @return PromiseInterface> + * @return PromiseInterface> * * @todo Make it in a trait along with Channel */ @@ -586,7 +586,7 @@ public function getMessageHistory(array $options = []): PromiseInterface } return $this->http->get($endpoint)->then(function ($responses) { - $messages = Collection::for(Message::class); + $messages = ($this->discord->getCollectionClass())::for(Message::class); foreach ($responses as $response) { if (! $message = $this->messages->get('id', $response->id)) { @@ -770,14 +770,14 @@ public function broadcastTyping(): PromiseInterface * @param int $options ['time'] Time in milliseconds until the collector finishes or false. * @param int $options ['limit'] The amount of messages allowed or false. * - * @return PromiseInterface> + * @return PromiseInterface> * * @todo Make it in a trait along with Channel */ public function createMessageCollector(callable $filter, array $options = []): PromiseInterface { $deferred = new Deferred(); - $messages = new Collection([], null, null); + $messages = new ($this->discord->getCollectionClass())([], null, null); $timer = null; $options = array_merge([ diff --git a/src/Discord/Parts/User/Member.php b/src/Discord/Parts/User/Member.php index cdf2088e7..59507da22 100644 --- a/src/Discord/Parts/User/Member.php +++ b/src/Discord/Parts/User/Member.php @@ -14,7 +14,7 @@ use Carbon\Carbon; use Discord\Builders\MessageBuilder; use Discord\Helpers\BigInt; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Http\Endpoint; use Discord\Http\Exceptions\NoPermissionsException; use Discord\Parts\Channel\Channel; @@ -46,7 +46,7 @@ * @property-read string $displayname The nickname or display name with optional discriminator of the member. * @property ?string|null $avatar The avatar URL of the member or null if member has no guild avatar. * @property ?string|null $avatar_hash The avatar hash of the member or null if member has no guild avatar. - * @property Collection|Role[] $roles A collection of Roles that the member has. + * @property CollectionInterface|Role[] $roles A collection of Roles that the member has. * @property Carbon|null $joined_at A timestamp of when the member joined the guild. * @property Carbon|null $premium_since When the user started boosting the server. * @property bool $deaf Whether the member is deaf. @@ -61,7 +61,7 @@ * @property string $id The unique identifier of the member. * @property string $status The status of the member. * @property-read Activity $game The game the member is playing. - * @property Collection|Activity[] $activities User's current activities. + * @property CollectionInterface|Activity[] $activities User's current activities. * @property object $client_status Current client status. * * @method PromiseInterface sendMessage(MessageBuilder $builder) @@ -609,11 +609,11 @@ protected function getGameAttribute(): ?Activity /** * Gets the activities attribute. * - * @return Collection|Activity[] + * @return CollectionInterfaceInterface|Activity[] */ - protected function getActivitiesAttribute(): Collection + protected function getActivitiesAttribute(): CollectionInterface { - $activities = Collection::for(Activity::class, null); + $activities = ($this->discord->getCollectionClass())::for(Activity::class, null); foreach ($this->attributes['activities'] ?? [] as $activity) { $activities->pushItem($this->createOf(Activity::class, $activity)); @@ -685,11 +685,11 @@ protected function getGuildAttribute(): ?Guild /** * Returns the roles attribute. * - * @return Collection A collection of roles the member is in. null role only contains ID in the collection. + * @return CollectionInterfaceInterface A collection of roles the member is in. null role only contains ID in the collection. */ - protected function getRolesAttribute(): Collection + protected function getRolesAttribute(): CollectionInterface { - $roles = new Collection(); + $roles = new ($this->discord->getCollectionClass())(); if (empty($this->attributes['roles'])) { return $roles; diff --git a/src/Discord/Parts/WebSockets/PresenceUpdate.php b/src/Discord/Parts/WebSockets/PresenceUpdate.php index 911e9306b..8c1635824 100644 --- a/src/Discord/Parts/WebSockets/PresenceUpdate.php +++ b/src/Discord/Parts/WebSockets/PresenceUpdate.php @@ -11,7 +11,7 @@ namespace Discord\Parts\WebSockets; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Guild\Guild; use Discord\Parts\Guild\Role; use Discord\Parts\Part; @@ -32,7 +32,7 @@ * @property string $guild_id The unique identifier of the guild that the presence update affects. * @property-read Guild|null $guild The guild that the presence update affects. * @property string $status The updated status of the user. - * @property Collection|Activity[] $activities The activities of the user. + * @property CollectionInterface|Activity[] $activities The activities of the user. * @property-read Activity $game The updated game of the user. * @property object $client_status Status of the client. * @property string|null $desktop_status Status of the user on their desktop client. Null if they are not active on desktop. @@ -40,7 +40,7 @@ * @property string|null $web_status Status of the user on their web client. Null if they are not active on web. * * @property-read Member $member The member that the presence update affects. - * @property-read Collection|Role[] $roles Roles that the user has in the guild. + * @property-read CollectionInterface|Role[] $roles Roles that the user has in the guild. */ class PresenceUpdate extends Part { @@ -93,11 +93,11 @@ protected function getGuildAttribute(): ?Guild /** * Gets the activities attribute. * - * @return Collection|Activity[] + * @return CollectionInterfaceInterface|Activity[] */ - protected function getActivitiesAttribute(): Collection + protected function getActivitiesAttribute(): CollectionInterface { - $collection = Collection::for(Activity::class, null); + $collection = ($this->discord->getCollectionClass())::for(Activity::class, null); foreach ($this->attributes['activities'] ?? [] as $activity) { $collection->pushItem($this->factory->part(Activity::class, (array) $activity, true)); @@ -163,14 +163,14 @@ protected function getMemberAttribute(): ?Member /** * Returns the users roles. * - * @return Collection|Role[] + * @return CollectionInterfaceInterface|Role[] */ - protected function getRolesAttribute(): Collection + protected function getRolesAttribute(): CollectionInterface { if ($member = $this->member) { return $member->roles; } - return Collection::for(Role::class); + return ($this->discord->getCollectionClass())::for(Role::class); } } diff --git a/src/Discord/Repository/AbstractRepository.php b/src/Discord/Repository/AbstractRepository.php index e6dd14dd9..6c43c730c 100755 --- a/src/Discord/Repository/AbstractRepository.php +++ b/src/Discord/Repository/AbstractRepository.php @@ -12,7 +12,19 @@ namespace Discord\Repository; use Discord\Helpers\CacheWrapper; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; +use Discord\Helpers\CollectionTrait; +use Discord\Helpers\LegacyCacheWrapper; +use Discord\Http\Endpoint; +use Discord\Http\Http; +use Discord\Parts\Part; +use React\Promise\PromiseInterface; +use Traversable; +use WeakReference; + +use function Discord\nowait; +use function React\Promise\reject; +use function React\Promise\resolve; /** * Repositories provide a way to store and update parts on the Discord server. @@ -25,7 +37,7 @@ * @property string $discrim The discriminator. * @property-read CacheWrapper $cache The react/cache wrapper. */ -abstract class AbstractRepository extends Collection +abstract class AbstractRepository implements CollectionInterface { use AbstractRepositoryTrait; -} \ No newline at end of file +} diff --git a/src/Discord/Repository/Channel/ThreadRepository.php b/src/Discord/Repository/Channel/ThreadRepository.php index e4dabada2..1b85402bf 100644 --- a/src/Discord/Repository/Channel/ThreadRepository.php +++ b/src/Discord/Repository/Channel/ThreadRepository.php @@ -11,7 +11,7 @@ namespace Discord\Repository\Channel; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Http\Endpoint; use Discord\Parts\Thread\Thread; use Discord\Repository\AbstractRepository; @@ -87,7 +87,7 @@ protected function cacheFreshen($response): PromiseInterface * * @link https://discord.com/developers/docs/resources/channel#list-active-threads * - * @return PromiseInterface> + * @return PromiseInterface> */ public function active(): PromiseInterface { @@ -109,7 +109,7 @@ public function active(): PromiseInterface * * @throws \InvalidArgumentException * - * @return PromiseInterface> + * @return PromiseInterface> */ public function archived(bool $private = false, bool $joined = false, ?int $limit = null, $before = null): PromiseInterface { @@ -150,11 +150,11 @@ public function archived(bool $private = false, bool $joined = false, ?int $limi * * @param object $response * - * @return Collection|Thread[] + * @return CollectionInterfaceInterface|Thread[] */ - private function handleThreadPaginationResponse(object $response): Collection + private function handleThreadPaginationResponse(object $response): CollectionInterface { - $collection = Collection::for(Thread::class); + $collection = ($this->discord->getCollectionClass())::for(Thread::class); foreach ($response->threads as $thread) { /** @var Thread */ diff --git a/src/Discord/Voice/VoiceClient.php b/src/Discord/Voice/VoiceClient.php index 398c30d0f..f01d28fa2 100644 --- a/src/Discord/Voice/VoiceClient.php +++ b/src/Discord/Voice/VoiceClient.php @@ -16,7 +16,7 @@ use Discord\Exceptions\LibSodiumNotFoundException; use Discord\Exceptions\OutdatedDCAException; use Discord\Helpers\Buffer as RealBuffer; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Channel\Channel; use Discord\WebSockets\Op; use Evenement\EventEmitter; @@ -371,7 +371,7 @@ public function __construct(WebSocket $websocket, LoopInterface $loop, Channel $ $this->deaf = $data['deaf']; $this->mute = $data['mute']; $this->endpoint = str_replace([':80', ':443'], '', $data['endpoint']); - $this->speakingStatus = new Collection([], 'ssrc'); + $this->speakingStatus = new ($this->discord->getCollectionClass())([], 'ssrc'); $this->dnsConfig = $data['dnsConfig']; } @@ -1341,7 +1341,7 @@ public function close(): void $this->sentLoginFrame = false; $this->startTime = null; $this->streamTime = 0; - $this->speakingStatus = new Collection([], 'ssrc'); + $this->speakingStatus = new ($this->discord->getCollectionClass())([], 'ssrc'); $this->emit('close'); } diff --git a/src/Discord/WebSockets/Events/GuildEmojisUpdate.php b/src/Discord/WebSockets/Events/GuildEmojisUpdate.php index 77dcf0692..ad830ec47 100644 --- a/src/Discord/WebSockets/Events/GuildEmojisUpdate.php +++ b/src/Discord/WebSockets/Events/GuildEmojisUpdate.php @@ -11,7 +11,7 @@ namespace Discord\WebSockets\Events; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\WebSockets\Event; use Discord\Parts\Guild\Emoji; use Discord\Parts\Guild\Guild; @@ -28,8 +28,8 @@ class GuildEmojisUpdate extends Event */ public function handle($data) { - $oldEmojis = Collection::for(Emoji::class); - $emojiParts = Collection::for(Emoji::class); + $oldEmojis = ($this->discord->getCollectionClass())::for(Emoji::class); + $emojiParts = ($this->discord->getCollectionClass())::for(Emoji::class); /** @var ?Guild */ if ($guild = yield $this->discord->guilds->cacheGet($data->guild_id)) { diff --git a/src/Discord/WebSockets/Events/GuildStickersUpdate.php b/src/Discord/WebSockets/Events/GuildStickersUpdate.php index 966bf7455..2e9c9c40a 100644 --- a/src/Discord/WebSockets/Events/GuildStickersUpdate.php +++ b/src/Discord/WebSockets/Events/GuildStickersUpdate.php @@ -11,7 +11,7 @@ namespace Discord\WebSockets\Events; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\WebSockets\Event; use Discord\Parts\Guild\Guild; use Discord\Parts\Guild\Sticker; @@ -28,8 +28,8 @@ class GuildStickersUpdate extends Event */ public function handle($data) { - $oldStickers = Collection::for(Sticker::class); - $stickerParts = Collection::for(Sticker::class); + $oldStickers = ($this->discord->getCollectionClass())::for(Sticker::class); + $stickerParts = ($this->discord->getCollectionClass())::for(Sticker::class); /** @var ?Guild */ if ($guild = yield $this->discord->guilds->cacheGet($data->guild_id)) { diff --git a/src/Discord/WebSockets/Events/MessageDeleteBulk.php b/src/Discord/WebSockets/Events/MessageDeleteBulk.php index 99b91972e..c56d3a2c3 100644 --- a/src/Discord/WebSockets/Events/MessageDeleteBulk.php +++ b/src/Discord/WebSockets/Events/MessageDeleteBulk.php @@ -11,7 +11,7 @@ namespace Discord\WebSockets\Events; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\WebSockets\Event; /** @@ -26,7 +26,7 @@ class MessageDeleteBulk extends Event */ public function handle($data) { - $resolved = new Collection(); + $resolved = new ($this->discord->getCollectionClass())(); foreach ($data->ids as $id) { $event = new MessageDelete($this->discord); diff --git a/src/Discord/WebSockets/Events/ThreadListSync.php b/src/Discord/WebSockets/Events/ThreadListSync.php index 4333274e4..5650277c2 100644 --- a/src/Discord/WebSockets/Events/ThreadListSync.php +++ b/src/Discord/WebSockets/Events/ThreadListSync.php @@ -11,7 +11,7 @@ namespace Discord\WebSockets\Events; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Channel\Channel; use Discord\Parts\Guild\Guild; use Discord\Parts\Thread\Thread; @@ -26,7 +26,7 @@ class ThreadListSync extends Event { public function handle($data) { - $threadParts = Collection::for(Thread::class); + $threadParts = ($this->discord->getCollectionClass())::for(Thread::class); /** @var ?Guild */ if ($guild = yield $this->discord->guilds->cacheGet($data->guild_id)) { diff --git a/tests/Parts/Channel/ChannelTest.php b/tests/Parts/Channel/ChannelTest.php index 24d195b38..eb618aad7 100644 --- a/tests/Parts/Channel/ChannelTest.php +++ b/tests/Parts/Channel/ChannelTest.php @@ -13,7 +13,7 @@ use Discord\Builders\MessageBuilder; use Discord\Discord; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Channel\Channel; use Discord\Parts\Channel\Message; use Discord\Parts\Channel\Invite; diff --git a/tests/Parts/Channel/Message/EmptyMessageTest.php b/tests/Parts/Channel/Message/EmptyMessageTest.php index 2eb476a8f..944d2a7ba 100644 --- a/tests/Parts/Channel/Message/EmptyMessageTest.php +++ b/tests/Parts/Channel/Message/EmptyMessageTest.php @@ -13,7 +13,7 @@ use Carbon\Carbon; use Discord\Discord; -use Discord\Helpers\Collection; +use Discord\Helpers\CollectionInterface; use Discord\Parts\Channel\Channel; use Discord\Parts\Channel\Message; use Discord\Parts\Embed\Embed; From bd8c0543ddd1148db84060ddafb9f0da95d7f79f Mon Sep 17 00:00:00 2001 From: Valithor Obsidion Date: Tue, 24 Dec 2024 11:31:22 -0500 Subject: [PATCH 03/14] CollectionInterface typing --- src/Discord/DiscordCommandClient.php | 6 ++-- src/Discord/Parts/Channel/Reaction.php | 2 +- src/Discord/Parts/Embed/Embed.php | 26 +++++++------- src/Discord/Parts/Guild/AuditLog/AuditLog.php | 18 +++++----- src/Discord/Parts/Guild/AuditLog/Entry.php | 16 ++++----- .../Parts/Guild/AutoModeration/Rule.php | 6 ++-- .../Parts/Guild/CommandPermissions.php | 2 +- src/Discord/Parts/Guild/Guild.php | 4 +-- src/Discord/Parts/Guild/WelcomeScreen.php | 2 +- .../Parts/Interactions/Command/Command.php | 2 +- .../Parts/Interactions/Command/Option.php | 4 +-- .../Parts/Interactions/Request/Component.php | 2 +- .../Interactions/Request/InteractionData.php | 4 +-- .../Parts/Interactions/Request/Option.php | 2 +- .../Parts/Interactions/Request/Resolved.php | 12 +++---- src/Discord/Parts/User/Member.php | 4 +-- .../Parts/WebSockets/PresenceUpdate.php | 4 +-- .../Repository/Channel/ThreadRepository.php | 2 +- tests/DiscordTest.php | 2 +- tests/Parts/Channel/ChannelTest.php | 36 +++++++++---------- .../Channel/Message/EmbedMessageTest.php | 2 +- .../Channel/Message/EmptyMessageTest.php | 26 +++++++------- tests/Parts/Channel/Message/MessageTest.php | 4 +-- .../Channel/Message/RemoveReactionTest.php | 8 ++--- tests/Parts/Embed/EmbedTest.php | 4 +-- 25 files changed, 100 insertions(+), 100 deletions(-) diff --git a/src/Discord/DiscordCommandClient.php b/src/Discord/DiscordCommandClient.php index d67943b92..c27abe1c7 100644 --- a/src/Discord/DiscordCommandClient.php +++ b/src/Discord/DiscordCommandClient.php @@ -99,7 +99,7 @@ public function __construct(array $options = []) $message ->reply($result) ->then(null, $this->commandClientOptions['internalRejectedPromiseHandler']) - ->done(); + ->then(); } } }); @@ -162,7 +162,7 @@ public function __construct(array $options = []) $message->channel ->sendEmbed($embed) ->then(null, $this->commandClientOptions['internalRejectedPromiseHandler']) - ->done(); + ->then(); return; } @@ -209,7 +209,7 @@ public function __construct(array $options = []) $message->channel ->sendEmbed($embed) ->then(null, $this->commandClientOptions['internalRejectedPromiseHandler']) - ->done(); + ->then(); }, [ 'description' => 'Provides a list of commands available.', 'usage' => '[command]', diff --git a/src/Discord/Parts/Channel/Reaction.php b/src/Discord/Parts/Channel/Reaction.php index 762a46bcc..cb0119a3f 100644 --- a/src/Discord/Parts/Channel/Reaction.php +++ b/src/Discord/Parts/Channel/Reaction.php @@ -193,7 +193,7 @@ public function getAllUsers(): PromiseInterface $options['after'] = $after; } - return $this->getUsers($options)->then(function (Collection $users) use ($response, &$getUsers) { + return $this->getUsers($options)->then(function (CollectionInterface $users) use ($response, &$getUsers) { $last = null; foreach ($users as $user) { $response->pushItem($user); diff --git a/src/Discord/Parts/Embed/Embed.php b/src/Discord/Parts/Embed/Embed.php index 5af6c67e7..727d9750e 100644 --- a/src/Discord/Parts/Embed/Embed.php +++ b/src/Discord/Parts/Embed/Embed.php @@ -24,18 +24,18 @@ * * @since 4.0.3 * - * @property string|null $title The title of the embed. - * @property-read string|null $type The type of the embed. - * @property string|null $description A description of the embed. - * @property string|null $url The URL of the embed. - * @property Carbon|null $timestamp A timestamp of the embed. - * @property int|null $color The color of the embed. - * @property Footer|null $footer The footer of the embed. - * @property Image|null $image The image of the embed. - * @property Image|null $thumbnail The thumbnail of the embed. - * @property-read Video|null $video The video of the embed. - * @property-read object|null $provider The provider of the embed. - * @property Author|null $author The author of the embed. + * @property string|null $title The title of the embed. + * @property-read string|null $type The type of the embed. + * @property string|null $description A description of the embed. + * @property string|null $url The URL of the embed. + * @property Carbon|null $timestamp A timestamp of the embed. + * @property int|null $color The color of the embed. + * @property Footer|null $footer The footer of the embed. + * @property Image|null $image The image of the embed. + * @property Image|null $thumbnail The thumbnail of the embed. + * @property-read Video|null $video The video of the embed. + * @property-read object|null $provider The provider of the embed. + * @property Author|null $author The author of the embed. * @property CollectionInterface|Field[] $fields A collection of embed fields. */ class Embed extends Part @@ -135,7 +135,7 @@ protected function getAuthorAttribute(): Author /** * Gets the fields attribute. * - * @return CollectionInterfaceInterface|Field[] + * @return CollectionInterface|Field[] */ protected function getFieldsAttribute(): CollectionInterface { diff --git a/src/Discord/Parts/Guild/AuditLog/AuditLog.php b/src/Discord/Parts/Guild/AuditLog/AuditLog.php index f787eb954..295611446 100644 --- a/src/Discord/Parts/Guild/AuditLog/AuditLog.php +++ b/src/Discord/Parts/Guild/AuditLog/AuditLog.php @@ -74,7 +74,7 @@ protected function getGuildAttribute(): ?Guild /** * Returns a collection of application commands found in the audit log. * - * @return CollectionInterfaceInterface|Command[] + * @return CollectionInterface|Command[] */ protected function getApplicationCommandsAttribute(): CollectionInterface { @@ -90,7 +90,7 @@ protected function getApplicationCommandsAttribute(): CollectionInterface /** * Returns a collection of audit log entries. * - * @return CollectionInterfaceInterface|Entry[] + * @return CollectionInterface|Entry[] */ protected function getAuditLogEntriesAttribute(): CollectionInterface { @@ -106,7 +106,7 @@ protected function getAuditLogEntriesAttribute(): CollectionInterface /** * Returns a collection of auto moderation rules found in the audit log. * - * @return CollectionInterfaceInterface|Rule[] + * @return CollectionInterface|Rule[] */ protected function getAutoModerationRulesAttribute(): CollectionInterface { @@ -122,7 +122,7 @@ protected function getAutoModerationRulesAttribute(): CollectionInterface /** * Returns a collection of guild scheduled events found in the audit log. * - * @return CollectionInterfaceInterface|ScheduledEvent[] + * @return CollectionInterface|ScheduledEvent[] */ protected function getGuildScheduledEventsAttribute(): CollectionInterface { @@ -140,7 +140,7 @@ protected function getGuildScheduledEventsAttribute(): CollectionInterface * * @link https://discord.com/developers/docs/resources/audit-log#audit-log-object-example-partial-integration-object * - * @return CollectionInterfaceInterface|Integration[] + * @return CollectionInterface|Integration[] */ protected function getIntegrationsAttribute(): CollectionInterface { @@ -156,7 +156,7 @@ protected function getIntegrationsAttribute(): CollectionInterface /** * Returns a collection of threads found in the audit log. * - * @return CollectionInterfaceInterface|Thread[] + * @return CollectionInterface|Thread[] */ protected function getThreadsAttribute(): CollectionInterface { @@ -172,7 +172,7 @@ protected function getThreadsAttribute(): CollectionInterface /** * Returns a collection of users found in the audit log. * - * @return CollectionInterfaceInterface|User[] + * @return CollectionInterface|User[] */ protected function getUsersAttribute(): CollectionInterface { @@ -188,7 +188,7 @@ protected function getUsersAttribute(): CollectionInterface /** * Returns a collection of webhooks found in the audit log. * - * @return CollectionInterfaceInterface|Webhook[] + * @return CollectionInterface|Webhook[] */ protected function getWebhooksAttribute(): CollectionInterface { @@ -208,7 +208,7 @@ protected function getWebhooksAttribute(): CollectionInterface * * @throws \InvalidArgumentException * - * @return CollectionInterfaceInterface|Entry[] + * @return CollectionInterface|Entry[] */ public function searchByType(int $action_type): CollectionInterface { diff --git a/src/Discord/Parts/Guild/AuditLog/Entry.php b/src/Discord/Parts/Guild/AuditLog/Entry.php index f2a483142..cc03d7a7d 100644 --- a/src/Discord/Parts/Guild/AuditLog/Entry.php +++ b/src/Discord/Parts/Guild/AuditLog/Entry.php @@ -22,14 +22,14 @@ * * @link https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object * - * @property ?string $target_id ID of the affected entity (webhook, user, role, etc.). - * @property Collection $changes Changes made to the target_id. - * @property ?string $user_id The user who made the changes. - * @property-read User|null $user - * @property string $id ID of the entry. - * @property int $action_type Type of action that occurred. - * @property Options|null $options Additional info for certain action types. - * @property string|null $reason The reason for the change (0-512 characters). + * @property ?string $target_id ID of the affected entity (webhook, user, role, etc.). + * @property CollectionInterface $changes Changes made to the target_id. + * @property ?string $user_id The user who made the changes. + * @property-read User|null $user + * @property string $id ID of the entry. + * @property int $action_type Type of action that occurred. + * @property Options|null $options Additional info for certain action types. + * @property string|null $reason The reason for the change (0-512 characters). */ class Entry extends Part { diff --git a/src/Discord/Parts/Guild/AutoModeration/Rule.php b/src/Discord/Parts/Guild/AutoModeration/Rule.php index a79202490..239cfc138 100644 --- a/src/Discord/Parts/Guild/AutoModeration/Rule.php +++ b/src/Discord/Parts/Guild/AutoModeration/Rule.php @@ -98,7 +98,7 @@ protected function getCreatorAttribute(): ?User /** * Returns the actions attribute. * - * @return CollectionInterfaceInterface|Action[] A collection of actions. + * @return CollectionInterface|Action[] A collection of actions. */ protected function getActionsAttribute(): CollectionInterface { @@ -114,7 +114,7 @@ protected function getActionsAttribute(): CollectionInterface /** * Returns the exempt roles attribute. * - * @return CollectionInterfaceInterface|?Role[] A collection of roles exempt from the rule. + * @return CollectionInterface|?Role[] A collection of roles exempt from the rule. */ protected function getExemptRolesAttribute(): CollectionInterface { @@ -138,7 +138,7 @@ protected function getExemptRolesAttribute(): CollectionInterface /** * Returns the exempt channels attribute. * - * @return CollectionInterfaceInterface|?Channel[] A collection of channels exempt from the rule. + * @return CollectionInterface|?Channel[] A collection of channels exempt from the rule. */ protected function getExemptChannelsAttribute(): CollectionInterface { diff --git a/src/Discord/Parts/Guild/CommandPermissions.php b/src/Discord/Parts/Guild/CommandPermissions.php index 4b8405c36..32a85ec57 100644 --- a/src/Discord/Parts/Guild/CommandPermissions.php +++ b/src/Discord/Parts/Guild/CommandPermissions.php @@ -55,7 +55,7 @@ protected function getGuildAttribute(): ?Guild /** * Gets the permissions attribute. * - * @return CollectionInterfaceInterface|Permission[] A collection of permissions. + * @return CollectionInterface|Permission[] A collection of permissions. */ protected function getPermissionsAttribute(): CollectionInterface { diff --git a/src/Discord/Parts/Guild/Guild.php b/src/Discord/Parts/Guild/Guild.php index f39c7740e..1f6087198 100644 --- a/src/Discord/Parts/Guild/Guild.php +++ b/src/Discord/Parts/Guild/Guild.php @@ -568,7 +568,7 @@ protected function getSplashHashAttribute(): ?string * * @deprecated 10.0.0 Use `$channel->stage_instances` * - * @return CollectionInterfaceInterface|StageInstance[] + * @return CollectionInterface|StageInstance[] */ protected function getStageInstancesAttribute(): CollectionInterface { @@ -744,7 +744,7 @@ protected function getFeatureWelcomeScreenEnabledAttribute(): bool * * @link https://discord.com/developers/docs/resources/voice#list-voice-regions * - * @return PromiseInterface + * @return PromiseInterface */ public function getVoiceRegions(): PromiseInterface { diff --git a/src/Discord/Parts/Guild/WelcomeScreen.php b/src/Discord/Parts/Guild/WelcomeScreen.php index b53938b14..3e6124273 100644 --- a/src/Discord/Parts/Guild/WelcomeScreen.php +++ b/src/Discord/Parts/Guild/WelcomeScreen.php @@ -37,7 +37,7 @@ class WelcomeScreen extends Part /** * Returns the Welcome Channels of the Welcome Screen. * - * @return CollectionInterfaceInterface|WelcomeChannel[] The channels of welcome screen. + * @return CollectionInterface|WelcomeChannel[] The channels of welcome screen. */ protected function getWelcomeChannelsAttribute(): CollectionInterface { diff --git a/src/Discord/Parts/Interactions/Command/Command.php b/src/Discord/Parts/Interactions/Command/Command.php index c50591862..b8cf1594a 100644 --- a/src/Discord/Parts/Interactions/Command/Command.php +++ b/src/Discord/Parts/Interactions/Command/Command.php @@ -79,7 +79,7 @@ protected function getApplicationIdAttribute(): string /** * Gets the options attribute. * - * @return CollectionInterfaceInterface|Option[]|null A collection of options. + * @return CollectionInterface|Option[]|null A collection of options. */ protected function getOptionsAttribute(): ?CollectionInterface { diff --git a/src/Discord/Parts/Interactions/Command/Option.php b/src/Discord/Parts/Interactions/Command/Option.php index 6648365e7..80ea54805 100644 --- a/src/Discord/Parts/Interactions/Command/Option.php +++ b/src/Discord/Parts/Interactions/Command/Option.php @@ -75,7 +75,7 @@ class Option extends Part /** * Gets the choices attribute. * - * @return CollectionInterfaceInterface|Choice[]|null A collection of choices. + * @return CollectionInterface|Choice[]|null A collection of choices. */ protected function getChoicesAttribute(): ?CollectionInterface { @@ -95,7 +95,7 @@ protected function getChoicesAttribute(): ?CollectionInterface /** * Gets the options attribute. * - * @return CollectionInterfaceInterface|Option[] A collection of options. + * @return CollectionInterface|Option[] A collection of options. */ protected function getOptionsAttribute(): CollectionInterface { diff --git a/src/Discord/Parts/Interactions/Request/Component.php b/src/Discord/Parts/Interactions/Request/Component.php index 9150f12ce..baa311112 100644 --- a/src/Discord/Parts/Interactions/Request/Component.php +++ b/src/Discord/Parts/Interactions/Request/Component.php @@ -69,7 +69,7 @@ class Component extends Part /** * Gets the sub-components of the component. * - * @return CollectionInterfaceInterface|Component[]|null $components + * @return CollectionInterface|Component[]|null $components */ protected function getComponentsAttribute(): ?CollectionInterface { diff --git a/src/Discord/Parts/Interactions/Request/InteractionData.php b/src/Discord/Parts/Interactions/Request/InteractionData.php index de6aee0a9..5b1fe2bae 100644 --- a/src/Discord/Parts/Interactions/Request/InteractionData.php +++ b/src/Discord/Parts/Interactions/Request/InteractionData.php @@ -58,7 +58,7 @@ class InteractionData extends Part /** * Gets the options of the interaction. * - * @return CollectionInterfaceInterface|Option[]|null $options + * @return CollectionInterface|Option[]|null $options */ protected function getOptionsAttribute(): ?CollectionInterface { @@ -78,7 +78,7 @@ protected function getOptionsAttribute(): ?CollectionInterface /** * Gets the components of the interaction. * - * @return CollectionInterfaceInterface|Component[]|null $components + * @return CollectionInterface|Component[]|null $components */ protected function getComponentsAttribute(): ?CollectionInterface { diff --git a/src/Discord/Parts/Interactions/Request/Option.php b/src/Discord/Parts/Interactions/Request/Option.php index 9a23d936e..a26a9eae0 100644 --- a/src/Discord/Parts/Interactions/Request/Option.php +++ b/src/Discord/Parts/Interactions/Request/Option.php @@ -44,7 +44,7 @@ class Option extends Part /** * Gets the options of the interaction. * - * @return CollectionInterfaceInterface|Option[]|null $options + * @return CollectionInterface|Option[]|null $options */ protected function getOptionsAttribute(): ?CollectionInterface { diff --git a/src/Discord/Parts/Interactions/Request/Resolved.php b/src/Discord/Parts/Interactions/Request/Resolved.php index e9cde45eb..fa18c8ebf 100644 --- a/src/Discord/Parts/Interactions/Request/Resolved.php +++ b/src/Discord/Parts/Interactions/Request/Resolved.php @@ -62,7 +62,7 @@ class Resolved extends Part /** * Returns a collection of resolved users. * - * @return CollectionInterfaceInterface|User[]|null Map of Snowflakes to user objects + * @return CollectionInterface|User[]|null Map of Snowflakes to user objects */ protected function getUsersAttribute(): ?CollectionInterface { @@ -84,7 +84,7 @@ protected function getUsersAttribute(): ?CollectionInterface * * Partial Member objects are missing user, deaf and mute fields * - * @return CollectionInterfaceInterface|Member[]|null Map of Snowflakes to partial member objects + * @return CollectionInterface|Member[]|null Map of Snowflakes to partial member objects */ protected function getMembersAttribute(): ?CollectionInterface { @@ -113,7 +113,7 @@ protected function getMembersAttribute(): ?CollectionInterface /** * Returns a collection of resolved roles. * - * @return CollectionInterfaceInterface|Role[]|null Map of Snowflakes to role objects + * @return CollectionInterface|Role[]|null Map of Snowflakes to role objects */ protected function getRolesAttribute(): ?CollectionInterface { @@ -143,7 +143,7 @@ protected function getRolesAttribute(): ?CollectionInterface * * Partial Channel objects only have id, name, type and permissions fields. Threads will also have thread_metadata and parent_id fields. * - * @return CollectionInterfaceInterface|Channel[]|Thread[]|null Map of Snowflakes to partial channel objects + * @return CollectionInterface|Channel[]|Thread[]|null Map of Snowflakes to partial channel objects */ protected function getChannelsAttribute(): ?CollectionInterface { @@ -175,7 +175,7 @@ protected function getChannelsAttribute(): ?CollectionInterface /** * Returns a collection of resolved messages. * - * @return CollectionInterfaceInterface|Message[]|null Map of Snowflakes to partial messages objects + * @return CollectionInterface|Message[]|null Map of Snowflakes to partial messages objects */ protected function getMessagesAttribute(): ?CollectionInterface { @@ -201,7 +201,7 @@ protected function getMessagesAttribute(): ?CollectionInterface /** * Returns a collection of resolved attachments. * - * @return CollectionInterfaceInterface|Attachment[]|null Map of Snowflakes to attachments objects + * @return CollectionInterface|Attachment[]|null Map of Snowflakes to attachments objects */ protected function getAttachmentsAttribute(): ?CollectionInterface { diff --git a/src/Discord/Parts/User/Member.php b/src/Discord/Parts/User/Member.php index 59507da22..0bceaae52 100644 --- a/src/Discord/Parts/User/Member.php +++ b/src/Discord/Parts/User/Member.php @@ -609,7 +609,7 @@ protected function getGameAttribute(): ?Activity /** * Gets the activities attribute. * - * @return CollectionInterfaceInterface|Activity[] + * @return CollectionInterface|Activity[] */ protected function getActivitiesAttribute(): CollectionInterface { @@ -685,7 +685,7 @@ protected function getGuildAttribute(): ?Guild /** * Returns the roles attribute. * - * @return CollectionInterfaceInterface A collection of roles the member is in. null role only contains ID in the collection. + * @return CollectionInterface A collection of roles the member is in. null role only contains ID in the collection. */ protected function getRolesAttribute(): CollectionInterface { diff --git a/src/Discord/Parts/WebSockets/PresenceUpdate.php b/src/Discord/Parts/WebSockets/PresenceUpdate.php index 8c1635824..ea4dc6f81 100644 --- a/src/Discord/Parts/WebSockets/PresenceUpdate.php +++ b/src/Discord/Parts/WebSockets/PresenceUpdate.php @@ -93,7 +93,7 @@ protected function getGuildAttribute(): ?Guild /** * Gets the activities attribute. * - * @return CollectionInterfaceInterface|Activity[] + * @return CollectionInterface|Activity[] */ protected function getActivitiesAttribute(): CollectionInterface { @@ -163,7 +163,7 @@ protected function getMemberAttribute(): ?Member /** * Returns the users roles. * - * @return CollectionInterfaceInterface|Role[] + * @return CollectionInterface|Role[] */ protected function getRolesAttribute(): CollectionInterface { diff --git a/src/Discord/Repository/Channel/ThreadRepository.php b/src/Discord/Repository/Channel/ThreadRepository.php index 1b85402bf..48f7d23b6 100644 --- a/src/Discord/Repository/Channel/ThreadRepository.php +++ b/src/Discord/Repository/Channel/ThreadRepository.php @@ -150,7 +150,7 @@ public function archived(bool $private = false, bool $joined = false, ?int $limi * * @param object $response * - * @return CollectionInterfaceInterface|Thread[] + * @return CollectionInterface|Thread[] */ private function handleThreadPaginationResponse(object $response): CollectionInterface { diff --git a/tests/DiscordTest.php b/tests/DiscordTest.php index 305c4ee7d..33dc09aad 100644 --- a/tests/DiscordTest.php +++ b/tests/DiscordTest.php @@ -41,7 +41,7 @@ public function testSetGetCacheAsync() } return $success; - })->done($resolve, $resolve); + })->then($resolve, $resolve); }, 10); } } diff --git a/tests/Parts/Channel/ChannelTest.php b/tests/Parts/Channel/ChannelTest.php index eb618aad7..6375fc1fa 100644 --- a/tests/Parts/Channel/ChannelTest.php +++ b/tests/Parts/Channel/ChannelTest.php @@ -36,14 +36,14 @@ public function testCanPinMessageAndGetPinnedMessage() ->then(function () { return $this->channel()->getPinnedMessages(); }) - ->then(function (Collection $messages) use ($message) { + ->then(function (CollectionInterface $messages) use ($message) { $this->assertGreaterThan(0, $messages->count()); $this->assertContains($message->id, $messages->map(function ($message) { return $message->id; })); }); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -64,13 +64,13 @@ public function testCanPinAndUnpinMessageAndCheckItIsUnpinned() ->then(function () { return $this->channel()->getPinnedMessages(); }) - ->then(function (Collection $messages) use ($message) { + ->then(function (CollectionInterface $messages) use ($message) { $this->assertNotContains($message->id, $messages->map(function ($message) { return $message->id; })); }); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -87,7 +87,7 @@ public function testCanGetMessage() $this->assertEquals($getMessage->id, $message->id); }); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -99,7 +99,7 @@ public function testCanCreateInvite() { return wait(function (Discord $discord, $resolve) { $this->channel()->createInvite() - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -111,7 +111,7 @@ public function testCanDeleteMessagesWithZeroMessages() { return wait(function (Discord $discord, $resolve) { $this->channel()->deleteMessages([]) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -126,7 +126,7 @@ public function testCanDeleteMessagesWithOneMessage() ->then(function (Message $message) { return $this->channel()->deleteMessages([$message]); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -144,7 +144,7 @@ public function testCanDeleteMessagesWithMultipleMessages() return $this->channel()->deleteMessages([$m1, $m2]); }); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -156,7 +156,7 @@ public function testCanLimitDeleteMessages() { return wait(function (Discord $discord, $resolve) { $this->channel()->limitDelete(5) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -168,7 +168,7 @@ public function testCanGetMessageHistory() return wait(function (Discord $discord, $resolve) { $this->channel()->getMessageHistory([]) ->then(function ($messages) { - $this->assertInstanceOf(Collection::class, $messages); + $this->assertInstanceOf(CollectionInterface::class, $messages); if ($messages->count() < 1) { $this->markTestSkipped('no messages were present when gettign message history - could not check if collection contained message objects.'); @@ -180,7 +180,7 @@ public function testCanGetMessageHistory() $this->assertInstanceOf(Message::class, $message); } }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -191,8 +191,8 @@ public function testCanGetInvites() { return wait(function (Discord $discord, $resolve) { $this->channel()->invites->freshen() - ->then(function (Collection $invites) { - $this->assertInstanceOf(Collection::class, $invites); + ->then(function (CollectionInterface $invites) { + $this->assertInstanceOf(CollectionInterface::class, $invites); if ($invites->count() < 1) { $this->markTestSkipped('no invites were present when getting invites - could not check if collection contained invite objects.'); @@ -204,7 +204,7 @@ public function testCanGetInvites() $this->assertInstanceOf(Invite::class, $invite); } }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -222,7 +222,7 @@ public function testCanEditMessageThroughChannel() $this->assertEquals($message->id, $updatedMessage->id); }); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -238,7 +238,7 @@ public function testCanSendFile() ->then(function (Message $message) { $this->assertEquals(1, count($message->attachments)); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -250,7 +250,7 @@ public function testCanBroadcastTyping() { return wait(function (Discord $discord, $resolve) { $this->channel()->broadcastTyping() - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } diff --git a/tests/Parts/Channel/Message/EmbedMessageTest.php b/tests/Parts/Channel/Message/EmbedMessageTest.php index d11f0e9ea..2986261d4 100644 --- a/tests/Parts/Channel/Message/EmbedMessageTest.php +++ b/tests/Parts/Channel/Message/EmbedMessageTest.php @@ -71,7 +71,7 @@ public function testCanSendEmbed() (string) $embed->fields->get('name', 'Field 2') ); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }, 10); } } diff --git a/tests/Parts/Channel/Message/EmptyMessageTest.php b/tests/Parts/Channel/Message/EmptyMessageTest.php index 944d2a7ba..c55463bf2 100644 --- a/tests/Parts/Channel/Message/EmptyMessageTest.php +++ b/tests/Parts/Channel/Message/EmptyMessageTest.php @@ -37,7 +37,7 @@ public function testCanSendMessage() return $message; }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -56,7 +56,7 @@ public function testCanReplyToMessage(Message $message) return $new_message; }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -79,7 +79,7 @@ public function testCanEditMessage() return $message; }); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -119,19 +119,19 @@ public function testChannelAttribute(Message $message) */ public function testCollectionsEmpty(Message $message) { - $this->assertInstanceOf(Collection::class, $message->mentions); + $this->assertInstanceOf(CollectionInterface::class, $message->mentions); $this->assertEquals(0, $message->mentions->count()); - $this->assertInstanceOf(Collection::class, $message->mention_roles); + $this->assertInstanceOf(CollectionInterface::class, $message->mention_roles); $this->assertEquals(0, $message->mention_roles->count()); - $this->assertInstanceOf(Collection::class, $message->reactions); + $this->assertInstanceOf(CollectionInterface::class, $message->reactions); $this->assertEquals(0, $message->reactions->count()); - $this->assertInstanceOf(Collection::class, $message->mention_channels); + $this->assertInstanceOf(CollectionInterface::class, $message->mention_channels); $this->assertEquals(0, $message->mention_channels->count()); - $this->assertInstanceOf(Collection::class, $message->embeds); + $this->assertInstanceOf(CollectionInterface::class, $message->embeds); $this->assertEquals(0, $message->embeds->count()); } @@ -174,7 +174,7 @@ public function testDelayedReply() $this->assertGreaterThanOrEqual($delay / 1000, $diff); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }, 10); } @@ -189,7 +189,7 @@ public function testCanReactWithString() ->then(function (Message $message) { return $message->react('😀'); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -222,7 +222,7 @@ public function testCanAddEmbed(Message $message) $this->assertEquals('Field value', $field->value); $this->assertEquals(true, $field->inline); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -237,7 +237,7 @@ public function testCanDeleteMessageThroughRepository(Message $message) ->then(function (Message $message) { $this->assertFalse($message->created); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -252,7 +252,7 @@ public function testCanDeleteMessageThroughPart() ->then(function (Message $message) { return $message->delete(); }) - ->done($resolve); + ->then($resolve); }); } } diff --git a/tests/Parts/Channel/Message/MessageTest.php b/tests/Parts/Channel/Message/MessageTest.php index 529d0173a..57cad9f0a 100644 --- a/tests/Parts/Channel/Message/MessageTest.php +++ b/tests/Parts/Channel/Message/MessageTest.php @@ -29,7 +29,7 @@ public function testCanMentionChannel() $this->assertInstanceOf(Channel::class, $message->mention_channels->first()); $this->assertEquals($this->channel()->id, $message->mention_channels->first()->id); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -46,7 +46,7 @@ public function testCanCrosspostMessage() ->then(function ($message) { $this->assertInstanceOf(Message::class, $message); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }, 10, function () { $this->markTestIncomplete('Crosspost has likely hit ratelimit.'); }); diff --git a/tests/Parts/Channel/Message/RemoveReactionTest.php b/tests/Parts/Channel/Message/RemoveReactionTest.php index e7a22e4c0..ab67238f6 100644 --- a/tests/Parts/Channel/Message/RemoveReactionTest.php +++ b/tests/Parts/Channel/Message/RemoveReactionTest.php @@ -35,7 +35,7 @@ public function testDeleteAllReactions() ->then(function (Message $message) { return $message->deleteReaction(Message::REACT_DELETE_ALL); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -56,7 +56,7 @@ public function testDeleteSelfReaction() })->then(function (Message $message) { return $message->deleteReaction(Message::REACT_DELETE_ME, '🤪'); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -77,7 +77,7 @@ public function testDeleteReactionOfUser() })->then(function (Message $message) use ($discord) { return $message->deleteReaction(Message::REACT_DELETE_ID, '🤪', $discord->id); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -98,7 +98,7 @@ public function testDeleteAllReactionsForEmoji() })->then(function (Message $message) use ($discord) { return $message->deleteReaction(Message::REACT_DELETE_EMOJI, '🤪'); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } } diff --git a/tests/Parts/Embed/EmbedTest.php b/tests/Parts/Embed/EmbedTest.php index 16f7b1d31..d290a5a1e 100644 --- a/tests/Parts/Embed/EmbedTest.php +++ b/tests/Parts/Embed/EmbedTest.php @@ -44,7 +44,7 @@ public function testCanGetVideoEmbed() $this->assertEquals($url, $embed->url); $this->assertEquals(Embed::TYPE_VIDEO, $embed->type); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }, 10); } @@ -66,7 +66,7 @@ public function testCanGetImageEmbed() $this->assertEquals(Embed::TYPE_IMAGE, $embed->type); $this->assertInstanceOf(Image::class, $embed->thumbnail); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }, 10); } } From 06f5d2004b4074539b74b049ea95a76ed39469a3 Mon Sep 17 00:00:00 2001 From: Valithor Obsidion Date: Tue, 24 Dec 2024 11:31:22 -0500 Subject: [PATCH 04/14] CollectionInterface typing and tests --- src/Discord/DiscordCommandClient.php | 6 ++-- src/Discord/Parts/Channel/Reaction.php | 2 +- src/Discord/Parts/Embed/Embed.php | 26 +++++++------- src/Discord/Parts/Guild/AuditLog/AuditLog.php | 18 +++++----- src/Discord/Parts/Guild/AuditLog/Entry.php | 16 ++++----- .../Parts/Guild/AutoModeration/Rule.php | 6 ++-- .../Parts/Guild/CommandPermissions.php | 2 +- src/Discord/Parts/Guild/Guild.php | 4 +-- src/Discord/Parts/Guild/WelcomeScreen.php | 2 +- .../Parts/Interactions/Command/Command.php | 2 +- .../Parts/Interactions/Command/Option.php | 4 +-- .../Parts/Interactions/Request/Component.php | 2 +- .../Interactions/Request/InteractionData.php | 4 +-- .../Parts/Interactions/Request/Option.php | 2 +- .../Parts/Interactions/Request/Resolved.php | 12 +++---- src/Discord/Parts/User/Member.php | 4 +-- .../Parts/WebSockets/PresenceUpdate.php | 4 +-- .../Repository/Channel/ThreadRepository.php | 2 +- tests/DiscordTest.php | 2 +- tests/Parts/Channel/ChannelTest.php | 36 +++++++++---------- .../Channel/Message/EmbedMessageTest.php | 2 +- .../Channel/Message/EmptyMessageTest.php | 26 +++++++------- tests/Parts/Channel/Message/MessageTest.php | 4 +-- .../Channel/Message/RemoveReactionTest.php | 8 ++--- tests/Parts/Embed/EmbedTest.php | 4 +-- 25 files changed, 100 insertions(+), 100 deletions(-) diff --git a/src/Discord/DiscordCommandClient.php b/src/Discord/DiscordCommandClient.php index d67943b92..c27abe1c7 100644 --- a/src/Discord/DiscordCommandClient.php +++ b/src/Discord/DiscordCommandClient.php @@ -99,7 +99,7 @@ public function __construct(array $options = []) $message ->reply($result) ->then(null, $this->commandClientOptions['internalRejectedPromiseHandler']) - ->done(); + ->then(); } } }); @@ -162,7 +162,7 @@ public function __construct(array $options = []) $message->channel ->sendEmbed($embed) ->then(null, $this->commandClientOptions['internalRejectedPromiseHandler']) - ->done(); + ->then(); return; } @@ -209,7 +209,7 @@ public function __construct(array $options = []) $message->channel ->sendEmbed($embed) ->then(null, $this->commandClientOptions['internalRejectedPromiseHandler']) - ->done(); + ->then(); }, [ 'description' => 'Provides a list of commands available.', 'usage' => '[command]', diff --git a/src/Discord/Parts/Channel/Reaction.php b/src/Discord/Parts/Channel/Reaction.php index 762a46bcc..cb0119a3f 100644 --- a/src/Discord/Parts/Channel/Reaction.php +++ b/src/Discord/Parts/Channel/Reaction.php @@ -193,7 +193,7 @@ public function getAllUsers(): PromiseInterface $options['after'] = $after; } - return $this->getUsers($options)->then(function (Collection $users) use ($response, &$getUsers) { + return $this->getUsers($options)->then(function (CollectionInterface $users) use ($response, &$getUsers) { $last = null; foreach ($users as $user) { $response->pushItem($user); diff --git a/src/Discord/Parts/Embed/Embed.php b/src/Discord/Parts/Embed/Embed.php index 5af6c67e7..727d9750e 100644 --- a/src/Discord/Parts/Embed/Embed.php +++ b/src/Discord/Parts/Embed/Embed.php @@ -24,18 +24,18 @@ * * @since 4.0.3 * - * @property string|null $title The title of the embed. - * @property-read string|null $type The type of the embed. - * @property string|null $description A description of the embed. - * @property string|null $url The URL of the embed. - * @property Carbon|null $timestamp A timestamp of the embed. - * @property int|null $color The color of the embed. - * @property Footer|null $footer The footer of the embed. - * @property Image|null $image The image of the embed. - * @property Image|null $thumbnail The thumbnail of the embed. - * @property-read Video|null $video The video of the embed. - * @property-read object|null $provider The provider of the embed. - * @property Author|null $author The author of the embed. + * @property string|null $title The title of the embed. + * @property-read string|null $type The type of the embed. + * @property string|null $description A description of the embed. + * @property string|null $url The URL of the embed. + * @property Carbon|null $timestamp A timestamp of the embed. + * @property int|null $color The color of the embed. + * @property Footer|null $footer The footer of the embed. + * @property Image|null $image The image of the embed. + * @property Image|null $thumbnail The thumbnail of the embed. + * @property-read Video|null $video The video of the embed. + * @property-read object|null $provider The provider of the embed. + * @property Author|null $author The author of the embed. * @property CollectionInterface|Field[] $fields A collection of embed fields. */ class Embed extends Part @@ -135,7 +135,7 @@ protected function getAuthorAttribute(): Author /** * Gets the fields attribute. * - * @return CollectionInterfaceInterface|Field[] + * @return CollectionInterface|Field[] */ protected function getFieldsAttribute(): CollectionInterface { diff --git a/src/Discord/Parts/Guild/AuditLog/AuditLog.php b/src/Discord/Parts/Guild/AuditLog/AuditLog.php index f787eb954..295611446 100644 --- a/src/Discord/Parts/Guild/AuditLog/AuditLog.php +++ b/src/Discord/Parts/Guild/AuditLog/AuditLog.php @@ -74,7 +74,7 @@ protected function getGuildAttribute(): ?Guild /** * Returns a collection of application commands found in the audit log. * - * @return CollectionInterfaceInterface|Command[] + * @return CollectionInterface|Command[] */ protected function getApplicationCommandsAttribute(): CollectionInterface { @@ -90,7 +90,7 @@ protected function getApplicationCommandsAttribute(): CollectionInterface /** * Returns a collection of audit log entries. * - * @return CollectionInterfaceInterface|Entry[] + * @return CollectionInterface|Entry[] */ protected function getAuditLogEntriesAttribute(): CollectionInterface { @@ -106,7 +106,7 @@ protected function getAuditLogEntriesAttribute(): CollectionInterface /** * Returns a collection of auto moderation rules found in the audit log. * - * @return CollectionInterfaceInterface|Rule[] + * @return CollectionInterface|Rule[] */ protected function getAutoModerationRulesAttribute(): CollectionInterface { @@ -122,7 +122,7 @@ protected function getAutoModerationRulesAttribute(): CollectionInterface /** * Returns a collection of guild scheduled events found in the audit log. * - * @return CollectionInterfaceInterface|ScheduledEvent[] + * @return CollectionInterface|ScheduledEvent[] */ protected function getGuildScheduledEventsAttribute(): CollectionInterface { @@ -140,7 +140,7 @@ protected function getGuildScheduledEventsAttribute(): CollectionInterface * * @link https://discord.com/developers/docs/resources/audit-log#audit-log-object-example-partial-integration-object * - * @return CollectionInterfaceInterface|Integration[] + * @return CollectionInterface|Integration[] */ protected function getIntegrationsAttribute(): CollectionInterface { @@ -156,7 +156,7 @@ protected function getIntegrationsAttribute(): CollectionInterface /** * Returns a collection of threads found in the audit log. * - * @return CollectionInterfaceInterface|Thread[] + * @return CollectionInterface|Thread[] */ protected function getThreadsAttribute(): CollectionInterface { @@ -172,7 +172,7 @@ protected function getThreadsAttribute(): CollectionInterface /** * Returns a collection of users found in the audit log. * - * @return CollectionInterfaceInterface|User[] + * @return CollectionInterface|User[] */ protected function getUsersAttribute(): CollectionInterface { @@ -188,7 +188,7 @@ protected function getUsersAttribute(): CollectionInterface /** * Returns a collection of webhooks found in the audit log. * - * @return CollectionInterfaceInterface|Webhook[] + * @return CollectionInterface|Webhook[] */ protected function getWebhooksAttribute(): CollectionInterface { @@ -208,7 +208,7 @@ protected function getWebhooksAttribute(): CollectionInterface * * @throws \InvalidArgumentException * - * @return CollectionInterfaceInterface|Entry[] + * @return CollectionInterface|Entry[] */ public function searchByType(int $action_type): CollectionInterface { diff --git a/src/Discord/Parts/Guild/AuditLog/Entry.php b/src/Discord/Parts/Guild/AuditLog/Entry.php index f2a483142..cc03d7a7d 100644 --- a/src/Discord/Parts/Guild/AuditLog/Entry.php +++ b/src/Discord/Parts/Guild/AuditLog/Entry.php @@ -22,14 +22,14 @@ * * @link https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object * - * @property ?string $target_id ID of the affected entity (webhook, user, role, etc.). - * @property Collection $changes Changes made to the target_id. - * @property ?string $user_id The user who made the changes. - * @property-read User|null $user - * @property string $id ID of the entry. - * @property int $action_type Type of action that occurred. - * @property Options|null $options Additional info for certain action types. - * @property string|null $reason The reason for the change (0-512 characters). + * @property ?string $target_id ID of the affected entity (webhook, user, role, etc.). + * @property CollectionInterface $changes Changes made to the target_id. + * @property ?string $user_id The user who made the changes. + * @property-read User|null $user + * @property string $id ID of the entry. + * @property int $action_type Type of action that occurred. + * @property Options|null $options Additional info for certain action types. + * @property string|null $reason The reason for the change (0-512 characters). */ class Entry extends Part { diff --git a/src/Discord/Parts/Guild/AutoModeration/Rule.php b/src/Discord/Parts/Guild/AutoModeration/Rule.php index a79202490..239cfc138 100644 --- a/src/Discord/Parts/Guild/AutoModeration/Rule.php +++ b/src/Discord/Parts/Guild/AutoModeration/Rule.php @@ -98,7 +98,7 @@ protected function getCreatorAttribute(): ?User /** * Returns the actions attribute. * - * @return CollectionInterfaceInterface|Action[] A collection of actions. + * @return CollectionInterface|Action[] A collection of actions. */ protected function getActionsAttribute(): CollectionInterface { @@ -114,7 +114,7 @@ protected function getActionsAttribute(): CollectionInterface /** * Returns the exempt roles attribute. * - * @return CollectionInterfaceInterface|?Role[] A collection of roles exempt from the rule. + * @return CollectionInterface|?Role[] A collection of roles exempt from the rule. */ protected function getExemptRolesAttribute(): CollectionInterface { @@ -138,7 +138,7 @@ protected function getExemptRolesAttribute(): CollectionInterface /** * Returns the exempt channels attribute. * - * @return CollectionInterfaceInterface|?Channel[] A collection of channels exempt from the rule. + * @return CollectionInterface|?Channel[] A collection of channels exempt from the rule. */ protected function getExemptChannelsAttribute(): CollectionInterface { diff --git a/src/Discord/Parts/Guild/CommandPermissions.php b/src/Discord/Parts/Guild/CommandPermissions.php index 4b8405c36..32a85ec57 100644 --- a/src/Discord/Parts/Guild/CommandPermissions.php +++ b/src/Discord/Parts/Guild/CommandPermissions.php @@ -55,7 +55,7 @@ protected function getGuildAttribute(): ?Guild /** * Gets the permissions attribute. * - * @return CollectionInterfaceInterface|Permission[] A collection of permissions. + * @return CollectionInterface|Permission[] A collection of permissions. */ protected function getPermissionsAttribute(): CollectionInterface { diff --git a/src/Discord/Parts/Guild/Guild.php b/src/Discord/Parts/Guild/Guild.php index f39c7740e..1f6087198 100644 --- a/src/Discord/Parts/Guild/Guild.php +++ b/src/Discord/Parts/Guild/Guild.php @@ -568,7 +568,7 @@ protected function getSplashHashAttribute(): ?string * * @deprecated 10.0.0 Use `$channel->stage_instances` * - * @return CollectionInterfaceInterface|StageInstance[] + * @return CollectionInterface|StageInstance[] */ protected function getStageInstancesAttribute(): CollectionInterface { @@ -744,7 +744,7 @@ protected function getFeatureWelcomeScreenEnabledAttribute(): bool * * @link https://discord.com/developers/docs/resources/voice#list-voice-regions * - * @return PromiseInterface + * @return PromiseInterface */ public function getVoiceRegions(): PromiseInterface { diff --git a/src/Discord/Parts/Guild/WelcomeScreen.php b/src/Discord/Parts/Guild/WelcomeScreen.php index b53938b14..3e6124273 100644 --- a/src/Discord/Parts/Guild/WelcomeScreen.php +++ b/src/Discord/Parts/Guild/WelcomeScreen.php @@ -37,7 +37,7 @@ class WelcomeScreen extends Part /** * Returns the Welcome Channels of the Welcome Screen. * - * @return CollectionInterfaceInterface|WelcomeChannel[] The channels of welcome screen. + * @return CollectionInterface|WelcomeChannel[] The channels of welcome screen. */ protected function getWelcomeChannelsAttribute(): CollectionInterface { diff --git a/src/Discord/Parts/Interactions/Command/Command.php b/src/Discord/Parts/Interactions/Command/Command.php index c50591862..b8cf1594a 100644 --- a/src/Discord/Parts/Interactions/Command/Command.php +++ b/src/Discord/Parts/Interactions/Command/Command.php @@ -79,7 +79,7 @@ protected function getApplicationIdAttribute(): string /** * Gets the options attribute. * - * @return CollectionInterfaceInterface|Option[]|null A collection of options. + * @return CollectionInterface|Option[]|null A collection of options. */ protected function getOptionsAttribute(): ?CollectionInterface { diff --git a/src/Discord/Parts/Interactions/Command/Option.php b/src/Discord/Parts/Interactions/Command/Option.php index 6648365e7..80ea54805 100644 --- a/src/Discord/Parts/Interactions/Command/Option.php +++ b/src/Discord/Parts/Interactions/Command/Option.php @@ -75,7 +75,7 @@ class Option extends Part /** * Gets the choices attribute. * - * @return CollectionInterfaceInterface|Choice[]|null A collection of choices. + * @return CollectionInterface|Choice[]|null A collection of choices. */ protected function getChoicesAttribute(): ?CollectionInterface { @@ -95,7 +95,7 @@ protected function getChoicesAttribute(): ?CollectionInterface /** * Gets the options attribute. * - * @return CollectionInterfaceInterface|Option[] A collection of options. + * @return CollectionInterface|Option[] A collection of options. */ protected function getOptionsAttribute(): CollectionInterface { diff --git a/src/Discord/Parts/Interactions/Request/Component.php b/src/Discord/Parts/Interactions/Request/Component.php index 9150f12ce..baa311112 100644 --- a/src/Discord/Parts/Interactions/Request/Component.php +++ b/src/Discord/Parts/Interactions/Request/Component.php @@ -69,7 +69,7 @@ class Component extends Part /** * Gets the sub-components of the component. * - * @return CollectionInterfaceInterface|Component[]|null $components + * @return CollectionInterface|Component[]|null $components */ protected function getComponentsAttribute(): ?CollectionInterface { diff --git a/src/Discord/Parts/Interactions/Request/InteractionData.php b/src/Discord/Parts/Interactions/Request/InteractionData.php index de6aee0a9..5b1fe2bae 100644 --- a/src/Discord/Parts/Interactions/Request/InteractionData.php +++ b/src/Discord/Parts/Interactions/Request/InteractionData.php @@ -58,7 +58,7 @@ class InteractionData extends Part /** * Gets the options of the interaction. * - * @return CollectionInterfaceInterface|Option[]|null $options + * @return CollectionInterface|Option[]|null $options */ protected function getOptionsAttribute(): ?CollectionInterface { @@ -78,7 +78,7 @@ protected function getOptionsAttribute(): ?CollectionInterface /** * Gets the components of the interaction. * - * @return CollectionInterfaceInterface|Component[]|null $components + * @return CollectionInterface|Component[]|null $components */ protected function getComponentsAttribute(): ?CollectionInterface { diff --git a/src/Discord/Parts/Interactions/Request/Option.php b/src/Discord/Parts/Interactions/Request/Option.php index 9a23d936e..a26a9eae0 100644 --- a/src/Discord/Parts/Interactions/Request/Option.php +++ b/src/Discord/Parts/Interactions/Request/Option.php @@ -44,7 +44,7 @@ class Option extends Part /** * Gets the options of the interaction. * - * @return CollectionInterfaceInterface|Option[]|null $options + * @return CollectionInterface|Option[]|null $options */ protected function getOptionsAttribute(): ?CollectionInterface { diff --git a/src/Discord/Parts/Interactions/Request/Resolved.php b/src/Discord/Parts/Interactions/Request/Resolved.php index e9cde45eb..fa18c8ebf 100644 --- a/src/Discord/Parts/Interactions/Request/Resolved.php +++ b/src/Discord/Parts/Interactions/Request/Resolved.php @@ -62,7 +62,7 @@ class Resolved extends Part /** * Returns a collection of resolved users. * - * @return CollectionInterfaceInterface|User[]|null Map of Snowflakes to user objects + * @return CollectionInterface|User[]|null Map of Snowflakes to user objects */ protected function getUsersAttribute(): ?CollectionInterface { @@ -84,7 +84,7 @@ protected function getUsersAttribute(): ?CollectionInterface * * Partial Member objects are missing user, deaf and mute fields * - * @return CollectionInterfaceInterface|Member[]|null Map of Snowflakes to partial member objects + * @return CollectionInterface|Member[]|null Map of Snowflakes to partial member objects */ protected function getMembersAttribute(): ?CollectionInterface { @@ -113,7 +113,7 @@ protected function getMembersAttribute(): ?CollectionInterface /** * Returns a collection of resolved roles. * - * @return CollectionInterfaceInterface|Role[]|null Map of Snowflakes to role objects + * @return CollectionInterface|Role[]|null Map of Snowflakes to role objects */ protected function getRolesAttribute(): ?CollectionInterface { @@ -143,7 +143,7 @@ protected function getRolesAttribute(): ?CollectionInterface * * Partial Channel objects only have id, name, type and permissions fields. Threads will also have thread_metadata and parent_id fields. * - * @return CollectionInterfaceInterface|Channel[]|Thread[]|null Map of Snowflakes to partial channel objects + * @return CollectionInterface|Channel[]|Thread[]|null Map of Snowflakes to partial channel objects */ protected function getChannelsAttribute(): ?CollectionInterface { @@ -175,7 +175,7 @@ protected function getChannelsAttribute(): ?CollectionInterface /** * Returns a collection of resolved messages. * - * @return CollectionInterfaceInterface|Message[]|null Map of Snowflakes to partial messages objects + * @return CollectionInterface|Message[]|null Map of Snowflakes to partial messages objects */ protected function getMessagesAttribute(): ?CollectionInterface { @@ -201,7 +201,7 @@ protected function getMessagesAttribute(): ?CollectionInterface /** * Returns a collection of resolved attachments. * - * @return CollectionInterfaceInterface|Attachment[]|null Map of Snowflakes to attachments objects + * @return CollectionInterface|Attachment[]|null Map of Snowflakes to attachments objects */ protected function getAttachmentsAttribute(): ?CollectionInterface { diff --git a/src/Discord/Parts/User/Member.php b/src/Discord/Parts/User/Member.php index 59507da22..0bceaae52 100644 --- a/src/Discord/Parts/User/Member.php +++ b/src/Discord/Parts/User/Member.php @@ -609,7 +609,7 @@ protected function getGameAttribute(): ?Activity /** * Gets the activities attribute. * - * @return CollectionInterfaceInterface|Activity[] + * @return CollectionInterface|Activity[] */ protected function getActivitiesAttribute(): CollectionInterface { @@ -685,7 +685,7 @@ protected function getGuildAttribute(): ?Guild /** * Returns the roles attribute. * - * @return CollectionInterfaceInterface A collection of roles the member is in. null role only contains ID in the collection. + * @return CollectionInterface A collection of roles the member is in. null role only contains ID in the collection. */ protected function getRolesAttribute(): CollectionInterface { diff --git a/src/Discord/Parts/WebSockets/PresenceUpdate.php b/src/Discord/Parts/WebSockets/PresenceUpdate.php index 8c1635824..ea4dc6f81 100644 --- a/src/Discord/Parts/WebSockets/PresenceUpdate.php +++ b/src/Discord/Parts/WebSockets/PresenceUpdate.php @@ -93,7 +93,7 @@ protected function getGuildAttribute(): ?Guild /** * Gets the activities attribute. * - * @return CollectionInterfaceInterface|Activity[] + * @return CollectionInterface|Activity[] */ protected function getActivitiesAttribute(): CollectionInterface { @@ -163,7 +163,7 @@ protected function getMemberAttribute(): ?Member /** * Returns the users roles. * - * @return CollectionInterfaceInterface|Role[] + * @return CollectionInterface|Role[] */ protected function getRolesAttribute(): CollectionInterface { diff --git a/src/Discord/Repository/Channel/ThreadRepository.php b/src/Discord/Repository/Channel/ThreadRepository.php index 1b85402bf..48f7d23b6 100644 --- a/src/Discord/Repository/Channel/ThreadRepository.php +++ b/src/Discord/Repository/Channel/ThreadRepository.php @@ -150,7 +150,7 @@ public function archived(bool $private = false, bool $joined = false, ?int $limi * * @param object $response * - * @return CollectionInterfaceInterface|Thread[] + * @return CollectionInterface|Thread[] */ private function handleThreadPaginationResponse(object $response): CollectionInterface { diff --git a/tests/DiscordTest.php b/tests/DiscordTest.php index 305c4ee7d..33dc09aad 100644 --- a/tests/DiscordTest.php +++ b/tests/DiscordTest.php @@ -41,7 +41,7 @@ public function testSetGetCacheAsync() } return $success; - })->done($resolve, $resolve); + })->then($resolve, $resolve); }, 10); } } diff --git a/tests/Parts/Channel/ChannelTest.php b/tests/Parts/Channel/ChannelTest.php index eb618aad7..6375fc1fa 100644 --- a/tests/Parts/Channel/ChannelTest.php +++ b/tests/Parts/Channel/ChannelTest.php @@ -36,14 +36,14 @@ public function testCanPinMessageAndGetPinnedMessage() ->then(function () { return $this->channel()->getPinnedMessages(); }) - ->then(function (Collection $messages) use ($message) { + ->then(function (CollectionInterface $messages) use ($message) { $this->assertGreaterThan(0, $messages->count()); $this->assertContains($message->id, $messages->map(function ($message) { return $message->id; })); }); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -64,13 +64,13 @@ public function testCanPinAndUnpinMessageAndCheckItIsUnpinned() ->then(function () { return $this->channel()->getPinnedMessages(); }) - ->then(function (Collection $messages) use ($message) { + ->then(function (CollectionInterface $messages) use ($message) { $this->assertNotContains($message->id, $messages->map(function ($message) { return $message->id; })); }); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -87,7 +87,7 @@ public function testCanGetMessage() $this->assertEquals($getMessage->id, $message->id); }); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -99,7 +99,7 @@ public function testCanCreateInvite() { return wait(function (Discord $discord, $resolve) { $this->channel()->createInvite() - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -111,7 +111,7 @@ public function testCanDeleteMessagesWithZeroMessages() { return wait(function (Discord $discord, $resolve) { $this->channel()->deleteMessages([]) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -126,7 +126,7 @@ public function testCanDeleteMessagesWithOneMessage() ->then(function (Message $message) { return $this->channel()->deleteMessages([$message]); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -144,7 +144,7 @@ public function testCanDeleteMessagesWithMultipleMessages() return $this->channel()->deleteMessages([$m1, $m2]); }); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -156,7 +156,7 @@ public function testCanLimitDeleteMessages() { return wait(function (Discord $discord, $resolve) { $this->channel()->limitDelete(5) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -168,7 +168,7 @@ public function testCanGetMessageHistory() return wait(function (Discord $discord, $resolve) { $this->channel()->getMessageHistory([]) ->then(function ($messages) { - $this->assertInstanceOf(Collection::class, $messages); + $this->assertInstanceOf(CollectionInterface::class, $messages); if ($messages->count() < 1) { $this->markTestSkipped('no messages were present when gettign message history - could not check if collection contained message objects.'); @@ -180,7 +180,7 @@ public function testCanGetMessageHistory() $this->assertInstanceOf(Message::class, $message); } }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -191,8 +191,8 @@ public function testCanGetInvites() { return wait(function (Discord $discord, $resolve) { $this->channel()->invites->freshen() - ->then(function (Collection $invites) { - $this->assertInstanceOf(Collection::class, $invites); + ->then(function (CollectionInterface $invites) { + $this->assertInstanceOf(CollectionInterface::class, $invites); if ($invites->count() < 1) { $this->markTestSkipped('no invites were present when getting invites - could not check if collection contained invite objects.'); @@ -204,7 +204,7 @@ public function testCanGetInvites() $this->assertInstanceOf(Invite::class, $invite); } }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -222,7 +222,7 @@ public function testCanEditMessageThroughChannel() $this->assertEquals($message->id, $updatedMessage->id); }); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -238,7 +238,7 @@ public function testCanSendFile() ->then(function (Message $message) { $this->assertEquals(1, count($message->attachments)); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -250,7 +250,7 @@ public function testCanBroadcastTyping() { return wait(function (Discord $discord, $resolve) { $this->channel()->broadcastTyping() - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } diff --git a/tests/Parts/Channel/Message/EmbedMessageTest.php b/tests/Parts/Channel/Message/EmbedMessageTest.php index d11f0e9ea..2986261d4 100644 --- a/tests/Parts/Channel/Message/EmbedMessageTest.php +++ b/tests/Parts/Channel/Message/EmbedMessageTest.php @@ -71,7 +71,7 @@ public function testCanSendEmbed() (string) $embed->fields->get('name', 'Field 2') ); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }, 10); } } diff --git a/tests/Parts/Channel/Message/EmptyMessageTest.php b/tests/Parts/Channel/Message/EmptyMessageTest.php index 944d2a7ba..c55463bf2 100644 --- a/tests/Parts/Channel/Message/EmptyMessageTest.php +++ b/tests/Parts/Channel/Message/EmptyMessageTest.php @@ -37,7 +37,7 @@ public function testCanSendMessage() return $message; }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -56,7 +56,7 @@ public function testCanReplyToMessage(Message $message) return $new_message; }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -79,7 +79,7 @@ public function testCanEditMessage() return $message; }); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -119,19 +119,19 @@ public function testChannelAttribute(Message $message) */ public function testCollectionsEmpty(Message $message) { - $this->assertInstanceOf(Collection::class, $message->mentions); + $this->assertInstanceOf(CollectionInterface::class, $message->mentions); $this->assertEquals(0, $message->mentions->count()); - $this->assertInstanceOf(Collection::class, $message->mention_roles); + $this->assertInstanceOf(CollectionInterface::class, $message->mention_roles); $this->assertEquals(0, $message->mention_roles->count()); - $this->assertInstanceOf(Collection::class, $message->reactions); + $this->assertInstanceOf(CollectionInterface::class, $message->reactions); $this->assertEquals(0, $message->reactions->count()); - $this->assertInstanceOf(Collection::class, $message->mention_channels); + $this->assertInstanceOf(CollectionInterface::class, $message->mention_channels); $this->assertEquals(0, $message->mention_channels->count()); - $this->assertInstanceOf(Collection::class, $message->embeds); + $this->assertInstanceOf(CollectionInterface::class, $message->embeds); $this->assertEquals(0, $message->embeds->count()); } @@ -174,7 +174,7 @@ public function testDelayedReply() $this->assertGreaterThanOrEqual($delay / 1000, $diff); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }, 10); } @@ -189,7 +189,7 @@ public function testCanReactWithString() ->then(function (Message $message) { return $message->react('😀'); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -222,7 +222,7 @@ public function testCanAddEmbed(Message $message) $this->assertEquals('Field value', $field->value); $this->assertEquals(true, $field->inline); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -237,7 +237,7 @@ public function testCanDeleteMessageThroughRepository(Message $message) ->then(function (Message $message) { $this->assertFalse($message->created); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -252,7 +252,7 @@ public function testCanDeleteMessageThroughPart() ->then(function (Message $message) { return $message->delete(); }) - ->done($resolve); + ->then($resolve); }); } } diff --git a/tests/Parts/Channel/Message/MessageTest.php b/tests/Parts/Channel/Message/MessageTest.php index 529d0173a..57cad9f0a 100644 --- a/tests/Parts/Channel/Message/MessageTest.php +++ b/tests/Parts/Channel/Message/MessageTest.php @@ -29,7 +29,7 @@ public function testCanMentionChannel() $this->assertInstanceOf(Channel::class, $message->mention_channels->first()); $this->assertEquals($this->channel()->id, $message->mention_channels->first()->id); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -46,7 +46,7 @@ public function testCanCrosspostMessage() ->then(function ($message) { $this->assertInstanceOf(Message::class, $message); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }, 10, function () { $this->markTestIncomplete('Crosspost has likely hit ratelimit.'); }); diff --git a/tests/Parts/Channel/Message/RemoveReactionTest.php b/tests/Parts/Channel/Message/RemoveReactionTest.php index e7a22e4c0..ab67238f6 100644 --- a/tests/Parts/Channel/Message/RemoveReactionTest.php +++ b/tests/Parts/Channel/Message/RemoveReactionTest.php @@ -35,7 +35,7 @@ public function testDeleteAllReactions() ->then(function (Message $message) { return $message->deleteReaction(Message::REACT_DELETE_ALL); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -56,7 +56,7 @@ public function testDeleteSelfReaction() })->then(function (Message $message) { return $message->deleteReaction(Message::REACT_DELETE_ME, '🤪'); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -77,7 +77,7 @@ public function testDeleteReactionOfUser() })->then(function (Message $message) use ($discord) { return $message->deleteReaction(Message::REACT_DELETE_ID, '🤪', $discord->id); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } @@ -98,7 +98,7 @@ public function testDeleteAllReactionsForEmoji() })->then(function (Message $message) use ($discord) { return $message->deleteReaction(Message::REACT_DELETE_EMOJI, '🤪'); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }); } } diff --git a/tests/Parts/Embed/EmbedTest.php b/tests/Parts/Embed/EmbedTest.php index 16f7b1d31..d290a5a1e 100644 --- a/tests/Parts/Embed/EmbedTest.php +++ b/tests/Parts/Embed/EmbedTest.php @@ -44,7 +44,7 @@ public function testCanGetVideoEmbed() $this->assertEquals($url, $embed->url); $this->assertEquals(Embed::TYPE_VIDEO, $embed->type); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }, 10); } @@ -66,7 +66,7 @@ public function testCanGetImageEmbed() $this->assertEquals(Embed::TYPE_IMAGE, $embed->type); $this->assertInstanceOf(Image::class, $embed->thumbnail); }) - ->done($resolve, $resolve); + ->then($resolve, $resolve); }, 10); } } From 5518bf789dbec781ff292eb2f480633e15551f52 Mon Sep 17 00:00:00 2001 From: Valithor Obsidion Date: Tue, 24 Dec 2024 11:52:03 -0500 Subject: [PATCH 05/14] Adds protected Discord property to AbstractRepository This is required to support the new method of creating Collections --- .../Repository/AbstractRepositoryTrait.php | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/Discord/Repository/AbstractRepositoryTrait.php b/src/Discord/Repository/AbstractRepositoryTrait.php index 679e5cc35..5da829946 100644 --- a/src/Discord/Repository/AbstractRepositoryTrait.php +++ b/src/Discord/Repository/AbstractRepositoryTrait.php @@ -135,7 +135,7 @@ trait AbstractRepositoryTrait * @param Discord $discord * @param array $vars An array of variables used for the endpoint. */ - public function __construct(Discord $discord, array $vars = []) + public function __construct(protected Discord $discord, array $vars = []) { $this->http = $discord->getHttpClient(); $this->factory = $discord->getFactory(); @@ -609,7 +609,7 @@ public function has(...$keys): bool */ public function filter(callable $callback): CollectionInterface { - $collection = new Collection([], $this->discrim, $this->class); + $collection = new ($this->discord->getCollectionClass())([], $this->discrim, $this->class); foreach ($this->items as $offset => $item) { if ($item instanceof WeakReference) { @@ -791,10 +791,25 @@ public function __get(string $key) } } - public function __call($name, $arguments) + /** + * This method checks if a method with the name "__Collection__{$name}" exists + * within the class. If it does, it calls that method with the provided arguments. + * If the method does not exist, it throws a BadMethodCallException. + * + * Previously, this class utilized `parent::method` to call methods from the parent class. + * This was changed to use the `__Collection__method` naming convention to avoid conflicts + * + * @param string $name The name of the method being called. + * @param array $arguments The arguments passed to the method. + * + * @return mixed The result of the called method. + * + * @throws \BadMethodCallException If the method does not exist. + */ + public function __call($name, $arguments): mixed { - if (method_exists(CollectionTrait::class, $name)) { - return (new CollectionTrait)->$name(...$arguments); + if (method_exists($this, "__Collection__{$name}")) { + return $this->{"__Collection__{$name}"}(...$arguments); } throw new \BadMethodCallException("Method {$name} does not exist."); From 19ecc2791e1fd04cf39c6860f4373ffa4cc97778 Mon Sep 17 00:00:00 2001 From: Valithor Obsidion Date: Tue, 24 Dec 2024 12:04:26 -0500 Subject: [PATCH 06/14] Add missing method to CollectionTrait and fix import --- src/Discord/Helpers/CollectionTrait.php | 12 ++++++++++++ src/Discord/Repository/AbstractRepositoryTrait.php | 10 ---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/Discord/Helpers/CollectionTrait.php b/src/Discord/Helpers/CollectionTrait.php index 2cbf79f6f..ae8e45922 100644 --- a/src/Discord/Helpers/CollectionTrait.php +++ b/src/Discord/Helpers/CollectionTrait.php @@ -353,6 +353,18 @@ public function toArray() return $this->items; } + /** + * @since 11.0.0 + * + * Get the keys of the items. + * + * @return int[]|string[] + */ + public function keys(): array + { + return array_keys($this->items); + } + /** * If the collection has an offset. * diff --git a/src/Discord/Repository/AbstractRepositoryTrait.php b/src/Discord/Repository/AbstractRepositoryTrait.php index 5da829946..77dea4df5 100644 --- a/src/Discord/Repository/AbstractRepositoryTrait.php +++ b/src/Discord/Repository/AbstractRepositoryTrait.php @@ -14,7 +14,6 @@ use Discord\Discord; use Discord\Factory\Factory; use Discord\Helpers\CacheWrapper; -use Discord\Helpers\Collection; use Discord\Helpers\CollectionInterface; use Discord\Helpers\CollectionTrait; use Discord\Helpers\LegacyCacheWrapper; @@ -47,17 +46,9 @@ trait AbstractRepositoryTrait // 'Parent' methods __construct as __Collection____construct; - freshen as __Collection__freshen; - create as __Collection__create; - save as __Collection__save; - delete as __Collection__delete; - fresh as __Collection__fresh; - fetch as __Collection__fetch; get as __Collection__get; - cacheGet as __Collection__cacheGet; set as __Collection__set; pull as __Collection__pull; - cachePull as __Collection__cachePull; pushItem as __Collection__pushItem; first as __Collection__first; last as __Collection__last; @@ -73,7 +64,6 @@ trait AbstractRepositoryTrait offsetUnset as __Collection__offsetUnset; jsonSerialize as __Collection__jsonSerialize; getIterator as __Collection__getIterator; - __get as __Collection____get; } /** * The collection discriminator. From dcd2df1da616ac613df5c2d7184cb986810f1ee3 Mon Sep 17 00:00:00 2001 From: Valithor Obsidion Date: Tue, 24 Dec 2024 12:16:01 -0500 Subject: [PATCH 07/14] Move properties out of trait and into class These properties will need to be overwritten by other classes that extend this one --- src/Discord/Helpers/Collection.php | 21 +++++++++++++++++++ src/Discord/Helpers/CollectionTrait.php | 21 ------------------- src/Discord/Repository/AbstractRepository.php | 21 +++++++++++++++++++ .../Repository/AbstractRepositoryTrait.php | 20 ------------------ 4 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/Discord/Helpers/Collection.php b/src/Discord/Helpers/Collection.php index 8f92909ee..d64f1ab2b 100644 --- a/src/Discord/Helpers/Collection.php +++ b/src/Discord/Helpers/Collection.php @@ -19,5 +19,26 @@ */ 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; + use CollectionTrait; } diff --git a/src/Discord/Helpers/CollectionTrait.php b/src/Discord/Helpers/CollectionTrait.php index ae8e45922..e5e9c32cc 100644 --- a/src/Discord/Helpers/CollectionTrait.php +++ b/src/Discord/Helpers/CollectionTrait.php @@ -13,27 +13,6 @@ 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. * diff --git a/src/Discord/Repository/AbstractRepository.php b/src/Discord/Repository/AbstractRepository.php index 6c43c730c..02ee7ac8b 100755 --- a/src/Discord/Repository/AbstractRepository.php +++ b/src/Discord/Repository/AbstractRepository.php @@ -39,5 +39,26 @@ */ abstract class AbstractRepository implements CollectionInterface { + /** + * The collection discriminator. + * + * @var string Discriminator. + */ + protected $discrim = 'id'; + + /** + * The items contained in the collection. + * + * @var array + */ + protected $items = []; + + /** + * Class type allowed into the collection. + * + * @var string + */ + protected $class; + use AbstractRepositoryTrait; } diff --git a/src/Discord/Repository/AbstractRepositoryTrait.php b/src/Discord/Repository/AbstractRepositoryTrait.php index 77dea4df5..123412d04 100644 --- a/src/Discord/Repository/AbstractRepositoryTrait.php +++ b/src/Discord/Repository/AbstractRepositoryTrait.php @@ -65,26 +65,6 @@ trait AbstractRepositoryTrait jsonSerialize as __Collection__jsonSerialize; getIterator as __Collection__getIterator; } - /** - * The collection discriminator. - * - * @var string Discriminator. - */ - protected $discrim = 'id'; - - /** - * The items contained in the collection. - * - * @var array - */ - protected $items = []; - - /** - * Class type allowed into the collection. - * - * @var string - */ - protected $class; /** * The HTTP client. From edfe2c64659f6bc7c227039992d99f101978360e Mon Sep 17 00:00:00 2001 From: Valithor Obsidion Date: Tue, 24 Dec 2024 12:19:23 -0500 Subject: [PATCH 08/14] Update AbstractRepositoryInterface.php --- src/Discord/Repository/AbstractRepositoryInterface.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Discord/Repository/AbstractRepositoryInterface.php b/src/Discord/Repository/AbstractRepositoryInterface.php index b821a64de..887bd43b3 100644 --- a/src/Discord/Repository/AbstractRepositoryInterface.php +++ b/src/Discord/Repository/AbstractRepositoryInterface.php @@ -50,7 +50,7 @@ public function jsonSerialize(): array; public function &getIterator(): Traversable; public function __get(string $key); - // Methods imported from CollectionTrait + /* Methods imported from CollectionTrait public function fill(array $items): static; public function push(...$items): static; public function isset($offset): bool; @@ -61,4 +61,5 @@ public function __serialize(): array; public function unserialize(string $serialized): void; public function __unserialize(array $data): void; public function __debugInfo(): array; + */ } From 97f2f17ed8dfacd63c94c7f4662ef84be7708d77 Mon Sep 17 00:00:00 2001 From: Valithor Obsidion Date: Tue, 24 Dec 2024 12:21:33 -0500 Subject: [PATCH 09/14] Remove static return typing from interfaces This causes a conflict when using as traits --- src/Discord/Helpers/CollectionInterface.php | 12 ++++++------ .../Repository/AbstractRepositoryInterface.php | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Discord/Helpers/CollectionInterface.php b/src/Discord/Helpers/CollectionInterface.php index b3ed23b61..9266e208a 100644 --- a/src/Discord/Helpers/CollectionInterface.php +++ b/src/Discord/Helpers/CollectionInterface.php @@ -22,19 +22,19 @@ interface CollectionInterface extends ArrayAccess, JsonSerializable, IteratorAgg 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 fill(array $items); + public function push(...$items); + public function pushItem($item); 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 filter(callable $callback); public function find(callable $callback); public function clear(): void; - public function map(callable $callback): static; - public function merge($collection): static; + public function map(callable $callback); + public function merge($collection); public function toArray(); public function offsetExists($offset): bool; #[\ReturnTypeWillChange] diff --git a/src/Discord/Repository/AbstractRepositoryInterface.php b/src/Discord/Repository/AbstractRepositoryInterface.php index 887bd43b3..4ba9eb336 100644 --- a/src/Discord/Repository/AbstractRepositoryInterface.php +++ b/src/Discord/Repository/AbstractRepositoryInterface.php @@ -51,11 +51,11 @@ public function &getIterator(): Traversable; public function __get(string $key); /* Methods imported from CollectionTrait - public function fill(array $items): static; - public function push(...$items): static; + public function fill(array $items); + public function push(...$items); public function isset($offset): bool; - public function map(callable $callback): static; - public function merge($collection): static; + public function map(callable $callback); + public function merge($collection); public function serialize(): string; public function __serialize(): array; public function unserialize(string $serialized): void; From d2a89055a9853697685e5cfecd12f4bf51d9eeb3 Mon Sep 17 00:00:00 2001 From: Valithor Obsidion Date: Tue, 24 Dec 2024 12:25:04 -0500 Subject: [PATCH 10/14] Fix default class string for options resolver --- src/Discord/Discord.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Discord/Discord.php b/src/Discord/Discord.php index 7a6360cbc..1ada107ad 100644 --- a/src/Discord/Discord.php +++ b/src/Discord/Discord.php @@ -1433,7 +1433,7 @@ protected function resolveOptions(array $options = []): array 'intents' => Intents::getDefaultIntents(), 'socket_options' => [], 'cache' => [AbstractRepository::class => null], // use LegacyCacheWrapper - 'collection' => [Collection::class => null], + 'collection' => Collection::class, ]) ->setAllowedTypes('token', 'string') ->setAllowedTypes('logger', ['null', LoggerInterface::class]) From 2d72180dcd8e68d046054e0187e5a9c2b75d5ff1 Mon Sep 17 00:00:00 2001 From: Valithor Obsidion Date: Tue, 24 Dec 2024 12:26:59 -0500 Subject: [PATCH 11/14] Fix typo in calls to imported methods --- src/Discord/Repository/AbstractRepositoryTrait.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Discord/Repository/AbstractRepositoryTrait.php b/src/Discord/Repository/AbstractRepositoryTrait.php index 123412d04..c53845d8e 100644 --- a/src/Discord/Repository/AbstractRepositoryTrait.php +++ b/src/Discord/Repository/AbstractRepositoryTrait.php @@ -676,7 +676,7 @@ public function keys(): array */ public function offsetExists($offset): bool { - return $this->__CollectionoffsetExists($offset); + return $this->__Collection__offsetExists($offset); } /** @@ -691,7 +691,7 @@ public function offsetExists($offset): bool */ public function offsetGet($offset) { - $item = $this->__CollectionoffsetGet($offset); + $item = $this->__Collection__offsetGet($offset); if ($item instanceof WeakReference) { $item = $item->get(); @@ -714,7 +714,7 @@ public function offsetGet($offset) */ public function offsetSet($offset, $value): void { - $this->__CollectionoffsetSet($offset, $value); + $this->__Collection__offsetSet($offset, $value); } /** @@ -726,7 +726,7 @@ public function offsetSet($offset, $value): void */ public function offsetUnset($offset): void { - $this->__CollectionoffsetUnset($offset); + $this->__Collection__offsetUnset($offset); } /** From 81c9451586de0cd1b61efc93ce8d28fafdc0e868 Mon Sep 17 00:00:00 2001 From: Valithor Obsidion Date: Tue, 24 Dec 2024 12:42:03 -0500 Subject: [PATCH 12/14] All output should be run through an escaping function --- src/Discord/Repository/AbstractRepositoryTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Discord/Repository/AbstractRepositoryTrait.php b/src/Discord/Repository/AbstractRepositoryTrait.php index c53845d8e..a11bf02e2 100644 --- a/src/Discord/Repository/AbstractRepositoryTrait.php +++ b/src/Discord/Repository/AbstractRepositoryTrait.php @@ -782,6 +782,6 @@ public function __call($name, $arguments): mixed return $this->{"__Collection__{$name}"}(...$arguments); } - throw new \BadMethodCallException("Method {$name} does not exist."); + throw new \BadMethodCallException("Method " . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . " does not exist."); } } From 71f91ff2c4ee50b445e23ce255cc8deb00088d1b Mon Sep 17 00:00:00 2001 From: Valithor Obsidion Date: Tue, 24 Dec 2024 13:01:45 -0500 Subject: [PATCH 13/14] idk what Codacy wants from me --- src/Discord/Repository/AbstractRepositoryTrait.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Discord/Repository/AbstractRepositoryTrait.php b/src/Discord/Repository/AbstractRepositoryTrait.php index a11bf02e2..6e5737ccf 100644 --- a/src/Discord/Repository/AbstractRepositoryTrait.php +++ b/src/Discord/Repository/AbstractRepositoryTrait.php @@ -782,6 +782,7 @@ public function __call($name, $arguments): mixed return $this->{"__Collection__{$name}"}(...$arguments); } - throw new \BadMethodCallException("Method " . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . " does not exist."); + $name = htmlspecialchars($name, ENT_QUOTES, 'UTF-8'); + throw new \BadMethodCallException("Method $name does not exist."); } } From e5d8c4660ba2d78cdb082d15abb16cc88563eec2 Mon Sep 17 00:00:00 2001 From: Valithor Obsidion Date: Tue, 24 Dec 2024 13:05:24 -0500 Subject: [PATCH 14/14] I've decided that I don't care --- src/Discord/Repository/AbstractRepositoryTrait.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Discord/Repository/AbstractRepositoryTrait.php b/src/Discord/Repository/AbstractRepositoryTrait.php index 6e5737ccf..c18c9f6ce 100644 --- a/src/Discord/Repository/AbstractRepositoryTrait.php +++ b/src/Discord/Repository/AbstractRepositoryTrait.php @@ -782,7 +782,6 @@ public function __call($name, $arguments): mixed return $this->{"__Collection__{$name}"}(...$arguments); } - $name = htmlspecialchars($name, ENT_QUOTES, 'UTF-8'); throw new \BadMethodCallException("Method $name does not exist."); } }