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.      * {@inheritDoc}
  148.      *
  149.      * @psalm-param TKey $offset
  150.      *
  151.      * @return bool
  152.      */
  153.     #[ReturnTypeWillChange]
  154.     public function offsetExists($offset)
  155.     {
  156.         return $this->containsKey($offset);
  157.     }
  158.     /**
  159.      * Required by interface ArrayAccess.
  160.      *
  161.      * {@inheritDoc}
  162.      *
  163.      * @psalm-param TKey $offset
  164.      *
  165.      * @return mixed
  166.      */
  167.     #[ReturnTypeWillChange]
  168.     public function offsetGet($offset)
  169.     {
  170.         return $this->get($offset);
  171.     }
  172.     /**
  173.      * Required by interface ArrayAccess.
  174.      *
  175.      * {@inheritDoc}
  176.      *
  177.      * @return void
  178.      */
  179.     #[ReturnTypeWillChange]
  180.     public function offsetSet($offset$value)
  181.     {
  182.         if (! isset($offset)) {
  183.             $this->add($value);
  184.             return;
  185.         }
  186.         $this->set($offset$value);
  187.     }
  188.     /**
  189.      * Required by interface ArrayAccess.
  190.      *
  191.      * {@inheritDoc}
  192.      *
  193.      * @psalm-param TKey $offset
  194.      *
  195.      * @return void
  196.      */
  197.     #[ReturnTypeWillChange]
  198.     public function offsetUnset($offset)
  199.     {
  200.         $this->remove($offset);
  201.     }
  202.     /**
  203.      * {@inheritDoc}
  204.      */
  205.     public function containsKey($key)
  206.     {
  207.         return isset($this->elements[$key]) || array_key_exists($key$this->elements);
  208.     }
  209.     /**
  210.      * {@inheritDoc}
  211.      */
  212.     public function contains($element)
  213.     {
  214.         return in_array($element$this->elementstrue);
  215.     }
  216.     /**
  217.      * {@inheritDoc}
  218.      */
  219.     public function exists(Closure $p)
  220.     {
  221.         foreach ($this->elements as $key => $element) {
  222.             if ($p($key$element)) {
  223.                 return true;
  224.             }
  225.         }
  226.         return false;
  227.     }
  228.     /**
  229.      * {@inheritDoc}
  230.      */
  231.     public function indexOf($element)
  232.     {
  233.         return array_search($element$this->elementstrue);
  234.     }
  235.     /**
  236.      * {@inheritDoc}
  237.      */
  238.     public function get($key)
  239.     {
  240.         return $this->elements[$key] ?? null;
  241.     }
  242.     /**
  243.      * {@inheritDoc}
  244.      */
  245.     public function getKeys()
  246.     {
  247.         return array_keys($this->elements);
  248.     }
  249.     /**
  250.      * {@inheritDoc}
  251.      */
  252.     public function getValues()
  253.     {
  254.         return array_values($this->elements);
  255.     }
  256.     /**
  257.      * {@inheritDoc}
  258.      *
  259.      * @return int
  260.      */
  261.     #[ReturnTypeWillChange]
  262.     public function count()
  263.     {
  264.         return count($this->elements);
  265.     }
  266.     /**
  267.      * {@inheritDoc}
  268.      */
  269.     public function set($key$value)
  270.     {
  271.         $this->elements[$key] = $value;
  272.     }
  273.     /**
  274.      * {@inheritDoc}
  275.      *
  276.      * @psalm-suppress InvalidPropertyAssignmentValue
  277.      *
  278.      * This breaks assumptions about the template type, but it would
  279.      * be a backwards-incompatible change to remove this method
  280.      */
  281.     public function add($element)
  282.     {
  283.         $this->elements[] = $element;
  284.         return true;
  285.     }
  286.     /**
  287.      * {@inheritDoc}
  288.      */
  289.     public function isEmpty()
  290.     {
  291.         return empty($this->elements);
  292.     }
  293.     /**
  294.      * {@inheritDoc}
  295.      *
  296.      * @return Traversable<int|string, mixed>
  297.      * @psalm-return Traversable<TKey,T>
  298.      */
  299.     #[ReturnTypeWillChange]
  300.     public function getIterator()
  301.     {
  302.         return new ArrayIterator($this->elements);
  303.     }
  304.     /**
  305.      * {@inheritDoc}
  306.      *
  307.      * @psalm-param Closure(T=):U $func
  308.      *
  309.      * @return static
  310.      * @psalm-return static<TKey, U>
  311.      *
  312.      * @psalm-template U
  313.      */
  314.     public function map(Closure $func)
  315.     {
  316.         return $this->createFrom(array_map($func$this->elements));
  317.     }
  318.     /**
  319.      * {@inheritDoc}
  320.      *
  321.      * @return static
  322.      * @psalm-return static<TKey,T>
  323.      */
  324.     public function filter(Closure $p)
  325.     {
  326.         return $this->createFrom(array_filter($this->elements$pARRAY_FILTER_USE_BOTH));
  327.     }
  328.     /**
  329.      * {@inheritDoc}
  330.      */
  331.     public function forAll(Closure $p)
  332.     {
  333.         foreach ($this->elements as $key => $element) {
  334.             if (! $p($key$element)) {
  335.                 return false;
  336.             }
  337.         }
  338.         return true;
  339.     }
  340.     /**
  341.      * {@inheritDoc}
  342.      */
  343.     public function partition(Closure $p)
  344.     {
  345.         $matches $noMatches = [];
  346.         foreach ($this->elements as $key => $element) {
  347.             if ($p($key$element)) {
  348.                 $matches[$key] = $element;
  349.             } else {
  350.                 $noMatches[$key] = $element;
  351.             }
  352.         }
  353.         return [$this->createFrom($matches), $this->createFrom($noMatches)];
  354.     }
  355.     /**
  356.      * Returns a string representation of this object.
  357.      *
  358.      * @return string
  359.      */
  360.     public function __toString()
  361.     {
  362.         return self::class . '@' spl_object_hash($this);
  363.     }
  364.     /**
  365.      * {@inheritDoc}
  366.      */
  367.     public function clear()
  368.     {
  369.         $this->elements = [];
  370.     }
  371.     /**
  372.      * {@inheritDoc}
  373.      */
  374.     public function slice($offset$length null)
  375.     {
  376.         return array_slice($this->elements$offset$lengthtrue);
  377.     }
  378.     /**
  379.      * {@inheritDoc}
  380.      */
  381.     public function matching(Criteria $criteria)
  382.     {
  383.         $expr     $criteria->getWhereExpression();
  384.         $filtered $this->elements;
  385.         if ($expr) {
  386.             $visitor  = new ClosureExpressionVisitor();
  387.             $filter   $visitor->dispatch($expr);
  388.             $filtered array_filter($filtered$filter);
  389.         }
  390.         $orderings $criteria->getOrderings();
  391.         if ($orderings) {
  392.             $next null;
  393.             foreach (array_reverse($orderings) as $field => $ordering) {
  394.                 $next ClosureExpressionVisitor::sortByField($field$ordering === Criteria::DESC ? -1$next);
  395.             }
  396.             uasort($filtered$next);
  397.         }
  398.         $offset $criteria->getFirstResult();
  399.         $length $criteria->getMaxResults();
  400.         if ($offset || $length) {
  401.             $filtered array_slice($filtered, (int) $offset$length);
  402.         }
  403.         return $this->createFrom($filtered);
  404.     }
  405. }