summaryrefslogtreecommitdiffstats
path: root/vendor/doctrine/collections/lib/Doctrine
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/doctrine/collections/lib/Doctrine')
-rw-r--r--vendor/doctrine/collections/lib/Doctrine/Common/Collections/AbstractLazyCollection.php389
-rw-r--r--vendor/doctrine/collections/lib/Doctrine/Common/Collections/ArrayCollection.php466
-rw-r--r--vendor/doctrine/collections/lib/Doctrine/Common/Collections/Collection.php99
-rw-r--r--vendor/doctrine/collections/lib/Doctrine/Common/Collections/Criteria.php245
-rw-r--r--vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php269
-rw-r--r--vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Comparison.php74
-rw-r--r--vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php67
-rw-r--r--vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Expression.php12
-rw-r--r--vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ExpressionVisitor.php59
-rw-r--r--vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Value.php29
-rw-r--r--vendor/doctrine/collections/lib/Doctrine/Common/Collections/ExpressionBuilder.php181
-rw-r--r--vendor/doctrine/collections/lib/Doctrine/Common/Collections/ReadableCollection.php213
-rw-r--r--vendor/doctrine/collections/lib/Doctrine/Common/Collections/Selectable.php30
13 files changed, 2133 insertions, 0 deletions
diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/AbstractLazyCollection.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/AbstractLazyCollection.php
new file mode 100644
index 0000000..baab4d5
--- /dev/null
+++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/AbstractLazyCollection.php
@@ -0,0 +1,389 @@
+<?php
+
+namespace Doctrine\Common\Collections;
+
+use Closure;
+use LogicException;
+use ReturnTypeWillChange;
+use Traversable;
+
+/**
+ * Lazy collection that is backed by a concrete collection
+ *
+ * @psalm-template TKey of array-key
+ * @psalm-template T
+ * @template-implements Collection<TKey,T>
+ */
+abstract class AbstractLazyCollection implements Collection
+{
+ /**
+ * The backed collection to use
+ *
+ * @psalm-var Collection<TKey,T>|null
+ * @var Collection<mixed>|null
+ */
+ protected $collection;
+
+ /** @var bool */
+ protected $initialized = false;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return int
+ */
+ #[ReturnTypeWillChange]
+ public function count()
+ {
+ $this->initialize();
+
+ return $this->collection->count();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function add($element)
+ {
+ $this->initialize();
+
+ return $this->collection->add($element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clear()
+ {
+ $this->initialize();
+ $this->collection->clear();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @template TMaybeContained
+ */
+ public function contains($element)
+ {
+ $this->initialize();
+
+ return $this->collection->contains($element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function isEmpty()
+ {
+ $this->initialize();
+
+ return $this->collection->isEmpty();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function remove($key)
+ {
+ $this->initialize();
+
+ return $this->collection->remove($key);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function removeElement($element)
+ {
+ $this->initialize();
+
+ return $this->collection->removeElement($element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function containsKey($key)
+ {
+ $this->initialize();
+
+ return $this->collection->containsKey($key);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function get($key)
+ {
+ $this->initialize();
+
+ return $this->collection->get($key);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getKeys()
+ {
+ $this->initialize();
+
+ return $this->collection->getKeys();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getValues()
+ {
+ $this->initialize();
+
+ return $this->collection->getValues();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function set($key, $value)
+ {
+ $this->initialize();
+ $this->collection->set($key, $value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function toArray()
+ {
+ $this->initialize();
+
+ return $this->collection->toArray();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function first()
+ {
+ $this->initialize();
+
+ return $this->collection->first();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function last()
+ {
+ $this->initialize();
+
+ return $this->collection->last();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function key()
+ {
+ $this->initialize();
+
+ return $this->collection->key();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function current()
+ {
+ $this->initialize();
+
+ return $this->collection->current();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function next()
+ {
+ $this->initialize();
+
+ return $this->collection->next();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function exists(Closure $p)
+ {
+ $this->initialize();
+
+ return $this->collection->exists($p);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function filter(Closure $p)
+ {
+ $this->initialize();
+
+ return $this->collection->filter($p);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function forAll(Closure $p)
+ {
+ $this->initialize();
+
+ return $this->collection->forAll($p);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function map(Closure $func)
+ {
+ $this->initialize();
+
+ return $this->collection->map($func);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function partition(Closure $p)
+ {
+ $this->initialize();
+
+ return $this->collection->partition($p);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @template TMaybeContained
+ */
+ public function indexOf($element)
+ {
+ $this->initialize();
+
+ return $this->collection->indexOf($element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function slice($offset, $length = null)
+ {
+ $this->initialize();
+
+ return $this->collection->slice($offset, $length);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return Traversable<int|string, mixed>
+ * @psalm-return Traversable<TKey,T>
+ */
+ #[ReturnTypeWillChange]
+ public function getIterator()
+ {
+ $this->initialize();
+
+ return $this->collection->getIterator();
+ }
+
+ /**
+ * @param TKey $offset
+ *
+ * @return bool
+ */
+ #[ReturnTypeWillChange]
+ public function offsetExists($offset)
+ {
+ $this->initialize();
+
+ return $this->collection->offsetExists($offset);
+ }
+
+ /**
+ * @param TKey $offset
+ *
+ * @return mixed
+ */
+ #[ReturnTypeWillChange]
+ public function offsetGet($offset)
+ {
+ $this->initialize();
+
+ return $this->collection->offsetGet($offset);
+ }
+
+ /**
+ * @param TKey|null $offset
+ * @param T $value
+ *
+ * @return void
+ */
+ #[ReturnTypeWillChange]
+ public function offsetSet($offset, $value)
+ {
+ $this->initialize();
+ $this->collection->offsetSet($offset, $value);
+ }
+
+ /**
+ * @param TKey $offset
+ *
+ * @return void
+ */
+ #[ReturnTypeWillChange]
+ public function offsetUnset($offset)
+ {
+ $this->initialize();
+ $this->collection->offsetUnset($offset);
+ }
+
+ /**
+ * Is the lazy collection already initialized?
+ *
+ * @return bool
+ *
+ * @psalm-assert-if-true Collection<TKey,T> $this->collection
+ */
+ public function isInitialized()
+ {
+ return $this->initialized;
+ }
+
+ /**
+ * Initialize the collection
+ *
+ * @return void
+ *
+ * @psalm-assert Collection<TKey,T> $this->collection
+ */
+ protected function initialize()
+ {
+ if ($this->initialized) {
+ return;
+ }
+
+ $this->doInitialize();
+ $this->initialized = true;
+
+ if ($this->collection === null) {
+ throw new LogicException('You must initialize the collection property in the doInitialize() method.');
+ }
+ }
+
+ /**
+ * Do the initialization logic
+ *
+ * @return void
+ */
+ abstract protected function doInitialize();
+}
diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ArrayCollection.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ArrayCollection.php
new file mode 100644
index 0000000..186f6ec
--- /dev/null
+++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ArrayCollection.php
@@ -0,0 +1,466 @@
+<?php
+
+namespace Doctrine\Common\Collections;
+
+use ArrayIterator;
+use Closure;
+use Doctrine\Common\Collections\Expr\ClosureExpressionVisitor;
+use ReturnTypeWillChange;
+use Traversable;
+
+use function array_filter;
+use function array_key_exists;
+use function array_keys;
+use function array_map;
+use function array_reverse;
+use function array_search;
+use function array_slice;
+use function array_values;
+use function count;
+use function current;
+use function end;
+use function in_array;
+use function key;
+use function next;
+use function reset;
+use function spl_object_hash;
+use function uasort;
+
+use const ARRAY_FILTER_USE_BOTH;
+
+/**
+ * An ArrayCollection is a Collection implementation that wraps a regular PHP array.
+ *
+ * Warning: Using (un-)serialize() on a collection is not a supported use-case
+ * and may break when we change the internals in the future. If you need to
+ * serialize a collection use {@link toArray()} and reconstruct the collection
+ * manually.
+ *
+ * @psalm-template TKey of array-key
+ * @psalm-template T
+ * @template-implements Collection<TKey,T>
+ * @template-implements Selectable<TKey,T>
+ * @psalm-consistent-constructor
+ */
+class ArrayCollection implements Collection, Selectable
+{
+ /**
+ * An array containing the entries of this collection.
+ *
+ * @psalm-var array<TKey,T>
+ * @var mixed[]
+ */
+ private $elements;
+
+ /**
+ * Initializes a new ArrayCollection.
+ *
+ * @param array $elements
+ * @psalm-param array<TKey,T> $elements
+ */
+ public function __construct(array $elements = [])
+ {
+ $this->elements = $elements;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function toArray()
+ {
+ return $this->elements;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function first()
+ {
+ return reset($this->elements);
+ }
+
+ /**
+ * Creates a new instance from the specified elements.
+ *
+ * This method is provided for derived classes to specify how a new
+ * instance should be created when constructor semantics have changed.
+ *
+ * @param array $elements Elements.
+ * @psalm-param array<K,V> $elements
+ *
+ * @return static
+ * @psalm-return static<K,V>
+ *
+ * @psalm-template K of array-key
+ * @psalm-template V
+ */
+ protected function createFrom(array $elements)
+ {
+ return new static($elements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function last()
+ {
+ return end($this->elements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function key()
+ {
+ return key($this->elements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function next()
+ {
+ return next($this->elements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function current()
+ {
+ return current($this->elements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function remove($key)
+ {
+ if (! isset($this->elements[$key]) && ! array_key_exists($key, $this->elements)) {
+ return null;
+ }
+
+ $removed = $this->elements[$key];
+ unset($this->elements[$key]);
+
+ return $removed;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function removeElement($element)
+ {
+ $key = array_search($element, $this->elements, true);
+
+ if ($key === false) {
+ return false;
+ }
+
+ unset($this->elements[$key]);
+
+ return true;
+ }
+
+ /**
+ * Required by interface ArrayAccess.
+ *
+ * @param TKey $offset
+ *
+ * @return bool
+ */
+ #[ReturnTypeWillChange]
+ public function offsetExists($offset)
+ {
+ return $this->containsKey($offset);
+ }
+
+ /**
+ * Required by interface ArrayAccess.
+ *
+ * @param TKey $offset
+ *
+ * @return mixed
+ */
+ #[ReturnTypeWillChange]
+ public function offsetGet($offset)
+ {
+ return $this->get($offset);
+ }
+
+ /**
+ * Required by interface ArrayAccess.
+ *
+ * @param TKey|null $offset
+ * @param T $value
+ *
+ * @return void
+ */
+ #[ReturnTypeWillChange]
+ public function offsetSet($offset, $value)
+ {
+ if (! isset($offset)) {
+ $this->add($value);
+
+ return;
+ }
+
+ $this->set($offset, $value);
+ }
+
+ /**
+ * Required by interface ArrayAccess.
+ *
+ * @param TKey $offset
+ *
+ * @return void
+ */
+ #[ReturnTypeWillChange]
+ public function offsetUnset($offset)
+ {
+ $this->remove($offset);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function containsKey($key)
+ {
+ return isset($this->elements[$key]) || array_key_exists($key, $this->elements);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @template TMaybeContained
+ */
+ public function contains($element)
+ {
+ return in_array($element, $this->elements, true);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function exists(Closure $p)
+ {
+ foreach ($this->elements as $key => $element) {
+ if ($p($key, $element)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @psalm-param TMaybeContained $element
+ *
+ * @psalm-return (TMaybeContained is T ? TKey|false : false)
+ *
+ * @template TMaybeContained
+ */
+ public function indexOf($element)
+ {
+ return array_search($element, $this->elements, true);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function get($key)
+ {
+ return $this->elements[$key] ?? null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getKeys()
+ {
+ return array_keys($this->elements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getValues()
+ {
+ return array_values($this->elements);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return int
+ */
+ #[ReturnTypeWillChange]
+ public function count()
+ {
+ return count($this->elements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function set($key, $value)
+ {
+ $this->elements[$key] = $value;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @psalm-suppress InvalidPropertyAssignmentValue
+ *
+ * This breaks assumptions about the template type, but it would
+ * be a backwards-incompatible change to remove this method
+ */
+ public function add($element)
+ {
+ $this->elements[] = $element;
+
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function isEmpty()
+ {
+ return empty($this->elements);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return Traversable<int|string, mixed>
+ * @psalm-return Traversable<TKey,T>
+ */
+ #[ReturnTypeWillChange]
+ public function getIterator()
+ {
+ return new ArrayIterator($this->elements);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @psalm-param Closure(T):U $func
+ *
+ * @return static
+ * @psalm-return static<TKey, U>
+ *
+ * @psalm-template U
+ */
+ public function map(Closure $func)
+ {
+ return $this->createFrom(array_map($func, $this->elements));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return static
+ * @psalm-return static<TKey,T>
+ */
+ public function filter(Closure $p)
+ {
+ return $this->createFrom(array_filter($this->elements, $p, ARRAY_FILTER_USE_BOTH));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function forAll(Closure $p)
+ {
+ foreach ($this->elements as $key => $element) {
+ if (! $p($key, $element)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function partition(Closure $p)
+ {
+ $matches = $noMatches = [];
+
+ foreach ($this->elements as $key => $element) {
+ if ($p($key, $element)) {
+ $matches[$key] = $element;
+ } else {
+ $noMatches[$key] = $element;
+ }
+ }
+
+ return [$this->createFrom($matches), $this->createFrom($noMatches)];
+ }
+
+ /**
+ * Returns a string representation of this object.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return self::class . '@' . spl_object_hash($this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clear()
+ {
+ $this->elements = [];
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function slice($offset, $length = null)
+ {
+ return array_slice($this->elements, $offset, $length, true);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function matching(Criteria $criteria)
+ {
+ $expr = $criteria->getWhereExpression();
+ $filtered = $this->elements;
+
+ if ($expr) {
+ $visitor = new ClosureExpressionVisitor();
+ $filter = $visitor->dispatch($expr);
+ $filtered = array_filter($filtered, $filter);
+ }
+
+ $orderings = $criteria->getOrderings();
+
+ if ($orderings) {
+ $next = null;
+ foreach (array_reverse($orderings) as $field => $ordering) {
+ $next = ClosureExpressionVisitor::sortByField($field, $ordering === Criteria::DESC ? -1 : 1, $next);
+ }
+
+ uasort($filtered, $next);
+ }
+
+ $offset = $criteria->getFirstResult();
+ $length = $criteria->getMaxResults();
+
+ if ($offset || $length) {
+ $filtered = array_slice($filtered, (int) $offset, $length);
+ }
+
+ return $this->createFrom($filtered);
+ }
+}
diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Collection.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Collection.php
new file mode 100644
index 0000000..fb09192
--- /dev/null
+++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Collection.php
@@ -0,0 +1,99 @@
+<?php
+
+namespace Doctrine\Common\Collections;
+
+use ArrayAccess;
+use Closure;
+
+/**
+ * The missing (SPL) Collection/Array/OrderedMap interface.
+ *
+ * A Collection resembles the nature of a regular PHP array. That is,
+ * it is essentially an <b>ordered map</b> that can also be used
+ * like a list.
+ *
+ * A Collection has an internal iterator just like a PHP array. In addition,
+ * a Collection can be iterated with external iterators, which is preferable.
+ * To use an external iterator simply use the foreach language construct to
+ * iterate over the collection (which calls {@link getIterator()} internally) or
+ * explicitly retrieve an iterator though {@link getIterator()} which can then be
+ * used to iterate over the collection.
+ * You can not rely on the internal iterator of the collection being at a certain
+ * position unless you explicitly positioned it before. Prefer iteration with
+ * external iterators.
+ *
+ * @psalm-template TKey of array-key
+ * @psalm-template T
+ * @template-extends ReadableCollection<TKey, T>
+ * @template-extends ArrayAccess<TKey, T>
+ */
+interface Collection extends ReadableCollection, ArrayAccess
+{
+ /**
+ * Adds an element at the end of the collection.
+ *
+ * @param mixed $element The element to add.
+ * @psalm-param T $element
+ *
+ * @return true Always TRUE.
+ */
+ public function add($element);
+
+ /**
+ * Clears the collection, removing all elements.
+ *
+ * @return void
+ */
+ public function clear();
+
+ /**
+ * Removes the element at the specified index from the collection.
+ *
+ * @param string|int $key The key/index of the element to remove.
+ * @psalm-param TKey $key
+ *
+ * @return mixed The removed element or NULL, if the collection did not contain the element.
+ * @psalm-return T|null
+ */
+ public function remove($key);
+
+ /**
+ * Removes the specified element from the collection, if it is found.
+ *
+ * @param mixed $element The element to remove.
+ * @psalm-param T $element
+ *
+ * @return bool TRUE if this collection contained the specified element, FALSE otherwise.
+ */
+ public function removeElement($element);
+
+ /**
+ * Sets an element in the collection at the specified key/index.
+ *
+ * @param string|int $key The key/index of the element to set.
+ * @param mixed $value The element to set.
+ * @psalm-param TKey $key
+ * @psalm-param T $value
+ *
+ * @return void
+ */
+ public function set($key, $value);
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return Collection<mixed> A collection with the results of the filter operation.
+ * @psalm-return Collection<TKey, T>
+ */
+ public function filter(Closure $p);
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return Collection<mixed>[] An array with two elements. The first element contains the collection
+ * of elements where the predicate returned TRUE, the second element
+ * contains the collection of elements where the predicate returned FALSE.
+ * @psalm-return array{0: Collection<TKey, T>, 1: Collection<TKey, T>}
+ */
+ public function partition(Closure $p);
+}
diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Criteria.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Criteria.php
new file mode 100644
index 0000000..c1639d3
--- /dev/null
+++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Criteria.php
@@ -0,0 +1,245 @@
+<?php
+
+namespace Doctrine\Common\Collections;
+
+use Doctrine\Common\Collections\Expr\CompositeExpression;
+use Doctrine\Common\Collections\Expr\Expression;
+use Doctrine\Deprecations\Deprecation;
+
+use function array_map;
+use function func_num_args;
+use function strtoupper;
+
+/**
+ * Criteria for filtering Selectable collections.
+ *
+ * @psalm-consistent-constructor
+ */
+class Criteria
+{
+ public const ASC = 'ASC';
+
+ public const DESC = 'DESC';
+
+ /** @var ExpressionBuilder|null */
+ private static $expressionBuilder;
+
+ /** @var Expression|null */
+ private $expression;
+
+ /** @var string[] */
+ private $orderings = [];
+
+ /** @var int|null */
+ private $firstResult;
+
+ /** @var int|null */
+ private $maxResults;
+
+ /**
+ * Creates an instance of the class.
+ *
+ * @return Criteria
+ */
+ public static function create()
+ {
+ return new static();
+ }
+
+ /**
+ * Returns the expression builder.
+ *
+ * @return ExpressionBuilder
+ */
+ public static function expr()
+ {
+ if (self::$expressionBuilder === null) {
+ self::$expressionBuilder = new ExpressionBuilder();
+ }
+
+ return self::$expressionBuilder;
+ }
+
+ /**
+ * Construct a new Criteria.
+ *
+ * @param string[]|null $orderings
+ * @param int|null $firstResult
+ * @param int|null $maxResults
+ */
+ public function __construct(?Expression $expression = null, ?array $orderings = null, $firstResult = null, $maxResults = null)
+ {
+ $this->expression = $expression;
+
+ if ($firstResult === null && func_num_args() > 2) {
+ Deprecation::trigger(
+ 'doctrine/collections',
+ 'https://github.com/doctrine/collections/pull/311',
+ 'Passing null as $firstResult to the constructor of %s is deprecated. Pass 0 instead or omit the argument.',
+ self::class
+ );
+ }
+
+ $this->setFirstResult($firstResult);
+ $this->setMaxResults($maxResults);
+
+ if ($orderings === null) {
+ return;
+ }
+
+ $this->orderBy($orderings);
+ }
+
+ /**
+ * Sets the where expression to evaluate when this Criteria is searched for.
+ *
+ * @return $this
+ */
+ public function where(Expression $expression)
+ {
+ $this->expression = $expression;
+
+ return $this;
+ }
+
+ /**
+ * Appends the where expression to evaluate when this Criteria is searched for
+ * using an AND with previous expression.
+ *
+ * @return $this
+ */
+ public function andWhere(Expression $expression)
+ {
+ if ($this->expression === null) {
+ return $this->where($expression);
+ }
+
+ $this->expression = new CompositeExpression(
+ CompositeExpression::TYPE_AND,
+ [$this->expression, $expression]
+ );
+
+ return $this;
+ }
+
+ /**
+ * Appends the where expression to evaluate when this Criteria is searched for
+ * using an OR with previous expression.
+ *
+ * @return $this
+ */
+ public function orWhere(Expression $expression)
+ {
+ if ($this->expression === null) {
+ return $this->where($expression);
+ }
+
+ $this->expression = new CompositeExpression(
+ CompositeExpression::TYPE_OR,
+ [$this->expression, $expression]
+ );
+
+ return $this;
+ }
+
+ /**
+ * Gets the expression attached to this Criteria.
+ *
+ * @return Expression|null
+ */
+ public function getWhereExpression()
+ {
+ return $this->expression;
+ }
+
+ /**
+ * Gets the current orderings of this Criteria.
+ *
+ * @return string[]
+ */
+ public function getOrderings()
+ {
+ return $this->orderings;
+ }
+
+ /**
+ * Sets the ordering of the result of this Criteria.
+ *
+ * Keys are field and values are the order, being either ASC or DESC.
+ *
+ * @see Criteria::ASC
+ * @see Criteria::DESC
+ *
+ * @param string[] $orderings
+ *
+ * @return $this
+ */
+ public function orderBy(array $orderings)
+ {
+ $this->orderings = array_map(
+ static function (string $ordering): string {
+ return strtoupper($ordering) === Criteria::ASC ? Criteria::ASC : Criteria::DESC;
+ },
+ $orderings
+ );
+
+ return $this;
+ }
+
+ /**
+ * Gets the current first result option of this Criteria.
+ *
+ * @return int|null
+ */
+ public function getFirstResult()
+ {
+ return $this->firstResult;
+ }
+
+ /**
+ * Set the number of first result that this Criteria should return.
+ *
+ * @param int|null $firstResult The value to set.
+ *
+ * @return $this
+ */
+ public function setFirstResult($firstResult)
+ {
+ if ($firstResult === null) {
+ Deprecation::triggerIfCalledFromOutside(
+ 'doctrine/collections',
+ 'https://github.com/doctrine/collections/pull/311',
+ 'Passing null to %s() is deprecated, pass 0 instead.',
+ __METHOD__
+ );
+ }
+
+ $this->firstResult = $firstResult;
+
+ return $this;
+ }
+
+ /**
+ * Gets maxResults.
+ *
+ * @return int|null
+ */
+ public function getMaxResults()
+ {
+ return $this->maxResults;
+ }
+
+ /**
+ * Sets maxResults.
+ *
+ * @param int|null $maxResults The value to set.
+ *
+ * @return $this
+ */
+ public function setMaxResults($maxResults)
+ {
+ $this->maxResults = $maxResults;
+
+ return $this;
+ }
+}
diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php
new file mode 100644
index 0000000..c10b8d5
--- /dev/null
+++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php
@@ -0,0 +1,269 @@
+<?php
+
+namespace Doctrine\Common\Collections\Expr;
+
+use ArrayAccess;
+use Closure;
+use RuntimeException;
+
+use function explode;
+use function in_array;
+use function is_array;
+use function is_scalar;
+use function iterator_to_array;
+use function method_exists;
+use function preg_match;
+use function preg_replace_callback;
+use function strlen;
+use function strpos;
+use function strtoupper;
+use function substr;
+
+/**
+ * Walks an expression graph and turns it into a PHP closure.
+ *
+ * This closure can be used with {@Collection#filter()} and is used internally
+ * by {@ArrayCollection#select()}.
+ */
+class ClosureExpressionVisitor extends ExpressionVisitor
+{
+ /**
+ * Accesses the field of a given object. This field has to be public
+ * directly or indirectly (through an accessor get*, is*, or a magic
+ * method, __get, __call).
+ *
+ * @param object|mixed[] $object
+ * @param string $field
+ *
+ * @return mixed
+ */
+ public static function getObjectFieldValue($object, $field)
+ {
+ if (strpos($field, '.') !== false) {
+ [$field, $subField] = explode('.', $field, 2);
+ $object = self::getObjectFieldValue($object, $field);
+
+ return self::getObjectFieldValue($object, $subField);
+ }
+
+ if (is_array($object)) {
+ return $object[$field];
+ }
+
+ $accessors = ['get', 'is', ''];
+
+ foreach ($accessors as $accessor) {
+ $accessor .= $field;
+
+ if (method_exists($object, $accessor)) {
+ return $object->$accessor();
+ }
+ }
+
+ if (preg_match('/^is[A-Z]+/', $field) === 1 && method_exists($object, $field)) {
+ return $object->$field();
+ }
+
+ // __call should be triggered for get.
+ $accessor = $accessors[0] . $field;
+
+ if (method_exists($object, '__call')) {
+ return $object->$accessor();
+ }
+
+ if ($object instanceof ArrayAccess) {
+ return $object[$field];
+ }
+
+ if (isset($object->$field)) {
+ return $object->$field;
+ }
+
+ // camelcase field name to support different variable naming conventions
+ $ccField = preg_replace_callback('/_(.?)/', static function ($matches) {
+ return strtoupper($matches[1]);
+ }, $field);
+
+ foreach ($accessors as $accessor) {
+ $accessor .= $ccField;
+
+ if (method_exists($object, $accessor)) {
+ return $object->$accessor();
+ }
+ }
+
+ return $object->$field;
+ }
+
+ /**
+ * Helper for sorting arrays of objects based on multiple fields + orientations.
+ *
+ * @param string $name
+ * @param int $orientation
+ *
+ * @return Closure
+ */
+ public static function sortByField($name, $orientation = 1, ?Closure $next = null)
+ {
+ if (! $next) {
+ $next = static function (): int {
+ return 0;
+ };
+ }
+
+ return static function ($a, $b) use ($name, $next, $orientation): int {
+ $aValue = ClosureExpressionVisitor::getObjectFieldValue($a, $name);
+
+ $bValue = ClosureExpressionVisitor::getObjectFieldValue($b, $name);
+
+ if ($aValue === $bValue) {
+ return $next($a, $b);
+ }
+
+ return ($aValue > $bValue ? 1 : -1) * $orientation;
+ };
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function walkComparison(Comparison $comparison)
+ {
+ $field = $comparison->getField();
+ $value = $comparison->getValue()->getValue(); // shortcut for walkValue()
+
+ switch ($comparison->getOperator()) {
+ case Comparison::EQ:
+ return static function ($object) use ($field, $value): bool {
+ return ClosureExpressionVisitor::getObjectFieldValue($object, $field) === $value;
+ };
+
+ case Comparison::NEQ:
+ return static function ($object) use ($field, $value): bool {
+ return ClosureExpressionVisitor::getObjectFieldValue($object, $field) !== $value;
+ };
+
+ case Comparison::LT:
+ return static function ($object) use ($field, $value): bool {
+ return ClosureExpressionVisitor::getObjectFieldValue($object, $field) < $value;
+ };
+
+ case Comparison::LTE:
+ return static function ($object) use ($field, $value): bool {
+ return ClosureExpressionVisitor::getObjectFieldValue($object, $field) <= $value;
+ };
+
+ case Comparison::GT:
+ return static function ($object) use ($field, $value): bool {
+ return ClosureExpressionVisitor::getObjectFieldValue($object, $field) > $value;
+ };
+
+ case Comparison::GTE:
+ return static function ($object) use ($field, $value): bool {
+ return ClosureExpressionVisitor::getObjectFieldValue($object, $field) >= $value;
+ };
+
+ case Comparison::IN:
+ return static function ($object) use ($field, $value): bool {
+ $fieldValue = ClosureExpressionVisitor::getObjectFieldValue($object, $field);
+
+ return in_array($fieldValue, $value, is_scalar($fieldValue));
+ };
+
+ case Comparison::NIN:
+ return static function ($object) use ($field, $value): bool {
+ $fieldValue = ClosureExpressionVisitor::getObjectFieldValue($object, $field);
+
+ return ! in_array($fieldValue, $value, is_scalar($fieldValue));
+ };
+
+ case Comparison::CONTAINS:
+ return static function ($object) use ($field, $value) {
+ return strpos(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value) !== false;
+ };
+
+ case Comparison::MEMBER_OF:
+ return static function ($object) use ($field, $value): bool {
+ $fieldValues = ClosureExpressionVisitor::getObjectFieldValue($object, $field);
+
+ if (! is_array($fieldValues)) {
+ $fieldValues = iterator_to_array($fieldValues);
+ }
+
+ return in_array($value, $fieldValues, true);
+ };
+
+ case Comparison::STARTS_WITH:
+ return static function ($object) use ($field, $value): bool {
+ return strpos(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value) === 0;
+ };
+
+ case Comparison::ENDS_WITH:
+ return static function ($object) use ($field, $value): bool {
+ return $value === substr(ClosureExpressionVisitor::getObjectFieldValue($object, $field), -strlen($value));
+ };
+
+ default:
+ throw new RuntimeException('Unknown comparison operator: ' . $comparison->getOperator());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function walkValue(Value $value)
+ {
+ return $value->getValue();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function walkCompositeExpression(CompositeExpression $expr)
+ {
+ $expressionList = [];
+
+ foreach ($expr->getExpressionList() as $child) {
+ $expressionList[] = $this->dispatch($child);
+ }
+
+ switch ($expr->getType()) {
+ case CompositeExpression::TYPE_AND:
+ return $this->andExpressions($expressionList);
+
+ case CompositeExpression::TYPE_OR:
+ return $this->orExpressions($expressionList);
+
+ default:
+ throw new RuntimeException('Unknown composite ' . $expr->getType());
+ }
+ }
+
+ /** @param callable[] $expressions */
+ private function andExpressions(array $expressions): callable
+ {
+ return static function ($object) use ($expressions): bool {
+ foreach ($expressions as $expression) {
+ if (! $expression($object)) {
+ return false;
+ }
+ }
+
+ return true;
+ };
+ }
+
+ /** @param callable[] $expressions */
+ private function orExpressions(array $expressions): callable
+ {
+ return static function ($object) use ($expressions): bool {
+ foreach ($expressions as $expression) {
+ if ($expression($object)) {
+ return true;
+ }
+ }
+
+ return false;
+ };
+ }
+}
diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Comparison.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Comparison.php
new file mode 100644
index 0000000..6762b8b
--- /dev/null
+++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Comparison.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace Doctrine\Common\Collections\Expr;
+
+/**
+ * Comparison of a field with a value by the given operator.
+ */
+class Comparison implements Expression
+{
+ public const EQ = '=';
+ public const NEQ = '<>';
+ public const LT = '<';
+ public const LTE = '<=';
+ public const GT = '>';
+ public const GTE = '>=';
+ public const IS = '='; // no difference with EQ
+ public const IN = 'IN';
+ public const NIN = 'NIN';
+ public const CONTAINS = 'CONTAINS';
+ public const MEMBER_OF = 'MEMBER_OF';
+ public const STARTS_WITH = 'STARTS_WITH';
+ public const ENDS_WITH = 'ENDS_WITH';
+
+ /** @var string */
+ private $field;
+
+ /** @var string */
+ private $op;
+
+ /** @var Value */
+ private $value;
+
+ /**
+ * @param string $field
+ * @param string $operator
+ * @param mixed $value
+ */
+ public function __construct($field, $operator, $value)
+ {
+ if (! ($value instanceof Value)) {
+ $value = new Value($value);
+ }
+
+ $this->field = $field;
+ $this->op = $operator;
+ $this->value = $value;
+ }
+
+ /** @return string */
+ public function getField()
+ {
+ return $this->field;
+ }
+
+ /** @return Value */
+ public function getValue()
+ {
+ return $this->value;
+ }
+
+ /** @return string */
+ public function getOperator()
+ {
+ return $this->op;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function visit(ExpressionVisitor $visitor)
+ {
+ return $visitor->walkComparison($this);
+ }
+}
diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php
new file mode 100644
index 0000000..174b21b
--- /dev/null
+++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace Doctrine\Common\Collections\Expr;
+
+use RuntimeException;
+
+/**
+ * Expression of Expressions combined by AND or OR operation.
+ */
+class CompositeExpression implements Expression
+{
+ public const TYPE_AND = 'AND';
+ public const TYPE_OR = 'OR';
+
+ /** @var string */
+ private $type;
+
+ /** @var Expression[] */
+ private $expressions = [];
+
+ /**
+ * @param string $type
+ * @param mixed[] $expressions
+ *
+ * @throws RuntimeException
+ */
+ public function __construct($type, array $expressions)
+ {
+ $this->type = $type;
+
+ foreach ($expressions as $expr) {
+ if ($expr instanceof Value) {
+ throw new RuntimeException('Values are not supported expressions as children of and/or expressions.');
+ }
+
+ if (! ($expr instanceof Expression)) {
+ throw new RuntimeException('No expression given to CompositeExpression.');
+ }
+
+ $this->expressions[] = $expr;
+ }
+ }
+
+ /**
+ * Returns the list of expressions nested in this composite.
+ *
+ * @return Expression[]
+ */
+ public function getExpressionList()
+ {
+ return $this->expressions;
+ }
+
+ /** @return string */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function visit(ExpressionVisitor $visitor)
+ {
+ return $visitor->walkCompositeExpression($this);
+ }
+}
diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Expression.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Expression.php
new file mode 100644
index 0000000..566d6d5
--- /dev/null
+++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Expression.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace Doctrine\Common\Collections\Expr;
+
+/**
+ * Expression for the {@link Selectable} interface.
+ */
+interface Expression
+{
+ /** @return mixed */
+ public function visit(ExpressionVisitor $visitor);
+}
diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ExpressionVisitor.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ExpressionVisitor.php
new file mode 100644
index 0000000..72bb153
--- /dev/null
+++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ExpressionVisitor.php
@@ -0,0 +1,59 @@
+<?php
+
+namespace Doctrine\Common\Collections\Expr;
+
+use RuntimeException;
+
+use function get_class;
+
+/**
+ * An Expression visitor walks a graph of expressions and turns them into a
+ * query for the underlying implementation.
+ */
+abstract class ExpressionVisitor
+{
+ /**
+ * Converts a comparison expression into the target query language output.
+ *
+ * @return mixed
+ */
+ abstract public function walkComparison(Comparison $comparison);
+
+ /**
+ * Converts a value expression into the target query language part.
+ *
+ * @return mixed
+ */
+ abstract public function walkValue(Value $value);
+
+ /**
+ * Converts a composite expression into the target query language output.
+ *
+ * @return mixed
+ */
+ abstract public function walkCompositeExpression(CompositeExpression $expr);
+
+ /**
+ * Dispatches walking an expression to the appropriate handler.
+ *
+ * @return mixed
+ *
+ * @throws RuntimeException
+ */
+ public function dispatch(Expression $expr)
+ {
+ switch (true) {
+ case $expr instanceof Comparison:
+ return $this->walkComparison($expr);
+
+ case $expr instanceof Value:
+ return $this->walkValue($expr);
+
+ case $expr instanceof CompositeExpression:
+ return $this->walkCompositeExpression($expr);
+
+ default:
+ throw new RuntimeException('Unknown Expression ' . get_class($expr));
+ }
+ }
+}
diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Value.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Value.php
new file mode 100644
index 0000000..693d345
--- /dev/null
+++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Value.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace Doctrine\Common\Collections\Expr;
+
+class Value implements Expression
+{
+ /** @var mixed */
+ private $value;
+
+ /** @param mixed $value */
+ public function __construct($value)
+ {
+ $this->value = $value;
+ }
+
+ /** @return mixed */
+ public function getValue()
+ {
+ return $this->value;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function visit(ExpressionVisitor $visitor)
+ {
+ return $visitor->walkValue($this);
+ }
+}
diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ExpressionBuilder.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ExpressionBuilder.php
new file mode 100644
index 0000000..ebb21ca
--- /dev/null
+++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ExpressionBuilder.php
@@ -0,0 +1,181 @@
+<?php
+
+namespace Doctrine\Common\Collections;
+
+use Doctrine\Common\Collections\Expr\Comparison;
+use Doctrine\Common\Collections\Expr\CompositeExpression;
+use Doctrine\Common\Collections\Expr\Value;
+
+use function func_get_args;
+
+/**
+ * Builder for Expressions in the {@link Selectable} interface.
+ *
+ * Important Notice for interoperable code: You have to use scalar
+ * values only for comparisons, otherwise the behavior of the comparison
+ * may be different between implementations (Array vs ORM vs ODM).
+ */
+class ExpressionBuilder
+{
+ /**
+ * @param mixed ...$x
+ *
+ * @return CompositeExpression
+ */
+ public function andX($x = null)
+ {
+ return new CompositeExpression(CompositeExpression::TYPE_AND, func_get_args());
+ }
+
+ /**
+ * @param mixed ...$x
+ *
+ * @return CompositeExpression
+ */
+ public function orX($x = null)
+ {
+ return new CompositeExpression(CompositeExpression::TYPE_OR, func_get_args());
+ }
+
+ /**
+ * @param string $field
+ * @param mixed $value
+ *
+ * @return Comparison
+ */
+ public function eq($field, $value)
+ {
+ return new Comparison($field, Comparison::EQ, new Value($value));
+ }
+
+ /**
+ * @param string $field
+ * @param mixed $value
+ *
+ * @return Comparison
+ */
+ public function gt($field, $value)
+ {
+ return new Comparison($field, Comparison::GT, new Value($value));
+ }
+
+ /**
+ * @param string $field
+ * @param mixed $value
+ *
+ * @return Comparison
+ */
+ public function lt($field, $value)
+ {
+ return new Comparison($field, Comparison::LT, new Value($value));
+ }
+
+ /**
+ * @param string $field
+ * @param mixed $value
+ *
+ * @return Comparison
+ */
+ public function gte($field, $value)
+ {
+ return new Comparison($field, Comparison::GTE, new Value($value));
+ }
+
+ /**
+ * @param string $field
+ * @param mixed $value
+ *
+ * @return Comparison
+ */
+ public function lte($field, $value)
+ {
+ return new Comparison($field, Comparison::LTE, new Value($value));
+ }
+
+ /**
+ * @param string $field
+ * @param mixed $value
+ *
+ * @return Comparison
+ */
+ public function neq($field, $value)
+ {
+ return new Comparison($field, Comparison::NEQ, new Value($value));
+ }
+
+ /**
+ * @param string $field
+ *
+ * @return Comparison
+ */
+ public function isNull($field)
+ {
+ return new Comparison($field, Comparison::EQ, new Value(null));
+ }
+
+ /**
+ * @param string $field
+ * @param mixed[] $values
+ *
+ * @return Comparison
+ */
+ public function in($field, array $values)
+ {
+ return new Comparison($field, Comparison::IN, new Value($values));
+ }
+
+ /**
+ * @param string $field
+ * @param mixed[] $values
+ *
+ * @return Comparison
+ */
+ public function notIn($field, array $values)
+ {
+ return new Comparison($field, Comparison::NIN, new Value($values));
+ }
+
+ /**
+ * @param string $field
+ * @param mixed $value
+ *
+ * @return Comparison
+ */
+ public function contains($field, $value)
+ {
+ return new Comparison($field, Comparison::CONTAINS, new Value($value));
+ }
+
+ /**
+ * @param string $field
+ * @param mixed $value
+ *
+ * @return Comparison
+ */
+ public function memberOf($field, $value)
+ {
+ return new Comparison($field, Comparison::MEMBER_OF, new Value($value));
+ }
+
+ /**
+ * @param string $field
+ * @param mixed $value
+ *
+ * @return Comparison
+ */
+ public function startsWith($field, $value)
+ {
+ return new Comparison($field, Comparison::STARTS_WITH, new Value($value));
+ }
+
+ /**
+ * @param string $field
+ * @param mixed $value
+ *
+ * @return Comparison
+ */
+ public function endsWith($field, $value)
+ {
+ return new Comparison($field, Comparison::ENDS_WITH, new Value($value));
+ }
+}
diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ReadableCollection.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ReadableCollection.php
new file mode 100644
index 0000000..44b3749
--- /dev/null
+++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ReadableCollection.php
@@ -0,0 +1,213 @@
+<?php
+
+namespace Doctrine\Common\Collections;
+
+use Closure;
+use Countable;
+use IteratorAggregate;
+
+/**
+ * @psalm-template TKey of array-key
+ * @template-covariant T
+ * @template-extends IteratorAggregate<TKey, T>
+ */
+interface ReadableCollection extends Countable, IteratorAggregate
+{
+ /**
+ * Checks whether an element is contained in the collection.
+ * This is an O(n) operation, where n is the size of the collection.
+ *
+ * @param mixed $element The element to search for.
+ * @psalm-param TMaybeContained $element
+ *
+ * @return bool TRUE if the collection contains the element, FALSE otherwise.
+ * @psalm-return (TMaybeContained is T ? bool : false)
+ *
+ * @template TMaybeContained
+ */
+ public function contains($element);
+
+ /**
+ * Checks whether the collection is empty (contains no elements).
+ *
+ * @return bool TRUE if the collection is empty, FALSE otherwise.
+ */
+ public function isEmpty();
+
+ /**
+ * Checks whether the collection contains an element with the specified key/index.
+ *
+ * @param string|int $key The key/index to check for.
+ * @psalm-param TKey $key
+ *
+ * @return bool TRUE if the collection contains an element with the specified key/index,
+ * FALSE otherwise.
+ */
+ public function containsKey($key);
+
+ /**
+ * Gets the element at the specified key/index.
+ *
+ * @param string|int $key The key/index of the element to retrieve.
+ * @psalm-param TKey $key
+ *
+ * @return mixed
+ * @psalm-return T|null
+ */
+ public function get($key);
+
+ /**
+ * Gets all keys/indices of the collection.
+ *
+ * @return int[]|string[] The keys/indices of the collection, in the order of the corresponding
+ * elements in the collection.
+ * @psalm-return list<TKey>
+ */
+ public function getKeys();
+
+ /**
+ * Gets all values of the collection.
+ *
+ * @return mixed[] The values of all elements in the collection, in the
+ * order they appear in the collection.
+ * @psalm-return list<T>
+ */
+ public function getValues();
+
+ /**
+ * Gets a native PHP array representation of the collection.
+ *
+ * @return mixed[]
+ * @psalm-return array<TKey,T>
+ */
+ public function toArray();
+
+ /**
+ * Sets the internal iterator to the first element in the collection and returns this element.
+ *
+ * @return mixed
+ * @psalm-return T|false
+ */
+ public function first();
+
+ /**
+ * Sets the internal iterator to the last element in the collection and returns this element.
+ *
+ * @return mixed
+ * @psalm-return T|false
+ */
+ public function last();
+
+ /**
+ * Gets the key/index of the element at the current iterator position.
+ *
+ * @return int|string|null
+ * @psalm-return TKey|null
+ */
+ public function key();
+
+ /**
+ * Gets the element of the collection at the current iterator position.
+ *
+ * @return mixed
+ * @psalm-return T|false
+ */
+ public function current();
+
+ /**
+ * Moves the internal iterator position to the next element and returns this element.
+ *
+ * @return mixed
+ * @psalm-return T|false
+ */
+ public function next();
+
+ /**
+ * Extracts a slice of $length elements starting at position $offset from the Collection.
+ *
+ * If $length is null it returns all elements from $offset to the end of the Collection.
+ * Keys have to be preserved by this method. Calling this method will only return the
+ * selected slice and NOT change the elements contained in the collection slice is called on.
+ *
+ * @param int $offset The offset to start from.
+ * @param int|null $length The maximum number of elements to return, or null for no limit.
+ *
+ * @return mixed[]
+ * @psalm-return array<TKey,T>
+ */
+ public function slice($offset, $length = null);
+
+ /**
+ * Tests for the existence of an element that satisfies the given predicate.
+ *
+ * @param Closure $p The predicate.
+ * @psalm-param Closure(TKey, T):bool $p
+ *
+ * @return bool TRUE if the predicate is TRUE for at least one element, FALSE otherwise.
+ */
+ public function exists(Closure $p);
+
+ /**
+ * Returns all the elements of this collection that satisfy the predicate p.
+ * The order of the elements is preserved.
+ *
+ * @param Closure $p The predicate used for filtering.
+ * @psalm-param Closure(T):bool $p
+ *
+ * @return ReadableCollection<mixed> A collection with the results of the filter operation.
+ * @psalm-return ReadableCollection<TKey, T>
+ */
+ public function filter(Closure $p);
+
+ /**
+ * Applies the given function to each element in the collection and returns
+ * a new collection with the elements returned by the function.
+ *
+ * @psalm-param Closure(T):U $func
+ *
+ * @return Collection<mixed>
+ * @psalm-return Collection<TKey, U>
+ *
+ * @psalm-template U
+ */
+ public function map(Closure $func);
+
+ /**
+ * Partitions this collection in two collections according to a predicate.
+ * Keys are preserved in the resulting collections.
+ *
+ * @param Closure $p The predicate on which to partition.
+ * @psalm-param Closure(TKey, T):bool $p
+ *
+ * @return ReadableCollection<mixed>[] An array with two elements. The first element contains the collection
+ * of elements where the predicate returned TRUE, the second element
+ * contains the collection of elements where the predicate returned FALSE.
+ * @psalm-return array{0: ReadableCollection<TKey, T>, 1: ReadableCollection<TKey, T>}
+ */
+ public function partition(Closure $p);
+
+ /**
+ * Tests whether the given predicate p holds for all elements of this collection.
+ *
+ * @param Closure $p The predicate.
+ * @psalm-param Closure(TKey, T):bool $p
+ *
+ * @return bool TRUE, if the predicate yields TRUE for all elements, FALSE otherwise.
+ */
+ public function forAll(Closure $p);
+
+ /**
+ * Gets the index/key of a given element. The comparison of two elements is strict,
+ * that means not only the value but also the type must match.
+ * For objects this means reference equality.
+ *
+ * @param mixed $element The element to search for.
+ * @psalm-param TMaybeContained $element
+ *
+ * @return int|string|bool The key/index of the element or FALSE if the element was not found.
+ * @psalm-return (TMaybeContained is T ? TKey|false : false)
+ *
+ * @template TMaybeContained
+ */
+ public function indexOf($element);
+}
diff --git a/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Selectable.php b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Selectable.php
new file mode 100644
index 0000000..9f7586d
--- /dev/null
+++ b/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Selectable.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Doctrine\Common\Collections;
+
+/**
+ * Interface for collections that allow efficient filtering with an expression API.
+ *
+ * Goal of this interface is a backend independent method to fetch elements
+ * from a collections. {@link Expression} is crafted in a way that you can
+ * implement queries from both in-memory and database-backed collections.
+ *
+ * For database backed collections this allows very efficient access by
+ * utilizing the query APIs, for example SQL in the ORM. Applications using
+ * this API can implement efficient database access without having to ask the
+ * EntityManager or Repositories.
+ *
+ * @psalm-template TKey as array-key
+ * @psalm-template T
+ */
+interface Selectable
+{
+ /**
+ * Selects all elements from a selectable that match the expression and
+ * returns a new collection containing these elements.
+ *
+ * @return Collection<mixed>&Selectable<mixed>
+ * @psalm-return Collection<TKey,T>&Selectable<TKey,T>
+ */
+ public function matching(Criteria $criteria);
+}