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

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