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