update inbox list

This commit is contained in:
manhlab
2021-04-07 19:25:18 -04:00
parent fda7245f7c
commit 436de2efd6
8576 changed files with 1013325 additions and 3 deletions

103
vendor/ramsey/collection/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,103 @@
# ramsey/collection Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
### Changed
### Deprecated
### Removed
### Fixed
### Security
## [1.0.1] - 2020-01-04
### Fixed
* Fixed `AbstractCollection::offsetSet()` so that it uses the provided `$offset`
when setting `$value` in the array.
## [1.0.0] - 2018-12-31
### Added
* Added support for *queue* data structures to represent collections of ordered
entities. Together with *double-ended queues* (a.k.a. *deques*),
first-in-first-out (FIFO), last-in-first-out (LIFO), and other queue and stack
behaviors may be implemented. This functionality includes interfaces
`QueueInterface` and `DoubleEndedQueueInterface` and classes `Queue` and
`DoubleEndedQueue`.
* Added support for *set* data structures, representing collections that cannot
contain any duplicated elements; includes classes `AbstractSet` and `Set`.
* Added support for *typed map* data structures to represent maps of elements
where both keys and values have specified data types; includes
`TypedMapInterface` and the classes `AbstractTypedMap` and `TypedMap`.
* Added new manipulation and analyze methods for collections: `column()`,
`first()`, `last()`, `sort()`, `filter()`, `where()`, `map()`, `diff()`,
`intersect()`, and `merge()`. See [CollectionInterface](https://github.com/ramsey/collection/blob/master/src/CollectionInterface.php)
for more information.
* Added the following new exceptions specific to the ramsey/collection library:
`CollectionMismatchException`, `InvalidArgumentException`,
`InvalidSortOrderException`, `NoSuchElementException`, `OutOfBoundsException`,
`UnsupportedOperationException`, and `ValueExtractionException`.
### Changed
* Minimum PHP version supported is 7.2.
* Strict types are enforced throughout.
### Removed
* Removed support for HHVM.
### Security
* Fixed possible exploit using `AbstractArray::unserialize()`
(see [#47](https://github.com/ramsey/collection/issues/47)).
## [0.3.0] - 2016-05-23
### Added
* Added `MapInterface::keys()` method to return the keys from a `MapInterface`
object. This was added to the `AbstractMap` class.
### Removed
* Removed `getType()` and constructor methods from `AbstractCollection`. Children
of `AbstractCollection` must now implement `getType()`, which should return a
string value that defines the data type of items for the collection.
### Fixed
* Improve error messages in exceptions when `Collection` and `NamedParameterMap`
items fail type checks.
## [0.2.1] - 2016-02-22
### Fixed
* Allow non-strict checking of values in typed collections.
## [0.2.0] - 2016-02-05
### Added
* Support typed collections.
## [0.1.0] - 2015-10-27
### Added
* Support generic arrays and maps.
[Unreleased]: https://github.com/ramsey/collection/compare/1.0.1...HEAD
[1.0.1]: https://github.com/ramsey/collection/compare/1.0.0...1.0.1
[1.0.0]: https://github.com/ramsey/collection/compare/0.3.0...1.0.0
[0.3.0]: https://github.com/ramsey/collection/compare/0.2.1...0.3.0
[0.2.1]: https://github.com/ramsey/collection/compare/0.2.0...0.2.1
[0.2.0]: https://github.com/ramsey/collection/compare/0.1.0...0.2.0
[0.1.0]: https://github.com/ramsey/collection/commits/0.1.0

19
vendor/ramsey/collection/LICENSE vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2015-2020 Ben Ramsey <ben@benramsey.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

72
vendor/ramsey/collection/README.md vendored Normal file
View File

@@ -0,0 +1,72 @@
# ramsey/collection
[![Source Code][badge-source]][source]
[![Latest Version][badge-release]][release]
[![Software License][badge-license]][license]
[![Build Status][badge-build]][build]
[![Coverage Status][badge-coverage]][coverage]
[![Total Downloads][badge-downloads]][downloads]
ramsey/collection is a PHP 7.2+ library for representing and manipulating collections..
This project adheres to a [Contributor Code of Conduct][conduct]. By participating in this project and its community, you are expected to uphold this code.
## About
Much inspiration for this library came from the [Java Collections Framework][java].
## Installation
The preferred method of installation is via [Packagist][] and [Composer][]. Run
the following command to install the package and add it as a requirement to
your project's `composer.json`:
```bash
composer require ramsey/collection
```
## API documentation
The [latest class API documentation][apidocs] is available online.
## Examples
Examples of how to use this framework can be found in the [Wiki pages](https://github.com/ramsey/collection/wiki/Examples).
## Contributing
Contributions are welcome! Please read [CONTRIBUTING][] for details.
## Copyright and License
The ramsey/collection library is copyright © [Ben Ramsey](https://benramsey.com/) and licensed for use under the MIT License (MIT). Please see [LICENSE][] for more information.
[conduct]: https://github.com/ramsey/collection/blob/master/.github/CODE_OF_CONDUCT.md
[java]: http://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html
[packagist]: https://packagist.org/packages/ramsey/collection
[composer]: http://getcomposer.org/
[apidocs]: https://docs.benramsey.com/ramsey-collection/latest/
[contributing]: https://github.com/ramsey/collection/blob/master/.github/CONTRIBUTING.md
[badge-source]: http://img.shields.io/badge/source-ramsey/collection-blue.svg?style=flat-square
[badge-release]: https://img.shields.io/github/release/ramsey/collection.svg?style=flat-square
[badge-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
[badge-build]: https://img.shields.io/travis/ramsey/collection/master.svg?style=flat-square
[badge-coverage]: https://img.shields.io/coveralls/ramsey/collection/master.svg?style=flat-square
[badge-downloads]: https://img.shields.io/packagist/dt/ramsey/collection.svg?style=flat-square
[source]: https://github.com/ramsey/collection
[release]: https://github.com/ramsey/collection/releases
[license]: https://github.com/ramsey/collection/blob/master/LICENSE
[build]: https://travis-ci.org/ramsey/collection
[hhvm]: http://hhvm.h4cc.de/package/ramsey/collection
[coverage]: https://coveralls.io/r/ramsey/collection?branch=master
[downloads]: https://packagist.org/packages/ramsey/collection

67
vendor/ramsey/collection/composer.json vendored Normal file
View File

@@ -0,0 +1,67 @@
{
"name": "ramsey/collection",
"description": "A PHP 7.2+ library for representing and manipulating collections.",
"type": "library",
"keywords": ["array", "collection", "hash", "map", "queue", "set"],
"homepage": "https://github.com/ramsey/collection",
"license": "MIT",
"authors": [
{
"name": "Ben Ramsey",
"email": "ben@benramsey.com",
"homepage": "https://benramsey.com"
}
],
"support": {
"issues": "https://github.com/ramsey/collection/issues",
"source": "https://github.com/ramsey/collection"
},
"require": {
"php": "^7.2"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.5.0",
"fzaninotto/faker": "^1.5",
"jakub-onderka/php-parallel-lint": "^1",
"jangregor/phpstan-prophecy": "^0.6",
"mockery/mockery": "^1.3",
"phpstan/extension-installer": "^1",
"phpstan/phpdoc-parser": "0.4.1",
"phpstan/phpstan": "^0.12",
"phpstan/phpstan-mockery": "^0.12",
"phpstan/phpstan-phpunit": "^0.12",
"phpunit/phpunit": "^8.5",
"slevomat/coding-standard": "^6.0",
"squizlabs/php_codesniffer": "^3.5"
},
"autoload": {
"psr-4": {
"Ramsey\\Collection\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Ramsey\\Collection\\Test\\": "tests/"
}
},
"scripts": {
"lint": "parallel-lint src tests",
"phpcbf": "phpcbf -vpw",
"phpcs": "phpcs",
"phpstan": [
"phpstan analyse src -c phpstan.neon --level max --no-progress",
"phpstan analyse tests -c phpstan-tests.neon --level max --no-progress"
],
"phpunit": "phpunit --verbose --colors=always",
"phpunit-coverage": "phpunit --verbose --colors=always --coverage-html build/coverage",
"test": [
"@lint",
"@phpcs",
"@phpstan",
"@phpunit"
]
},
"config": {
"sort-packages": true
}
}

View File

@@ -0,0 +1,3 @@
parameters:
checkGenericClassInNonGenericObjectType: false
checkMissingIterableValueType: false

View File

@@ -0,0 +1,180 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection;
use ArrayIterator;
use Traversable;
use function serialize;
use function unserialize;
/**
* This class provides a basic implementation of `ArrayInterface`, to minimize
* the effort required to implement this interface.
*/
abstract class AbstractArray implements ArrayInterface
{
/**
* The items of this array.
*
* @var mixed[]
*/
protected $data = [];
/**
* Constructs a new array object.
*
* @param mixed[] $data The initial items to add to this array.
*/
public function __construct(array $data = [])
{
// Invoke offsetSet() for each value added; in this way, sub-classes
// may provide additional logic about values added to the array object.
foreach ($data as $key => $value) {
$this[$key] = $value;
}
}
/**
* Returns an iterator for this array.
*
* @link http://php.net/manual/en/iteratoraggregate.getiterator.php IteratorAggregate::getIterator()
*
* @return ArrayIterator<mixed, mixed>
*/
public function getIterator(): Traversable
{
return new ArrayIterator($this->data);
}
/**
* Returns `true` if the given offset exists in this array.
*
* @link http://php.net/manual/en/arrayaccess.offsetexists.php ArrayAccess::offsetExists()
*
* @param mixed $offset The offset to check.
*/
public function offsetExists($offset): bool
{
return isset($this->data[$offset]);
}
/**
* Returns the value at the specified offset.
*
* @link http://php.net/manual/en/arrayaccess.offsetget.php ArrayAccess::offsetGet()
*
* @param mixed $offset The offset for which a value should be returned.
*
* @return mixed|null the value stored at the offset, or null if the offset
* does not exist.
*/
public function offsetGet($offset)
{
return $this->data[$offset] ?? null;
}
/**
* Sets the given value to the given offset in the array.
*
* @link http://php.net/manual/en/arrayaccess.offsetset.php ArrayAccess::offsetSet()
*
* @param mixed|null $offset The offset to set. If `null`, the value may be
* set at a numerically-indexed offset.
* @param mixed $value The value to set at the given offset.
*/
public function offsetSet($offset, $value): void
{
if ($offset === null) {
$this->data[] = $value;
} else {
$this->data[$offset] = $value;
}
}
/**
* Removes the given offset and its value from the array.
*
* @link http://php.net/manual/en/arrayaccess.offsetunset.php ArrayAccess::offsetUnset()
*
* @param mixed $offset The offset to remove from the array.
*/
public function offsetUnset($offset): void
{
unset($this->data[$offset]);
}
/**
* Returns a serialized string representation of this array object.
*
* @link http://php.net/manual/en/serializable.serialize.php Serializable::serialize()
*
* @return string a PHP serialized string.
*/
public function serialize(): string
{
return serialize($this->data);
}
/**
* Converts a serialized string representation into an instance object.
*
* @link http://php.net/manual/en/serializable.unserialize.php Serializable::unserialize()
*
* @param string $serialized A PHP serialized string to unserialize.
*
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
*/
public function unserialize($serialized): void
{
$this->data = unserialize($serialized, ['allowed_classes' => false]);
}
/**
* Returns the number of items in this array.
*
* @link http://php.net/manual/en/countable.count.php Countable::count()
*/
public function count(): int
{
return count($this->data);
}
/**
* Removes all items from this array.
*/
public function clear(): void
{
$this->data = [];
}
/**
* Returns a native PHP array representation of this array object.
*
* @return mixed[]
*/
public function toArray(): array
{
return $this->data;
}
/**
* Returns `true` if this array is empty.
*/
public function isEmpty(): bool
{
return count($this->data) === 0;
}
}

View File

@@ -0,0 +1,355 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection;
use Ramsey\Collection\Exception\CollectionMismatchException;
use Ramsey\Collection\Exception\InvalidArgumentException;
use Ramsey\Collection\Exception\InvalidSortOrderException;
use Ramsey\Collection\Exception\OutOfBoundsException;
use Ramsey\Collection\Exception\ValueExtractionException;
use Ramsey\Collection\Tool\TypeTrait;
use Ramsey\Collection\Tool\ValueExtractorTrait;
use Ramsey\Collection\Tool\ValueToStringTrait;
use function array_filter;
use function array_map;
use function array_merge;
use function array_search;
use function array_udiff;
use function array_uintersect;
use function current;
use function end;
use function in_array;
use function reset;
use function sprintf;
use function unserialize;
use function usort;
/**
* This class provides a basic implementation of `CollectionInterface`, to
* minimize the effort required to implement this interface
*/
abstract class AbstractCollection extends AbstractArray implements CollectionInterface
{
use TypeTrait;
use ValueToStringTrait;
use ValueExtractorTrait;
/**
* Ensures that this collection contains the specified element.
*
* @param mixed $element The element to add to the collection.
*
* @return bool `true` if this collection changed as a result of the call.
*
* @throws InvalidArgumentException when the element does not match the
* specified type for this collection.
*/
public function add($element): bool
{
$this[] = $element;
return true;
}
/**
* Returns `true` if this collection contains the specified element.
*
* @param mixed $element The element to check whether the collection contains.
* @param bool $strict Whether to perform a strict type check on the value.
*/
public function contains($element, bool $strict = true): bool
{
return in_array($element, $this->data, $strict);
}
/**
* Sets the given value to the given offset in the array.
*
* @param mixed|null $offset The position to set the value in the array, or
* `null` to append the value to the array.
* @param mixed $value The value to set at the given offset.
*
* @throws InvalidArgumentException when the value does not match the
* specified type for this collection.
*/
public function offsetSet($offset, $value): void
{
if ($this->checkType($this->getType(), $value) === false) {
throw new InvalidArgumentException(
'Value must be of type ' . $this->getType() . '; value is '
. $this->toolValueToString($value)
);
}
if ($offset === null) {
$this->data[] = $value;
} else {
$this->data[$offset] = $value;
}
}
/**
* Removes a single instance of the specified element from this collection,
* if it is present.
*
* @param mixed $element The element to remove from the collection.
*
* @return bool `true` if an element was removed as a result of this call.
*/
public function remove($element): bool
{
if (($position = array_search($element, $this->data, true)) !== false) {
unset($this->data[$position]);
return true;
}
return false;
}
/**
* Returns the values from given property or method.
*
* @param string $propertyOrMethod The property or method name to filter by.
*
* @return mixed[]
*
* @throws ValueExtractionException if property or method is not defined.
*/
public function column(string $propertyOrMethod): array
{
$temp = [];
foreach ($this->data as $item) {
$temp[] = $this->extractValue($item, $propertyOrMethod);
}
return $temp;
}
/**
* Returns the first item of the collection.
*
* @return mixed
*
* @throws OutOfBoundsException when the collection is empty.
*/
public function first()
{
if ($this->isEmpty()) {
throw new OutOfBoundsException('Can\'t determine first item. Collection is empty');
}
reset($this->data);
return current($this->data);
}
/**
* Returns the last item of the collection.
*
* @return mixed
*
* @throws OutOfBoundsException when the collection is empty.
*/
public function last()
{
if ($this->isEmpty()) {
throw new OutOfBoundsException('Can\'t determine last item. Collection is empty');
}
$item = end($this->data);
reset($this->data);
return $item;
}
/**
* Returns a sorted collection.
*
* {@inheritdoc}
*
* @param string $propertyOrMethod The property or method to sort by.
* @param string $order The sort order for the resulting collection (one of
* this interface's `SORT_*` constants).
*
* @return CollectionInterface<mixed, mixed>
*
* @throws InvalidSortOrderException if neither "asc" nor "desc" was given
* as the order.
* @throws ValueExtractionException if property or method is not defined.
*/
public function sort(string $propertyOrMethod, string $order = self::SORT_ASC): CollectionInterface
{
if (!in_array($order, [self::SORT_ASC, self::SORT_DESC], true)) {
throw new InvalidSortOrderException('Invalid sort order given: ' . $order);
}
$collection = clone $this;
usort($collection->data, function ($a, $b) use ($propertyOrMethod, $order) {
$aValue = $this->extractValue($a, $propertyOrMethod);
$bValue = $this->extractValue($b, $propertyOrMethod);
return ($aValue <=> $bValue) * ($order === self::SORT_DESC ? -1 : 1);
});
return $collection;
}
/**
* Returns a filtered collection.
*
* {@inheritdoc}
*
* @param callable $callback A callable to use for filtering elements.
*
* @return CollectionInterface<mixed, mixed>
*/
public function filter(callable $callback): CollectionInterface
{
$collection = clone $this;
$collection->data = array_merge([], array_filter($collection->data, $callback));
return $collection;
}
/**
* Returns a collection of matching items.
*
* {@inheritdoc}
*
* @param string $propertyOrMethod The property or method to evaluate.
* @param mixed $value The value to match.
*
* @return CollectionInterface<mixed, mixed>
*
* @throws ValueExtractionException if property or method is not defined.
*/
public function where(string $propertyOrMethod, $value): CollectionInterface
{
return $this->filter(function ($item) use ($propertyOrMethod, $value) {
$accessorValue = $this->extractValue($item, $propertyOrMethod);
return $accessorValue === $value;
});
}
/**
* Applies a callback to each item of the collection.
*
* {@inheritdoc}
*
* @param callable $callback A callable to apply to each item of the
* collection.
*
* @return CollectionInterface<mixed, mixed>
*/
public function map(callable $callback): CollectionInterface
{
$collection = clone $this;
array_map($callback, $collection->data);
return $collection;
}
/**
* Create a new collection with divergent items between current and given
* collection.
*
* @param CollectionInterface<mixed, mixed> $other The collection to check for divergent
* items.
*
* @return CollectionInterface<mixed, mixed>
*
* @throws CollectionMismatchException if the given collection is not of the
* same type.
*/
public function diff(CollectionInterface $other): CollectionInterface
{
if (!$other instanceof static) {
throw new CollectionMismatchException('Collection must be of type ' . static::class);
}
$comparator = function ($a, $b) {
return $a === $b ? 0 : -1;
};
$diffAtoB = array_udiff($this->data, $other->data, $comparator);
$diffBtoA = array_udiff($other->data, $this->data, $comparator);
return new static(array_merge($diffAtoB, $diffBtoA));
}
/**
* Create a new collection with intersecting item between current and given
* collection.
*
* @param CollectionInterface<mixed, mixed> $other The collection to check for
* intersecting items.
*
* @return CollectionInterface<mixed, mixed>
*
* @throws CollectionMismatchException if the given collection is not of the
* same type.
*/
public function intersect(CollectionInterface $other): CollectionInterface
{
if (!$other instanceof static) {
throw new CollectionMismatchException('Collection must be of type ' . static::class);
}
$intersect = array_uintersect($this->data, $other->data, function ($a, $b) {
return $a === $b ? 0 : -1;
});
return new static($intersect);
}
/**
* Merge current items and items of given collections into a new one.
*
* @param CollectionInterface<mixed, mixed> ...$collections The collections to merge.
*
* @return CollectionInterface<mixed, mixed>
*
* @throws CollectionMismatchException if any of the given collections are not of the same type.
*/
public function merge(CollectionInterface ...$collections): CollectionInterface
{
$temp = [$this->data];
foreach ($collections as $index => $collection) {
if (!$collection instanceof static) {
throw new CollectionMismatchException(
sprintf('Collection with index %d must be of type %s', $index, static::class)
);
}
$temp[] = $collection->toArray();
}
return new static(array_merge(...$temp));
}
/**
* @inheritDoc
*/
public function unserialize($serialized): void
{
$this->data = unserialize($serialized, ['allowed_classes' => [$this->getType()]]);
}
}

View File

@@ -0,0 +1,64 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection;
use Ramsey\Collection\Exception\InvalidArgumentException;
/**
* This class contains the basic implementation of a collection that does not
* allow duplicated values (a set), to minimize the effort required to implement
* this specific type of collection.
*/
abstract class AbstractSet extends AbstractCollection
{
/**
* Adds the specified element to this set, if it is not already present.
*
* @param mixed $element The element to add to the set.
*
* @return bool `true` if this set did not already contain the specified
* element.
*
* @throws InvalidArgumentException when the element does not match the
* specified type for this set.
*/
public function add($element): bool
{
if ($this->contains($element)) {
return false;
}
return parent::add($element);
}
/**
* Sets the given value to the given offset in this set, if it is not
* already present.
*
* @param mixed|null $offset The offset is ignored and is treated as `null`.
* @param mixed $value The value to set at the given offset.
*
* @throws InvalidArgumentException when the value does not match the
* specified type for this set.
*/
public function offsetSet($offset, $value): void
{
if ($this->contains($value)) {
return;
}
parent::offsetSet($offset, $value);
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection;
use ArrayAccess;
use Countable;
use IteratorAggregate;
use Serializable;
/**
* `ArrayInterface` provides traversable array functionality to data types.
*/
interface ArrayInterface extends
ArrayAccess,
Countable,
IteratorAggregate,
Serializable
{
/**
* Removes all items from this array.
*/
public function clear(): void;
/**
* Returns a native PHP array representation of this array object.
*
* @return mixed[]
*/
public function toArray(): array;
/**
* Returns `true` if this array is empty.
*/
public function isEmpty(): bool;
}

View File

@@ -0,0 +1,106 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection;
/**
* A collection represents a group of objects.
*
* Each object in the collection is of a specific, defined type.
*
* This is a direct implementation of `CollectionInterface`, provided for
* the sake of convenience.
*
* Example usage:
*
* ``` php
* $collection = new \Ramsey\Collection\Collection('My\\Foo');
* $collection->add(new \My\Foo());
* $collection->add(new \My\Foo());
*
* foreach ($collection as $foo) {
* // Do something with $foo
* }
* ```
*
* It is preferable to subclass `AbstractCollection` to create your own typed
* collections. For example:
*
* ``` php
* namespace My\Foo;
*
* class FooCollection extends \Ramsey\Collection\AbstractCollection
* {
* public function getType()
* {
* return 'My\\Foo';
* }
* }
* ```
*
* And then use it similarly to the earlier example:
*
* ``` php
* $fooCollection = new \My\Foo\FooCollection();
* $fooCollection->add(new \My\Foo());
* $fooCollection->add(new \My\Foo());
*
* foreach ($fooCollection as $foo) {
* // Do something with $foo
* }
* ```
*
* The benefit with this approach is that you may do type-checking on the
* collection object:
*
* ``` php
* if ($collection instanceof \My\Foo\FooCollection) {
* // the collection is a collection of My\Foo objects
* }
* ```
*/
class Collection extends AbstractCollection
{
/**
* The type of elements stored in this collection.
*
* A collection's type is immutable once it is set. For this reason, this
* property is set private.
*
* @var string
*/
private $collectionType;
/**
* Constructs a collection object of the specified type, optionally with the
* specified data.
*
* @param string $collectionType The type (FQCN) associated with this
* collection.
* @param mixed[] $data The initial items to store in the collection.
*/
public function __construct(string $collectionType, array $data = [])
{
$this->collectionType = $collectionType;
parent::__construct($data);
}
/**
* Returns the type associated with this collection.
*/
public function getType(): string
{
return $this->collectionType;
}
}

View File

@@ -0,0 +1,196 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection;
/**
* A collection represents a group of objects, known as its elements.
*
* Some collections allow duplicate elements and others do not. Some are ordered
* and others unordered.
*/
interface CollectionInterface extends ArrayInterface
{
/**
* Ascending sort type.
*/
public const SORT_ASC = 'asc';
/**
* Descending sort type.
*/
public const SORT_DESC = 'desc';
/**
* Ensures that this collection contains the specified element (optional
* operation).
*
* Returns `true` if this collection changed as a result of the call.
* (Returns `false` if this collection does not permit duplicates and
* already contains the specified element.)
*
* Collections that support this operation may place limitations on what
* elements may be added to this collection. In particular, some
* collections will refuse to add `null` elements, and others will impose
* restrictions on the type of elements that may be added. Collection
* classes should clearly specify in their documentation any restrictions
* on what elements may be added.
*
* If a collection refuses to add a particular element for any reason other
* than that it already contains the element, it must throw an exception
* (rather than returning `false`). This preserves the invariant that a
* collection always contains the specified element after this call returns.
*
* @param mixed $element The element to add to the collection.
*
* @return bool `true` if this collection changed as a result of the call.
*/
public function add($element): bool;
/**
* Returns `true` if this collection contains the specified element.
*
* @param mixed $element The element to check whether the collection contains.
* @param bool $strict Whether to perform a strict type check on the value.
*/
public function contains($element, bool $strict = true): bool;
/**
* Returns the type associated with this collection.
*/
public function getType(): string;
/**
* Removes a single instance of the specified element from this collection,
* if it is present.
*
* @param mixed $element The element to remove from the collection.
*
* @return bool `true` if an element was removed as a result of this call.
*/
public function remove($element): bool;
/**
* Returns the values from the given property or method.
*
* @param string $propertyOrMethod The property or method name to filter by.
*
* @return mixed[]
*/
public function column(string $propertyOrMethod): array;
/**
* Returns the first item of the collection.
*
* @return mixed
*/
public function first();
/**
* Returns the last item of the collection.
*
* @return mixed
*/
public function last();
/**
* Sort the collection by a property or method with the given sort order.
*
* This will always leave the original collection untouched and will return
* a new one.
*
* @param string $propertyOrMethod The property or method to sort by.
* @param string $order The sort order for the resulting collection (one of
* this interface's `SORT_*` constants).
*
* @return CollectionInterface<mixed, mixed>
*/
public function sort(string $propertyOrMethod, string $order = self::SORT_ASC): self;
/**
* Filter out items of the collection which don't match the criteria of
* given callback.
*
* This will always leave the original collection untouched and will return
* a new one.
*
* See the {@link http://php.net/manual/en/function.array-filter.php PHP array_filter() documentation}
* for examples of how the `$callback` parameter works.
*
* @param callable $callback A callable to use for filtering elements.
*
* @return CollectionInterface<mixed, mixed>
*/
public function filter(callable $callback): self;
/**
* Create a new collection where items match the criteria of given callback.
*
* This will always leave the original collection untouched and will return
* a new one.
*
* @param string $propertyOrMethod The property or method to evaluate.
* @param mixed $value The value to match.
*
* @return CollectionInterface<mixed, mixed>
*/
public function where(string $propertyOrMethod, $value): self;
/**
* Apply a given callback method on each item of the collection.
*
* This will always leave the original collection untouched and will return
* a new one.
*
* See the {@link http://php.net/manual/en/function.array-map.php PHP array_map() documentation}
* for examples of how the `$callback` parameter works.
*
* @param callable $callback A callable to apply to each item of the
* collection.
*
* @return CollectionInterface<mixed, mixed>
*/
public function map(callable $callback): self;
/**
* Create a new collection with divergent items between current and given
* collection.
*
* @param CollectionInterface<mixed, mixed> $other The collection to check for divergent
* items.
*
* @return CollectionInterface<mixed, mixed>
*/
public function diff(CollectionInterface $other): self;
/**
* Create a new collection with intersecting item between current and given
* collection.
*
* @param CollectionInterface<mixed, mixed> $other The collection to check for
* intersecting items.
*
* @return CollectionInterface<mixed, mixed>
*/
public function intersect(CollectionInterface $other): self;
/**
* Merge current items and items of given collections into a new one.
*
* @param CollectionInterface<mixed, mixed> ...$collections The collections to merge.
*
* @return CollectionInterface<mixed, mixed>
*/
public function merge(CollectionInterface ...$collections): self;
}

View File

@@ -0,0 +1,288 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection;
use Ramsey\Collection\Exception\InvalidArgumentException;
use Ramsey\Collection\Exception\NoSuchElementException;
/**
* This class provides a basic implementation of `DoubleEndedQueueInterface`, to
* minimize the effort required to implement this interface.
*/
class DoubleEndedQueue extends Queue implements DoubleEndedQueueInterface
{
/**
* Index of the last element in the queue.
*
* @var int
*/
private $tail = -1;
/**
* Sets the given value to the given offset in the queue.
*
* Since arbitrary offsets may not be manipulated in a queue, this method
* serves only to fulfill the `ArrayAccess` interface requirements. It is
* invoked by other operations when adding values to the queue.
*
* @link http://php.net/manual/en/arrayaccess.offsetset.php ArrayAccess::offsetSet()
*
* @param mixed|null $offset The offset is ignored and is treated as `null`.
* @param mixed $value The value to set at the given offset.
*
* @throws InvalidArgumentException when the value does not match the
* specified type for this queue.
*/
public function offsetSet($offset, $value): void
{
if ($this->checkType($this->getType(), $value) === false) {
throw new InvalidArgumentException(
'Value must be of type ' . $this->getType() . '; value is '
. $this->toolValueToString($value)
);
}
$this->tail++;
$this->data[$this->tail] = $value;
}
/**
* Ensures that the specified element is inserted at the front of this queue.
*
* @see self::offerFirst()
*
* @param mixed $element The element to add to this queue.
*
* @return bool `true` if this queue changed as a result of the call.
*
* @throws InvalidArgumentException when the value does not match the
* specified type for this queue.
*/
public function addFirst($element): bool
{
if ($this->checkType($this->getType(), $element) === false) {
throw new InvalidArgumentException(
'Value must be of type ' . $this->getType() . '; value is '
. $this->toolValueToString($element)
);
}
$this->index--;
$this->data[$this->index] = $element;
return true;
}
/**
* Ensures that the specified element in inserted at the end of this queue.
*
* @see Queue::add()
*
* @param mixed $element The element to add to this queue.
*
* @return bool `true` if this queue changed as a result of the call.
*
* @throws InvalidArgumentException when the value does not match the
* specified type for this queue.
*/
public function addLast($element): bool
{
return $this->add($element);
}
/**
* Inserts the specified element at the front this queue.
*
* @see self::addFirst()
*
* @param mixed $element The element to add to this queue.
*
* @return bool `true` if the element was added to this queue, else `false`.
*/
public function offerFirst($element): bool
{
try {
return $this->addFirst($element);
} catch (InvalidArgumentException $e) {
return false;
}
}
/**
* Inserts the specified element at the end this queue.
*
* @see self::addLast()
* @see Queue::offer()
*
* @param mixed $element The element to add to this queue.
*
* @return bool `true` if the element was added to this queue, else `false`.
*/
public function offerLast($element): bool
{
return $this->offer($element);
}
/**
* Retrieves and removes the head of this queue.
*
* This method differs from `pollFirst()` only in that it throws an
* exception if this queue is empty.
*
* @see self::pollFirst()
* @see Queue::remove()
*
* @return mixed the head of this queue.
*
* @throws NoSuchElementException if this queue is empty.
*/
public function removeFirst()
{
return $this->remove();
}
/**
* Retrieves and removes the tail of this queue.
*
* This method differs from `pollLast()` only in that it throws an exception
* if this queue is empty.
*
* @see self::pollLast()
*
* @return mixed the tail of this queue.
*
* @throws NoSuchElementException if this queue is empty.
*/
public function removeLast()
{
if ($this->count() === 0) {
throw new NoSuchElementException('Can\'t return element from Queue. Queue is empty.');
}
$tail = $this[$this->tail];
unset($this[$this->tail]);
$this->tail--;
return $tail;
}
/**
* Retrieves and removes the head of this queue, or returns `null` if this
* queue is empty.
*
* @see self::removeFirst()
*
* @return mixed|null the head of this queue, or `null` if this queue is empty.
*/
public function pollFirst()
{
return $this->poll();
}
/**
* Retrieves and removes the tail of this queue, or returns `null` if this
* queue is empty.
*
* @see self::removeLast()
*
* @return mixed|null the tail of this queue, or `null` if this queue is empty.
*/
public function pollLast()
{
if ($this->count() === 0) {
return null;
}
$tail = $this[$this->tail];
unset($this[$this->tail]);
$this->tail--;
return $tail;
}
/**
* Retrieves, but does not remove, the head of this queue.
*
* This method differs from `peekFirst()` only in that it throws an
* exception if this queue is empty.
*
* @see self::peekFirst()
* @see Queue::element()
*
* @return mixed the head of this queue.
*
* @throws NoSuchElementException if this queue is empty.
*/
public function firstElement()
{
return $this->element();
}
/**
* Retrieves, but does not remove, the tail of this queue.
*
* This method differs from `peekLast()` only in that it throws an exception
* if this queue is empty.
*
* @see self::peekLast()
*
* @return mixed the tail of this queue.
*
* @throws NoSuchElementException if this queue is empty.
*/
public function lastElement()
{
if ($this->count() === 0) {
throw new NoSuchElementException('Can\'t return element from Queue. Queue is empty.');
}
return $this->data[$this->tail];
}
/**
* Retrieves, but does not remove, the head of this queue, or returns `null`
* if this queue is empty.
*
* @see self::firstElement()
* @see Queue::peek()
*
* @return mixed|null the head of this queue, or `null` if this queue is empty.
*/
public function peekFirst()
{
return $this->peek();
}
/**
* Retrieves, but does not remove, the tail of this queue, or returns `null`
* if this queue is empty.
*
* @see self::lastElement()
*
* @return mixed|null the tail of this queue, or `null` if this queue is empty
*/
public function peekLast()
{
if ($this->count() === 0) {
return null;
}
return $this->data[$this->tail];
}
}

View File

@@ -0,0 +1,309 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection;
use Ramsey\Collection\Exception\NoSuchElementException;
/**
* A linear collection that supports element insertion and removal at both ends.
*
* Most `DoubleEndedQueueInterface` implementations place no fixed limits on the
* number of elements they may contain, but this interface supports
* capacity-restricted double-ended queues as well as those with no fixed size
* limit.
*
* This interface defines methods to access the elements at both ends of the
* double-ended queue. Methods are provided to insert, remove, and examine the
* element. Each of these methods exists in two forms: one throws an exception
* if the operation fails, the other returns a special value (either `null` or
* `false`, depending on the operation). The latter form of the insert operation
* is designed specifically for use with capacity-restricted implementations; in
* most implementations, insert operations cannot fail.
*
* The twelve methods described above are summarized in the following table:
*
* <table>
* <caption>Summary of DoubleEndedQueueInterface methods</caption>
* <thead>
* <tr>
* <th></th>
* <th colspan=2>First Element (Head)</th>
* <th colspan=2>Last Element (Tail)</th>
* </tr>
* <tr>
* <td></td>
* <td><em>Throws exception</em></td>
* <td><em>Special value</em></td>
* <td><em>Throws exception</em></td>
* <td><em>Special value</em></td>
* </tr>
* </thead>
* <tbody>
* <tr>
* <th>Insert</th>
* <td><code>addFirst()</code></td>
* <td><code>offerFirst()</code></td>
* <td><code>addLast()</code></td>
* <td><code>offerLast()</code></td>
* </tr>
* <tr>
* <th>Remove</th>
* <td><code>removeFirst()</code></td>
* <td><code>pollFirst()</code></td>
* <td><code>removeLast()</code></td>
* <td><code>pollLast()</code></td>
* </tr>
* <tr>
* <th>Examine</th>
* <td><code>firstElement()</code></td>
* <td><code>peekFirst()</code></td>
* <td><code>lastElement()</code></td>
* <td><code>peekLast()</code></td>
* </tr>
* </tbody>
* </table>
*
* This interface extends the `QueueInterface`. When a double-ended queue is
* used as a queue, FIFO (first-in-first-out) behavior results. Elements are
* added at the end of the double-ended queue and removed from the beginning.
* The methods inherited from the `QueueInterface` are precisely equivalent to
* `DoubleEndedQueueInterface` methods as indicated in the following table:
*
* <table>
* <caption>Comparison of QueueInterface and DoubleEndedQueueInterface methods</caption>
* <thead>
* <tr>
* <th>QueueInterface Method</th>
* <th>DoubleEndedQueueInterface Method</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <td><code>add()</code></td>
* <td><code>addLast()</code></td>
* </tr>
* <tr>
* <td><code>offer()</code></td>
* <td><code>offerLast()</code></td>
* </tr>
* <tr>
* <td><code>remove()</code></td>
* <td><code>removeFirst()</code></td>
* </tr>
* <tr>
* <td><code>poll()</code></td>
* <td><code>pollFirst()</code></td>
* </tr>
* <tr>
* <td><code>element()</code></td>
* <td><code>firstElement()</code></td>
* </tr>
* <tr>
* <td><code>peek()</code></td>
* <td><code>peekFirst()</code></td>
* </tr>
* </tbody>
* </table>
*
* Double-ended queues can also be used as LIFO (last-in-first-out) stacks. When
* a double-ended queue is used as a stack, elements are pushed and popped from
* the beginning of the double-ended queue. Stack concepts are precisely
* equivalent to `DoubleEndedQueueInterface` methods as indicated in the table
* below:
*
* <table>
* <caption>Comparison of stack concepts and DoubleEndedQueueInterface methods</caption>
* <thead>
* <tr>
* <th>Stack concept</th>
* <th>DoubleEndedQueueInterface Method</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <td><em>push</em></td>
* <td><code>addFirst()</code></td>
* </tr>
* <tr>
* <td><em>pop</em></td>
* <td><code>removeFirst()</code></td>
* </tr>
* <tr>
* <td><em>peek</em></td>
* <td><code>peekFirst()</code></td>
* </tr>
* </tbody>
* </table>
*
* Note that the `peek()` method works equally well when a double-ended queue is
* used as a queue or a stack; in either case, elements are drawn from the
* beginning of the double-ended queue.
*
* While `DoubleEndedQueueInterface` implementations are not strictly required
* to prohibit the insertion of `null` elements, they are strongly encouraged to
* do so. Users of any `DoubleEndedQueueInterface` implementations that do allow
* `null` elements are strongly encouraged *not* to take advantage of the
* ability to insert nulls. This is so because `null` is used as a special
* return value by various methods to indicated that the double-ended queue is
* empty.
*/
interface DoubleEndedQueueInterface extends QueueInterface
{
/**
* Inserts the specified element at the front of this queue if it is
* possible to do so immediately without violating capacity restrictions.
*
* When using a capacity-restricted double-ended queue, it is generally
* preferable to use the `offerFirst()` method.
*
* @param mixed $element The element to add to the front of this queue.
*
* @return bool `true` if this queue changed as a result of the call.
*
* @throws \RuntimeException if a queue refuses to add a particular element
* for any reason other than that it already contains the element.
* Implementations should use a more-specific exception that extends
* `\RuntimeException`.
*/
public function addFirst($element): bool;
/**
* Inserts the specified element at the end of this queue if it is possible
* to do so immediately without violating capacity restrictions.
*
* When using a capacity-restricted double-ended queue, it is generally
* preferable to use the `offerLast()` method.
*
* This method is equivalent to `add()`.
*
* @param mixed $element The element to add to the end of this queue.
*
* @return bool `true` if this queue changed as a result of the call.
*
* @throws \RuntimeException if a queue refuses to add a particular element
* for any reason other than that it already contains the element.
* Implementations should use a more-specific exception that extends
* `\RuntimeException`.
*/
public function addLast($element): bool;
/**
* Inserts the specified element at the front of this queue if it is
* possible to do so immediately without violating capacity restrictions.
*
* When using a capacity-restricted queue, this method is generally
* preferable to `addFirst()`, which can fail to insert an element only by
* throwing an exception.
*
* @param mixed $element The element to add to the front of this queue.
*
* @return bool `true` if the element was added to this queue, else `false`.
*/
public function offerFirst($element): bool;
/**
* Inserts the specified element at the end of this queue if it is possible
* to do so immediately without violating capacity restrictions.
*
* When using a capacity-restricted queue, this method is generally
* preferable to `addLast()` which can fail to insert an element only by
* throwing an exception.
*
* @param mixed $element The element to add to the end of this queue.
*
* @return bool `true` if the element was added to this queue, else `false`.
*/
public function offerLast($element): bool;
/**
* Retrieves and removes the head of this queue.
*
* This method differs from `pollFirst()` only in that it throws an
* exception if this queue is empty.
*
* @return mixed the first element in this queue.
*
* @throws NoSuchElementException if this queue is empty.
*/
public function removeFirst();
/**
* Retrieves and removes the tail of this queue.
*
* This method differs from `pollLast()` only in that it throws an exception
* if this queue is empty.
*
* @return mixed the last element in this queue.
*
* @throws NoSuchElementException if this queue is empty.
*/
public function removeLast();
/**
* Retrieves and removes the head of this queue, or returns `null` if this
* queue is empty.
*
* @return mixed|null the head of this queue, or `null` if this queue is empty.
*/
public function pollFirst();
/**
* Retrieves and removes the tail of this queue, or returns `null` if this
* queue is empty.
*
* @return mixed|null the tail of this queue, or `null` if this queue is empty.
*/
public function pollLast();
/**
* Retrieves, but does not remove, the head of this queue.
*
* This method differs from `peekFirst()` only in that it throws an
* exception if this queue is empty.
*
* @return mixed the head of this queue.
*
* @throws NoSuchElementException if this queue is empty.
*/
public function firstElement();
/**
* Retrieves, but does not remove, the tail of this queue.
*
* This method differs from `peekLast()` only in that it throws an exception
* if this queue is empty.
*
* @return mixed the tail of this queue.
*
* @throws NoSuchElementException if this queue is empty.
*/
public function lastElement();
/**
* Retrieves, but does not remove, the head of this queue, or returns `null`
* if this queue is empty.
*
* @return mixed|null the head of this queue, or `null` if this queue is empty.
*/
public function peekFirst();
/**
* Retrieves, but does not remove, the tail of this queue, or returns `null`
* if this queue is empty.
*
* @return mixed|null the tail of this queue, or `null` if this queue is empty.
*/
public function peekLast();
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection\Exception;
/**
* Thrown when attempting to operate on collections of differing types.
*/
class CollectionMismatchException extends \RuntimeException
{
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection\Exception;
/**
* Thrown to indicate an argument is not of the expected type.
*/
class InvalidArgumentException extends \InvalidArgumentException
{
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection\Exception;
/**
* Thrown when attempting to use a sort order that is not recognized.
*/
class InvalidSortOrderException extends \RuntimeException
{
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection\Exception;
/**
* Thrown when attempting to access an element that does not exist.
*/
class NoSuchElementException extends \RuntimeException
{
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection\Exception;
/**
* Thrown when attempting to access an element out of the range of the collection.
*/
class OutOfBoundsException extends \OutOfBoundsException
{
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection\Exception;
/**
* Thrown to indicate that the requested operation is not supported.
*/
class UnsupportedOperationException extends \RuntimeException
{
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection\Exception;
/**
* Thrown when attempting to extract a value for a method or property that does not exist.
*/
class ValueExtractionException extends \RuntimeException
{
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection;
/**
* `GenericArray` represents a standard array object.
*/
class GenericArray extends AbstractArray
{
}

View File

@@ -0,0 +1,226 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection\Map;
use Ramsey\Collection\AbstractArray;
use Ramsey\Collection\Exception\InvalidArgumentException;
use function array_key_exists;
use function array_keys;
use function in_array;
/**
* This class provides a basic implementation of `MapInterface`, to minimize the
* effort required to implement this interface.
*/
abstract class AbstractMap extends AbstractArray implements MapInterface
{
/**
* Sets the given value to the given offset in the map.
*
* @param mixed $offset The offset to set.
* @param mixed $value The value to set at the given offset.
*
* @throws InvalidArgumentException if the offset provided is `null`.
*/
public function offsetSet($offset, $value): void
{
if ($offset === null) {
throw new InvalidArgumentException(
'Map elements are key/value pairs; a key must be provided for '
. 'value ' . $value
);
}
$this->data[$offset] = $value;
}
/**
* Returns `true` if this map contains a mapping for the specified key.
*
* @param mixed $key The key to check in the map.
*/
public function containsKey($key): bool
{
return array_key_exists($key, $this->data);
}
/**
* Returns `true` if this map maps one or more keys to the specified value.
*
* This performs a strict type check on the value.
*
* @param mixed $value The value to check in the map.
*/
public function containsValue($value): bool
{
return in_array($value, $this->data, true);
}
/**
* Return an array of the keys contained in this map.
*
* @return mixed[]
*/
public function keys(): array
{
return array_keys($this->data);
}
/**
* Returns the value to which the specified key is mapped, `null` if this
* map contains no mapping for the key, or (optionally) `$defaultValue` if
* this map contains no mapping for the key.
*
* @param mixed $key The key to return from the map.
* @param mixed $defaultValue The default value to use if `$key` is not found.
*
* @return mixed|null the value or `null` if the key could not be found.
*/
public function get($key, $defaultValue = null)
{
if (!$this->containsKey($key)) {
return $defaultValue;
}
return $this[$key];
}
/**
* Associates the specified value with the specified key in this map.
*
* If the map previously contained a mapping for the key, the old value is
* replaced by the specified value.
*
* @param mixed $key The key to put or replace in the map.
* @param mixed $value The value to store at `$key`.
*
* @return mixed|null the previous value associated with key, or `null` if
* there was no mapping for `$key`.
*/
public function put($key, $value)
{
$previousValue = $this->get($key);
$this[$key] = $value;
return $previousValue;
}
/**
* Associates the specified value with the specified key in this map only if
* it is not already set.
*
* If there is already a value associated with `$key`, this returns that
* value without replacing it.
*
* @param mixed $key The key to put in the map.
* @param mixed $value The value to store at `$key`.
*
* @return mixed|null the previous value associated with key, or `null` if
* there was no mapping for `$key`.
*/
public function putIfAbsent($key, $value)
{
$currentValue = $this->get($key);
if ($currentValue === null) {
$this[$key] = $value;
}
return $currentValue;
}
/**
* Removes the mapping for a key from this map if it is present.
*
* @param mixed $key The key to remove from the map.
*
* @return mixed|null the previous value associated with key, or `null` if
* there was no mapping for `$key`.
*/
public function remove($key)
{
$previousValue = $this->get($key);
unset($this[$key]);
return $previousValue;
}
/**
* Removes the entry for the specified key only if it is currently mapped to
* the specified value.
*
* This performs a strict type check on the value.
*
* @param mixed $key The key to remove from the map.
* @param mixed $value The value to match.
*
* @return bool true if the value was removed.
*/
public function removeIf($key, $value): bool
{
if ($this->get($key) === $value) {
unset($this[$key]);
return true;
}
return false;
}
/**
* Replaces the entry for the specified key only if it is currently mapped
* to some value.
*
* @param mixed $key The key to replace.
* @param mixed $value The value to set at `$key`.
*
* @return mixed|null the previous value associated with key, or `null` if
* there was no mapping for `$key`.
*/
public function replace($key, $value)
{
$currentValue = $this->get($key);
if ($this->containsKey($key)) {
$this[$key] = $value;
}
return $currentValue;
}
/**
* Replaces the entry for the specified key only if currently mapped to the
* specified value.
*
* This performs a strict type check on the value.
*
* @param mixed $key The key to remove from the map.
* @param mixed $oldValue The value to match.
* @param mixed $newValue The value to use as a replacement.
*
* @return bool true if the value was replaced.
*/
public function replaceIf($key, $oldValue, $newValue): bool
{
if ($this->get($key) === $oldValue) {
$this[$key] = $newValue;
return true;
}
return false;
}
}

View File

@@ -0,0 +1,57 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection\Map;
use Ramsey\Collection\Exception\InvalidArgumentException;
use Ramsey\Collection\Tool\TypeTrait;
use Ramsey\Collection\Tool\ValueToStringTrait;
/**
* This class provides a basic implementation of `TypedMapInterface`, to
* minimize the effort required to implement this interface.
*/
abstract class AbstractTypedMap extends AbstractMap implements TypedMapInterface
{
use TypeTrait;
use ValueToStringTrait;
/**
* Sets the given value to the given offset in the map.
*
* @param mixed $offset The offset to set.
* @param mixed $value The value to set at the given offset.
*
* @throws InvalidArgumentException if the offset or value do not match the
* expected types.
*/
public function offsetSet($offset, $value): void
{
if ($this->checkType($this->getKeyType(), $offset) === false) {
throw new InvalidArgumentException(
'Key must be of type ' . $this->getKeyType() . '; key is '
. $this->toolValueToString($offset)
);
}
if ($this->checkType($this->getValueType(), $value) === false) {
throw new InvalidArgumentException(
'Value must be of type ' . $this->getValueType() . '; value is '
. $this->toolValueToString($value)
);
}
parent::offsetSet($offset, $value);
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection\Map;
/**
* `AssociativeArrayMap` represents a standard associative array object.
*/
class AssociativeArrayMap extends AbstractMap
{
}

View File

@@ -0,0 +1,138 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection\Map;
use Ramsey\Collection\ArrayInterface;
/**
* An object that maps keys to values.
*
* A map cannot contain duplicate keys; each key can map to at most one value.
*/
interface MapInterface extends ArrayInterface
{
/**
* Returns `true` if this map contains a mapping for the specified key.
*
* @param mixed $key The key to check in the map.
*/
public function containsKey($key): bool;
/**
* Returns `true` if this map maps one or more keys to the specified value.
*
* This performs a strict type check on the value.
*
* @param mixed $value The value to check in the map.
*/
public function containsValue($value): bool;
/**
* Return an array of the keys contained in this map.
*
* @return mixed[]
*/
public function keys(): array;
/**
* Returns the value to which the specified key is mapped, `null` if this
* map contains no mapping for the key, or (optionally) `$defaultValue` if
* this map contains no mapping for the key.
*
* @param mixed $key The key to return from the map.
* @param mixed $defaultValue The default value to use if `$key` is not found.
*
* @return mixed|null the value or `null` if the key could not be found.
*/
public function get($key, $defaultValue = null);
/**
* Associates the specified value with the specified key in this map.
*
* If the map previously contained a mapping for the key, the old value is
* replaced by the specified value.
*
* @param mixed $key The key to put or replace in the map.
* @param mixed $value The value to store at `$key`.
*
* @return mixed|null the previous value associated with key, or `null` if
* there was no mapping for `$key`.
*/
public function put($key, $value);
/**
* Associates the specified value with the specified key in this map only if
* it is not already set.
*
* If there is already a value associated with `$key`, this returns that
* value without replacing it.
*
* @param mixed $key The key to put in the map.
* @param mixed $value The value to store at `$key`.
*
* @return mixed|null the previous value associated with key, or `null` if
* there was no mapping for `$key`.
*/
public function putIfAbsent($key, $value);
/**
* Removes the mapping for a key from this map if it is present.
*
* @param mixed $key The key to remove from the map.
*
* @return mixed|null the previous value associated with key, or `null` if
* there was no mapping for `$key`.
*/
public function remove($key);
/**
* Removes the entry for the specified key only if it is currently mapped to
* the specified value.
*
* This performs a strict type check on the value.
*
* @param mixed $key The key to remove from the map.
* @param mixed $value The value to match.
*
* @return bool true if the value was removed.
*/
public function removeIf($key, $value): bool;
/**
* Replaces the entry for the specified key only if it is currently mapped
* to some value.
*
* @param mixed $key The key to replace.
* @param mixed $value The value to set at `$key`.
*
* @return mixed|null the previous value associated with key, or `null` if
* there was no mapping for `$key`.
*/
public function replace($key, $value);
/**
* Replaces the entry for the specified key only if currently mapped to the
* specified value.
*
* This performs a strict type check on the value.
*
* @param mixed $key The key to remove from the map.
* @param mixed $oldValue The value to match.
* @param mixed $newValue The value to use as a replacement.
*
* @return bool true if the value was replaced.
*/
public function replaceIf($key, $oldValue, $newValue): bool;
}

View File

@@ -0,0 +1,118 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection\Map;
use Ramsey\Collection\Exception\InvalidArgumentException;
use Ramsey\Collection\Tool\TypeTrait;
use Ramsey\Collection\Tool\ValueToStringTrait;
use function array_combine;
use function array_key_exists;
use function is_int;
/**
* `NamedParameterMap` represents a mapping of values to a set of named keys
* that may optionally be typed
*/
class NamedParameterMap extends AbstractMap
{
use TypeTrait;
use ValueToStringTrait;
/**
* Named parameters defined for this map.
*
* @var array<mixed, string>
*/
protected $namedParameters;
/**
* Constructs a new `NamedParameterMap`.
*
* @param array<mixed, string> $namedParameters The named parameters defined for this map.
* @param mixed[] $data An initial set of data to set on this map.
*/
public function __construct(array $namedParameters, array $data = [])
{
$this->namedParameters = $this->filterNamedParameters($namedParameters);
parent::__construct($data);
}
/**
* Returns named parameters set for this `NamedParameterMap`.
*
* @return array<mixed, string>
*/
public function getNamedParameters(): array
{
return $this->namedParameters;
}
/**
* Sets the given value to the given offset in the map.
*
* @param mixed $offset The offset to set.
* @param mixed $value The value to set at the given offset.
*
* @throws InvalidArgumentException if the offset provided is not a
* defined named parameter, or if the value is not of the type defined
* for the given named parameter.
*/
public function offsetSet($offset, $value): void
{
if (!array_key_exists($offset, $this->namedParameters)) {
throw new InvalidArgumentException(
'Attempting to set value for unconfigured parameter \''
. $offset . '\''
);
}
if ($this->checkType($this->namedParameters[$offset], $value) === false) {
throw new InvalidArgumentException(
'Value for \'' . $offset . '\' must be of type '
. $this->namedParameters[$offset] . '; value is '
. $this->toolValueToString($value)
);
}
$this->data[$offset] = $value;
}
/**
* Given an array of named parameters, constructs a proper mapping of
* named parameters to types.
*
* @param array<mixed, string> $namedParameters The named parameters to filter.
*
* @return array<mixed, string>
*/
protected function filterNamedParameters(array $namedParameters): array
{
$names = [];
$types = [];
foreach ($namedParameters as $key => $value) {
if (is_int($key)) {
$names[] = (string) $value;
$types[] = 'mixed';
} else {
$names[] = $key;
$types[] = (string) $value;
}
}
return array_combine($names, $types) ?: [];
}
}

View File

@@ -0,0 +1,137 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection\Map;
use Ramsey\Collection\Tool\TypeTrait;
/**
* A `TypedMap` represents a map of elements where key and value are typed.
*
* Each element is identified by a key with defined type and a value of defined
* type. The keys of the map must be unique. The values on the map can be=
* repeated but each with its own different key.
*
* The most common case is to use a string type key, but it's not limited to
* this type of keys.
*
* This is a direct implementation of `TypedMapInterface`, provided for the sake
* of convenience.
*
* Example usage:
*
* ```php
* $map = new TypedMap('string', Foo::class);
* $map['x'] = new Foo();
* foreach ($map as $key => $value) {
* // do something with $key, it will be a Foo::class
* }
*
* // this will throw an exception since key must be string
* $map[10] = new Foo();
*
* // this will throw an exception since value must be a Foo
* $map['bar'] = 'bar';
*
* // initialize map with contents
* $map = new TypedMap('string', Foo::class, [
* new Foo(), new Foo(), new Foo()
* ]);
* ```
*
* It is preferable to subclass `AbstractTypedMap` to create your own typed map
* implementation:
*
* ```php
* class FooTypedMap extends AbstractTypedMap
* {
* public function getKeyType()
* {
* return 'int';
* }
*
* public function getValueType()
* {
* return Foo::class;
* }
* }
* ```
*
* … but you also may use the `TypedMap` class:
*
* ```php
* class FooTypedMap extends TypedMap
* {
* public function __constructor(array $data = [])
* {
* parent::__construct('int', Foo::class, $data);
* }
* }
* ```
*/
class TypedMap extends AbstractTypedMap
{
use TypeTrait;
/**
* The data type of keys stored in this collection.
*
* A map key's type is immutable once it is set. For this reason, this
* property is set private.
*
* @var string data type of the map key.
*/
private $keyType;
/**
* The data type of values stored in this collection.
*
* A map values's type is immutable once it is set. For this reason, this
* property is set private.
*
* @var string data type of the map value.
*/
private $valueType;
/**
* Constructs a map object of the specified key and value types,
* optionally with the specified data.
*
* @param string $keyType The data type of the map's keys.
* @param string $valueType The data type of the map's values.
* @param mixed[] $data The initial data to set for this map.
*/
public function __construct(string $keyType, string $valueType, array $data = [])
{
$this->keyType = $keyType;
$this->valueType = $valueType;
parent::__construct($data);
}
/**
* Return the type used on the key.
*/
public function getKeyType(): string
{
return $this->keyType;
}
/**
* Return the type forced on the values.
*/
public function getValueType(): string
{
return $this->valueType;
}
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection\Map;
/**
* A `TypedMapInterface` represents a map of elements where key and value are
* typed.
*/
interface TypedMapInterface extends MapInterface
{
/**
* Return the type used on the key.
*/
public function getKeyType(): string;
/**
* Return the type forced on the values.
*/
public function getValueType(): string;
}

226
vendor/ramsey/collection/src/Queue.php vendored Normal file
View File

@@ -0,0 +1,226 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection;
use Ramsey\Collection\Exception\InvalidArgumentException;
use Ramsey\Collection\Exception\NoSuchElementException;
use Ramsey\Collection\Tool\TypeTrait;
use Ramsey\Collection\Tool\ValueToStringTrait;
/**
* This class provides a basic implementation of `QueueInterface`, to minimize
* the effort required to implement this interface.
*/
class Queue extends AbstractArray implements QueueInterface
{
use TypeTrait;
use ValueToStringTrait;
/**
* The type of elements stored in this queue.
*
* A queue's type is immutable once it is set. For this reason, this
* property is set private.
*
* @var string
*/
private $queueType;
/**
* The index of the head of the queue.
*
* @var int
*/
protected $index = 0;
/**
* Constructs a queue object of the specified type, optionally with the
* specified data.
*
* @param string $queueType The type (FQCN) associated with this queue.
* @param mixed[] $data The initial items to store in the collection.
*/
public function __construct(string $queueType, array $data = [])
{
$this->queueType = $queueType;
parent::__construct($data);
}
/**
* Sets the given value to the given offset in the queue.
*
* Since arbitrary offsets may not be manipulated in a queue, this method
* serves only to fulfill the `ArrayAccess` interface requirements. It is
* invoked by other operations when adding values to the queue.
*
* @link http://php.net/manual/en/arrayaccess.offsetset.php ArrayAccess::offsetSet()
*
* @param mixed|null $offset The offset is ignored and is treated as `null`.
* @param mixed $value The value to set at the given offset.
*
* @throws InvalidArgumentException when the value does not match the
* specified type for this queue.
*/
public function offsetSet($offset, $value): void
{
if ($this->checkType($this->getType(), $value) === false) {
throw new InvalidArgumentException(
'Value must be of type ' . $this->getType() . '; value is '
. $this->toolValueToString($value)
);
}
$this->data[] = $value;
}
/**
* Ensures that this queue contains the specified element.
*
* This method differs from `offer()` only in that it throws an exception if
* it cannot add the element to the queue.
*
* @see self::offer()
*
* @param mixed $element The element to add to this queue.
*
* @return bool `true` if this queue changed as a result of the call.
*
* @throws InvalidArgumentException when the element does not match the
* specified type for this queue.
*/
public function add($element): bool
{
$this[] = $element;
return true;
}
/**
* Retrieves, but does not remove, the head of this queue.
*
* This method differs from `peek()` only in that it throws an exception if
* this queue is empty.
*
* @see self::peek()
*
* @return mixed the head of this queue.
*
* @throws NoSuchElementException if this queue is empty.
*/
public function element()
{
if ($this->count() === 0) {
throw new NoSuchElementException(
'Can\'t return element from Queue. Queue is empty.'
);
}
return $this[$this->index];
}
/**
* Inserts the specified element into this queue.
*
* This method differs from `add()` only in that it does not throw an
* exception if it cannot add the element to the queue.
*
* @see self::add()
*
* @param mixed $element The element to add to this queue.
*
* @return bool `true` if the element was added to this queue, else `false`.
*/
public function offer($element): bool
{
try {
return $this->add($element);
} catch (InvalidArgumentException $e) {
return false;
}
}
/**
* Retrieves, but does not remove, the head of this queue, or returns `null`
* if this queue is empty.
*
* @see self::element()
*
* @return mixed|null the head of this queue, or `null` if this queue is empty.
*/
public function peek()
{
if ($this->count() === 0) {
return null;
}
return $this[$this->index];
}
/**
* Retrieves and removes the head of this queue, or returns `null`
* if this queue is empty.
*
* @see self::remove()
*
* @return mixed|null the head of this queue, or `null` if this queue is empty.
*/
public function poll()
{
if ($this->count() === 0) {
return null;
}
$head = $this[$this->index];
unset($this[$this->index]);
$this->index++;
return $head;
}
/**
* Retrieves and removes the head of this queue.
*
* This method differs from `poll()` only in that it throws an exception if
* this queue is empty.
*
* @see self::poll()
*
* @return mixed the head of this queue.
*
* @throws NoSuchElementException if this queue is empty.
*/
public function remove()
{
if ($this->count() === 0) {
throw new NoSuchElementException('Can\'t return element from Queue. Queue is empty.');
}
$head = $this[$this->index];
unset($this[$this->index]);
$this->index++;
return $head;
}
/**
* Returns the type associated with this queue.
*/
public function getType(): string
{
return $this->queueType;
}
}

View File

@@ -0,0 +1,198 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection;
use Ramsey\Collection\Exception\NoSuchElementException;
/**
* A queue is a collection in which the entities in the collection are kept in
* order.
*
* The principal operations on the queue are the addition of entities to the end
* (tail), also known as *enqueue*, and removal of entities from the front
* (head), also known as *dequeue*. This makes the queue a first-in-first-out
* (FIFO) data structure.
*
* Besides basic array operations, queues provide additional insertion,
* extraction, and inspection operations. Each of these methods exists in two
* forms: one throws an exception if the operation fails, the other returns a
* special value (either `null` or `false`, depending on the operation). The
* latter form of the insert operation is designed specifically for use with
* capacity-restricted `QueueInterface` implementations; in most
* implementations, insert operations cannot fail.
*
* <table>
* <caption>Summary of QueueInterface methods</caption>
* <thead>
* <tr>
* <td></td>
* <td><em>Throws exception</em></td>
* <td><em>Returns special value</em></td>
* </tr>
* </thead>
* <tbody>
* <tr>
* <th>Insert</th>
* <td><code>add()</code></td>
* <td><code>offer()</code></td>
* </tr>
* <tr>
* <th>Remove</th>
* <td><code>remove()</code></td>
* <td><code>poll()</code></td>
* </tr>
* <tr>
* <th>Examine</th>
* <td><code>element()</code></td>
* <td><code>peek()</code></td>
* </tr>
* </tbody>
* </table>
*
* Queues typically, but do not necessarily, order elements in a FIFO
* (first-in-first-out) manner. Among the exceptions are priority queues, which
* order elements according to a supplied comparator, or the elements' natural
* ordering, and LIFO queues (or stacks) which order the elements LIFO
* (last-in-first-out). Whatever the ordering used, the head of the queue is
* that element which would be removed by a call to remove() or poll(). In a
* FIFO queue, all new elements are inserted at the tail of the queue. Other
* kinds of queues may use different placement rules. Every `QueueInterface`
* implementation must specify its ordering properties.
*
* The `offer()` method inserts an element if possible, otherwise returning
* `false`. This differs from the `add()` method, which can fail to add an
* element only by throwing an unchecked exception. The `offer()` method is
* designed for use when failure is a normal, rather than exceptional
* occurrence, for example, in fixed-capacity (or "bounded") queues.
*
* The `remove()` and `poll()` methods remove and return the head of the queue.
* Exactly which element is removed from the queue is a function of the queue's
* ordering policy, which differs from implementation to implementation. The
* `remove()` and `poll()` methods differ only in their behavior when the queue
* is empty: the `remove()` method throws an exception, while the `poll()`
* method returns `null`.
*
* The `element()` and `peek()` methods return, but do not remove, the head of
* the queue.
*
* `QueueInterface` implementations generally do not allow insertion of `null`
* elements, although some implementations do not prohibit insertion of `null`.
* Even in the implementations that permit it, `null` should not be inserted
* into a queue, as `null` is also used as a special return value by the
* `poll()` method to indicate that the queue contains no elements.
*/
interface QueueInterface extends ArrayInterface
{
/**
* Ensures that this queue contains the specified element (optional
* operation).
*
* Returns `true` if this queue changed as a result of the call. (Returns
* `false` if this queue does not permit duplicates and already contains the
* specified element.)
*
* Queues that support this operation may place limitations on what elements
* may be added to this queue. In particular, some queues will refuse to add
* `null` elements, and others will impose restrictions on the type of
* elements that may be added. Queue classes should clearly specify in their
* documentation any restrictions on what elements may be added.
*
* If a queue refuses to add a particular element for any reason other than
* that it already contains the element, it must throw an exception (rather
* than returning `false`). This preserves the invariant that a queue always
* contains the specified element after this call returns.
*
* @see self::offer()
*
* @param mixed $element The element to add to this queue.
*
* @return bool `true` if this queue changed as a result of the call.
*
* @throws \RuntimeException if a queue refuses to add a particular element
* for any reason other than that it already contains the element.
* Implementations should use a more-specific exception that extends
* `\RuntimeException`.
*/
public function add($element): bool;
/**
* Retrieves, but does not remove, the head of this queue.
*
* This method differs from `peek()` only in that it throws an exception if
* this queue is empty.
*
* @see self::peek()
*
* @return mixed the head of this queue.
*
* @throws NoSuchElementException if this queue is empty.
*/
public function element();
/**
* Inserts the specified element into this queue if it is possible to do so
* immediately without violating capacity restrictions.
*
* When using a capacity-restricted queue, this method is generally
* preferable to `add()`, which can fail to insert an element only by
* throwing an exception.
*
* @see self::add()
*
* @param mixed $element The element to add to this queue.
*
* @return bool `true` if the element was added to this queue, else `false`.
*/
public function offer($element): bool;
/**
* Retrieves, but does not remove, the head of this queue, or returns `null`
* if this queue is empty.
*
* @see self::element()
*
* @return mixed|null the head of this queue, or `null` if this queue is empty.
*/
public function peek();
/**
* Retrieves and removes the head of this queue, or returns `null`
* if this queue is empty.
*
* @see self::remove()
*
* @return mixed|null the head of this queue, or `null` if this queue is empty.
*/
public function poll();
/**
* Retrieves and removes the head of this queue.
*
* This method differs from `poll()` only in that it throws an exception if
* this queue is empty.
*
* @see self::poll()
*
* @return mixed the head of this queue.
*
* @throws NoSuchElementException if this queue is empty.
*/
public function remove();
/**
* Returns the type associated with this queue.
*/
public function getType(): string;
}

69
vendor/ramsey/collection/src/Set.php vendored Normal file
View File

@@ -0,0 +1,69 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection;
/**
* A set is a collection that contains no duplicate elements.
*
* Great care must be exercised if mutable objects are used as set elements.
* The behavior of a set is not specified if the value of an object is changed
* in a manner that affects equals comparisons while the object is an element in
* the set.
*
* Example usage:
*
* ``` php
* $foo = new \My\Foo();
* $set = new Set(\My\Foo::class);
*
* $set->add($foo); // returns TRUE, the element don't exists
* $set->add($foo); // returns FALSE, the element already exists
*
* $bar = new \My\Foo();
* $set->add($bar); // returns TRUE, $bar !== $foo
* ```
*/
class Set extends AbstractSet
{
/**
* The type of elements stored in this set
*
* A set's type is immutable. For this reason, this property is private.
*
* @var string
*/
private $setType;
/**
* Constructs a set object of the specified type, optionally with the
* specified data.
*
* @param string $setType The type (FQCN) associated with this set.
* @param mixed[] $data The initial items to store in the set.
*/
public function __construct(string $setType, array $data = [])
{
$this->setType = $setType;
parent::__construct($data);
}
/**
* Returns the type associated with this set.
*/
public function getType(): string
{
return $this->setType;
}
}

View File

@@ -0,0 +1,73 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection\Tool;
use function is_array;
use function is_bool;
use function is_callable;
use function is_float;
use function is_int;
use function is_numeric;
use function is_object;
use function is_resource;
use function is_scalar;
use function is_string;
/**
* Provides functionality to check values for specific types.
*/
trait TypeTrait
{
/**
* Returns `true` if value is of the specified type.
*
* @param string $type The type to check the value against.
* @param mixed $value The value to check.
*/
protected function checkType(string $type, $value): bool
{
switch ($type) {
case 'array':
return is_array($value);
case 'bool':
case 'boolean':
return is_bool($value);
case 'callable':
return is_callable($value);
case 'float':
case 'double':
return is_float($value);
case 'int':
case 'integer':
return is_int($value);
case 'null':
return $value === null;
case 'numeric':
return is_numeric($value);
case 'object':
return is_object($value);
case 'resource':
return is_resource($value);
case 'scalar':
return is_scalar($value);
case 'string':
return is_string($value);
case 'mixed':
return true;
default:
return $value instanceof $type;
}
}
}

View File

@@ -0,0 +1,54 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection\Tool;
use Ramsey\Collection\Exception\ValueExtractionException;
use function get_class;
use function method_exists;
use function property_exists;
use function sprintf;
/**
* Provides functionality to extract the value of a property or method from an object.
*/
trait ValueExtractorTrait
{
/**
* Extracts the value of the given property or method from the object.
*
* @param object $object The object to extract the value from.
* @param string $propertyOrMethod The property or method for which the
* value should be extracted.
*
* @return mixed the value extracted from the specified property or method.
*
* @throws ValueExtractionException if the method or property is not defined.
*/
protected function extractValue(object $object, string $propertyOrMethod)
{
if (property_exists($object, $propertyOrMethod)) {
return $object->$propertyOrMethod;
}
if (method_exists($object, $propertyOrMethod)) {
return $object->{$propertyOrMethod}();
}
throw new ValueExtractionException(
sprintf('Method or property "%s" not defined in %s', $propertyOrMethod, get_class($object))
);
}
}

View File

@@ -0,0 +1,89 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection\Tool;
use DateTimeInterface;
use function get_class;
use function get_resource_type;
use function is_array;
use function is_bool;
use function is_callable;
use function is_resource;
use function is_scalar;
/**
* Provides functionality to express a value as string
*/
trait ValueToStringTrait
{
/**
* Returns a string representation of the value.
*
* - null value: `'NULL'`
* - boolean: `'TRUE'`, `'FALSE'`
* - array: `'Array'`
* - scalar: converted-value
* - resource: `'(type resource #number)'`
* - object with `__toString()`: result of `__toString()`
* - object DateTime: ISO 8601 date
* - object: `'(className Object)'`
* - anonymous function: same as object
*
* @param mixed $value the value to return as a string.
*/
protected function toolValueToString($value): string
{
// null
if ($value === null) {
return 'NULL';
}
// boolean constants
if (is_bool($value)) {
return $value ? 'TRUE' : 'FALSE';
}
// array
if (is_array($value)) {
return 'Array';
}
// scalar types (integer, float, string)
if (is_scalar($value)) {
return (string) $value;
}
// resource
if (is_resource($value)) {
return '(' . get_resource_type($value) . ' resource #' . (int) $value . ')';
}
// after this line $value is an object since is not null, scalar, array or resource
// __toString() is implemented
if (is_callable([$value, '__toString'])) {
return (string) $value->__toString();
}
// object of type \DateTime
if ($value instanceof DateTimeInterface) {
return $value->format('c');
}
// unknown type
return '(' . get_class($value) . ' Object)';
}
}