vendor/doctrine/collections/lib/Doctrine/Common/Collections/ArrayCollection.php line 45

Open in your IDE?
  1. <?php
  2. namespace Doctrine\Common\Collections;
  3. use ArrayIterator;
  4. use Closure;
  5. use Doctrine\Common\Collections\Expr\ClosureExpressionVisitor;
  6. use ReturnTypeWillChange;
  7. use Traversable;
  8. use function array_filter;
  9. use function array_key_exists;
  10. use function array_keys;
  11. use function array_map;
  12. use function array_reverse;
  13. use function array_search;
  14. use function array_slice;
  15. use function array_values;
  16. use function count;
  17. use function current;
  18. use function end;
  19. use function in_array;
  20. use function key;
  21. use function next;
  22. use function reset;
  23. use function spl_object_hash;
  24. use function uasort;
  25. use const ARRAY_FILTER_USE_BOTH;
  26. /**
  27.  * An ArrayCollection is a Collection implementation that wraps a regular PHP array.
  28.  *
  29.  * Warning: Using (un-)serialize() on a collection is not a supported use-case
  30.  * and may break when we change the internals in the future. If you need to
  31.  * serialize a collection use {@link toArray()} and reconstruct the collection
  32.  * manually.
  33.  *
  34.  * @psalm-template TKey of array-key
  35.  * @psalm-template T
  36.  * @template-implements Collection<TKey,T>
  37.  * @template-implements Selectable<TKey,T>
  38.  * @psalm-consistent-constructor
  39.  */
  40. class ArrayCollection implements CollectionSelectable
  41. {
  42.     /**
  43.      * An array containing the entries of this collection.
  44.      *
  45.      * @psalm-var array<TKey,T>
  46.      * @var mixed[]
  47.      */
  48.     private $elements;
  49.     /**
  50.      * Initializes a new ArrayCollection.
  51.      *
  52.      * @param array $elements
  53.      * @psalm-param array<TKey,T> $elements
  54.      */
  55.     public function __construct(array $elements = [])
  56.     {
  57.         $this->elements $elements;
  58.     }
  59.     /**
  60.      * {@inheritDoc}
  61.      */
  62.     public function toArray()
  63.     {
  64.         return $this->elements;
  65.     }
  66.     /**
  67.      * {@inheritDoc}
  68.      */
  69.     public function first()
  70.     {
  71.         return reset($this->elements);
  72.     }
  73.     /**
  74.      * Creates a new instance from the specified elements.
  75.      *
  76.      * This method is provided for derived classes to specify how a new
  77.      * instance should be created when constructor semantics have changed.
  78.      *
  79.      * @param array $elements Elements.
  80.      * @psalm-param array<K,V> $elements
  81.      *
  82.      * @return static
  83.      * @psalm-return static<K,V>
  84.      *
  85.      * @psalm-template K of array-key
  86.      * @psalm-template V
  87.      */
  88.     protected function createFrom(array $elements)
  89.     {
  90.         return new static($elements);
  91.     }
  92.     /**
  93.      * {@inheritDoc}
  94.      */
  95.     public function last()
  96.     {
  97.         return end($this->elements);
  98.     }
  99.     /**
  100.      * {@inheritDoc}
  101.      */
  102.     public function key()
  103.     {
  104.         return key($this->elements);
  105.     }
  106.     /**
  107.      * {@inheritDoc}
  108.      */
  109.     public function next()
  110.     {
  111.         return next($this->elements);
  112.     }
  113.     /**
  114.      * {@inheritDoc}
  115.      */
  116.     public function current()
  117.     {
  118.         return current($this->elements);
  119.     }
  120.     /**
  121.      * {@inheritDoc}
  122.      */
  123.     public function remove($key)
  124.     {
  125.         if (! isset($this->elements[$key]) && ! array_key_exists($key$this->elements)) {
  126.             return null;
  127.         }
  128.         $removed $this->elements[$key];
  129.         unset($this->elements[$key]);
  130.         return $removed;
  131.     }
  132.     /**
  133.      * {@inheritDoc}
  134.      */
  135.     public function removeElement($element)
  136.     {
  137.         $key array_search($element$this->elementstrue);
  138.         if ($key === false) {
  139.             return false;
  140.         }
  141.         unset($this->elements[$key]);
  142.         return true;
  143.     }
  144.     /**
  145.      * Required by interface ArrayAccess.
  146.      *
  147.      * @param TKey $offset
  148.      *
  149.      * @return bool
  150.      */
  151.     #[ReturnTypeWillChange]
  152.     public function offsetExists($offset)
  153.     {
  154.         return $this->containsKey($offset);
  155.     }
  156.     /**
  157.      * Required by interface ArrayAccess.
  158.      *
  159.      * @param TKey $offset
  160.      *
  161.      * @return mixed
  162.      */
  163.     #[ReturnTypeWillChange]
  164.     public function offsetGet($offset)
  165.     {
  166.         return $this->get($offset);
  167.     }
  168.     /**
  169.      * Required by interface ArrayAccess.
  170.      *
  171.      * @param TKey|null $offset
  172.      * @param T         $value
  173.      *
  174.      * @return void
  175.      */
  176.     #[ReturnTypeWillChange]
  177.     public function offsetSet($offset$value)
  178.     {
  179.         if (! isset($offset)) {
  180.             $this->add($value);
  181.             return;
  182.         }
  183.         $this->set($offset$value);
  184.     }
  185.     /**
  186.      * Required by interface ArrayAccess.
  187.      *
  188.      * @param TKey $offset
  189.      *
  190.      * @return void
  191.      */
  192.     #[ReturnTypeWillChange]
  193.     public function offsetUnset($offset)
  194.     {
  195.         $this->remove($offset);
  196.     }
  197.     /**
  198.      * {@inheritDoc}
  199.      */
  200.     public function containsKey($key)
  201.     {
  202.         return isset($this->elements[$key]) || array_key_exists($key$this->elements);
  203.     }
  204.     /**
  205.      * {@inheritDoc}
  206.      *
  207.      * @template TMaybeContained
  208.      */
  209.     public function contains($element)
  210.     {
  211.         return in_array($element$this->elementstrue);
  212.     }
  213.     /**
  214.      * {@inheritDoc}
  215.      */
  216.     public function exists(Closure $p)
  217.     {
  218.         foreach ($this->elements as $key => $element) {
  219.             if ($p($key$element)) {
  220.                 return true;
  221.             }
  222.         }
  223.         return false;
  224.     }
  225.     /**
  226.      * {@inheritDoc}
  227.      *
  228.      * @psalm-param TMaybeContained $element
  229.      *
  230.      * @psalm-return (TMaybeContained is T ? TKey|false : false)
  231.      *
  232.      * @template TMaybeContained
  233.      */
  234.     public function indexOf($element)
  235.     {
  236.         return array_search($element$this->elementstrue);
  237.     }
  238.     /**
  239.      * {@inheritDoc}
  240.      */
  241.     public function get($key)
  242.     {
  243.         return $this->elements[$key] ?? null;
  244.     }
  245.     /**
  246.      * {@inheritDoc}
  247.      */
  248.     public function getKeys()
  249.     {
  250.         return array_keys($this->elements);
  251.     }
  252.     /**
  253.      * {@inheritDoc}
  254.      */
  255.     public function getValues()
  256.     {
  257.         return array_values($this->elements);
  258.     }
  259.     /**
  260.      * {@inheritDoc}
  261.      *
  262.      * @return int
  263.      */
  264.     #[ReturnTypeWillChange]
  265.     public function count()
  266.     {
  267.         return count($this->elements);
  268.     }
  269.     /**
  270.      * {@inheritDoc}
  271.      */
  272.     public function set($key$value)
  273.     {
  274.         $this->elements[$key] = $value;
  275.     }
  276.     /**
  277.      * {@inheritDoc}
  278.      *
  279.      * @psalm-suppress InvalidPropertyAssignmentValue
  280.      *
  281.      * This breaks assumptions about the template type, but it would
  282.      * be a backwards-incompatible change to remove this method
  283.      */
  284.     public function add($element)
  285.     {
  286.         $this->elements[] = $element;
  287.         return true;
  288.     }
  289.     /**
  290.      * {@inheritDoc}
  291.      */
  292.     public function isEmpty()
  293.     {
  294.         return empty($this->elements);
  295.     }
  296.     /**
  297.      * {@inheritDoc}
  298.      *
  299.      * @return Traversable<int|string, mixed>
  300.      * @psalm-return Traversable<TKey,T>
  301.      */
  302.     #[ReturnTypeWillChange]
  303.     public function getIterator()
  304.     {
  305.         return new ArrayIterator($this->elements);
  306.     }
  307.     /**
  308.      * {@inheritDoc}
  309.      *
  310.      * @psalm-param Closure(T):U $func
  311.      *
  312.      * @return static
  313.      * @psalm-return static<TKey, U>
  314.      *
  315.      * @psalm-template U
  316.      */
  317.     public function map(Closure $func)
  318.     {
  319.         return $this->createFrom(array_map($func$this->elements));
  320.     }
  321.     /**
  322.      * {@inheritDoc}
  323.      *
  324.      * @return static
  325.      * @psalm-return static<TKey,T>
  326.      */
  327.     public function filter(Closure $p)
  328.     {
  329.         return $this->createFrom(array_filter($this->elements$pARRAY_FILTER_USE_BOTH));
  330.     }
  331.     /**
  332.      * {@inheritDoc}
  333.      */
  334.     public function forAll(Closure $p)
  335.     {
  336.         foreach ($this->elements as $key => $element) {
  337.             if (! $p($key$element)) {
  338.                 return false;
  339.             }
  340.         }
  341.         return true;
  342.     }
  343.     /**
  344.      * {@inheritDoc}
  345.      */
  346.     public function partition(Closure $p)
  347.     {
  348.         $matches $noMatches = [];
  349.         foreach ($this->elements as $key => $element) {
  350.             if ($p($key$element)) {
  351.                 $matches[$key] = $element;
  352.             } else {
  353.                 $noMatches[$key] = $element;
  354.             }
  355.         }
  356.         return [$this->createFrom($matches), $this->createFrom($noMatches)];
  357.     }
  358.     /**
  359.      * Returns a string representation of this object.
  360.      *
  361.      * @return string
  362.      */
  363.     public function __toString()
  364.     {
  365.         return self::class . '@' spl_object_hash($this);
  366.     }
  367.     /**
  368.      * {@inheritDoc}
  369.      */
  370.     public function clear()
  371.     {
  372.         $this->elements = [];
  373.     }
  374.     /**
  375.      * {@inheritDoc}
  376.      */
  377.     public function slice($offset$length null)
  378.     {
  379.         return array_slice($this->elements$offset$lengthtrue);
  380.     }
  381.     /**
  382.      * {@inheritDoc}
  383.      */
  384.     public function matching(Criteria $criteria)
  385.     {
  386.         $expr     $criteria->getWhereExpression();
  387.         $filtered $this->elements;
  388.         if ($expr) {
  389.             $visitor  = new ClosureExpressionVisitor();
  390.             $filter   $visitor->dispatch($expr);
  391.             $filtered array_filter($filtered$filter);
  392.         }
  393.         $orderings $criteria->getOrderings();
  394.         if ($orderings) {
  395.             $next null;
  396.             foreach (array_reverse($orderings) as $field => $ordering) {
  397.                 $next ClosureExpressionVisitor::sortByField($field$ordering === Criteria::DESC ? -1$next);
  398.             }
  399.             uasort($filtered$next);
  400.         }
  401.         $offset $criteria->getFirstResult();
  402.         $length $criteria->getMaxResults();
  403.         if ($offset || $length) {
  404.             $filtered array_slice($filtered, (int) $offset$length);
  405.         }
  406.         return $this->createFrom($filtered);
  407.     }
  408. }