Security update to Drupal 8.4.6
[yaffs-website] / vendor / doctrine / collections / lib / Doctrine / Common / Collections / ArrayCollection.php
1 <?php
2 /*
3  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14  *
15  * This software consists of voluntary contributions made by many individuals
16  * and is licensed under the MIT license. For more information, see
17  * <http://www.doctrine-project.org>.
18  */
19
20 namespace Doctrine\Common\Collections;
21
22 use ArrayIterator;
23 use Closure;
24 use Doctrine\Common\Collections\Expr\ClosureExpressionVisitor;
25
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  * @since  2.0
35  * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
36  * @author Jonathan Wage <jonwage@gmail.com>
37  * @author Roman Borschel <roman@code-factory.org>
38  */
39 class ArrayCollection implements Collection, Selectable
40 {
41     /**
42      * An array containing the entries of this collection.
43      *
44      * @var array
45      */
46     private $elements;
47
48     /**
49      * Initializes a new ArrayCollection.
50      *
51      * @param array $elements
52      */
53     public function __construct(array $elements = [])
54     {
55         $this->elements = $elements;
56     }
57
58     /**
59      * Creates a new instance from the specified elements.
60      *
61      * This method is provided for derived classes to specify how a new
62      * instance should be created when constructor semantics have changed.
63      *
64      * @param array $elements Elements.
65      *
66      * @return static
67      */
68     protected function createFrom(array $elements)
69     {
70         return new static($elements);
71     }
72
73     /**
74      * {@inheritDoc}
75      */
76     public function toArray()
77     {
78         return $this->elements;
79     }
80
81     /**
82      * {@inheritDoc}
83      */
84     public function first()
85     {
86         return reset($this->elements);
87     }
88
89     /**
90      * {@inheritDoc}
91      */
92     public function last()
93     {
94         return end($this->elements);
95     }
96
97     /**
98      * {@inheritDoc}
99      */
100     public function key()
101     {
102         return key($this->elements);
103     }
104
105     /**
106      * {@inheritDoc}
107      */
108     public function next()
109     {
110         return next($this->elements);
111     }
112
113     /**
114      * {@inheritDoc}
115      */
116     public function current()
117     {
118         return current($this->elements);
119     }
120
121     /**
122      * {@inheritDoc}
123      */
124     public function remove($key)
125     {
126         if ( ! isset($this->elements[$key]) && ! array_key_exists($key, $this->elements)) {
127             return null;
128         }
129
130         $removed = $this->elements[$key];
131         unset($this->elements[$key]);
132
133         return $removed;
134     }
135
136     /**
137      * {@inheritDoc}
138      */
139     public function removeElement($element)
140     {
141         $key = array_search($element, $this->elements, true);
142
143         if ($key === false) {
144             return false;
145         }
146
147         unset($this->elements[$key]);
148
149         return true;
150     }
151
152     /**
153      * Required by interface ArrayAccess.
154      *
155      * {@inheritDoc}
156      */
157     public function offsetExists($offset)
158     {
159         return $this->containsKey($offset);
160     }
161
162     /**
163      * Required by interface ArrayAccess.
164      *
165      * {@inheritDoc}
166      */
167     public function offsetGet($offset)
168     {
169         return $this->get($offset);
170     }
171
172     /**
173      * Required by interface ArrayAccess.
174      *
175      * {@inheritDoc}
176      */
177     public function offsetSet($offset, $value)
178     {
179         if ( ! isset($offset)) {
180             $this->add($value);
181             return;
182         }
183
184         $this->set($offset, $value);
185     }
186
187     /**
188      * Required by interface ArrayAccess.
189      *
190      * {@inheritDoc}
191      */
192     public function offsetUnset($offset)
193     {
194         $this->remove($offset);
195     }
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     /**
206      * {@inheritDoc}
207      */
208     public function contains($element)
209     {
210         return in_array($element, $this->elements, true);
211     }
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
224         return false;
225     }
226
227     /**
228      * {@inheritDoc}
229      */
230     public function indexOf($element)
231     {
232         return array_search($element, $this->elements, true);
233     }
234
235     /**
236      * {@inheritDoc}
237      */
238     public function get($key)
239     {
240         return $this->elements[$key] ?? null;
241     }
242
243     /**
244      * {@inheritDoc}
245      */
246     public function getKeys()
247     {
248         return array_keys($this->elements);
249     }
250
251     /**
252      * {@inheritDoc}
253      */
254     public function getValues()
255     {
256         return array_values($this->elements);
257     }
258
259     /**
260      * {@inheritDoc}
261      */
262     public function count()
263     {
264         return count($this->elements);
265     }
266
267     /**
268      * {@inheritDoc}
269      */
270     public function set($key, $value)
271     {
272         $this->elements[$key] = $value;
273     }
274
275     /**
276      * {@inheritDoc}
277      */
278     public function add($element)
279     {
280         $this->elements[] = $element;
281
282         return true;
283     }
284
285     /**
286      * {@inheritDoc}
287      */
288     public function isEmpty()
289     {
290         return empty($this->elements);
291     }
292
293     /**
294      * Required by interface IteratorAggregate.
295      *
296      * {@inheritDoc}
297      */
298     public function getIterator()
299     {
300         return new ArrayIterator($this->elements);
301     }
302
303     /**
304      * {@inheritDoc}
305      *
306      * @return static
307      */
308     public function map(Closure $func)
309     {
310         return $this->createFrom(array_map($func, $this->elements));
311     }
312
313     /**
314      * {@inheritDoc}
315      *
316      * @return static
317      */
318     public function filter(Closure $p)
319     {
320         return $this->createFrom(array_filter($this->elements, $p));
321     }
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
334         return true;
335     }
336
337     /**
338      * {@inheritDoc}
339      */
340     public function partition(Closure $p)
341     {
342         $matches = $noMatches = [];
343
344         foreach ($this->elements as $key => $element) {
345             if ($p($key, $element)) {
346                 $matches[$key] = $element;
347             } else {
348                 $noMatches[$key] = $element;
349             }
350         }
351
352         return [$this->createFrom($matches), $this->createFrom($noMatches)];
353     }
354
355     /**
356      * Returns a string representation of this object.
357      *
358      * @return string
359      */
360     public function __toString()
361     {
362         return __CLASS__ . '@' . spl_object_hash($this);
363     }
364
365     /**
366      * {@inheritDoc}
367      */
368     public function clear()
369     {
370         $this->elements = [];
371     }
372
373     /**
374      * {@inheritDoc}
375      */
376     public function slice($offset, $length = null)
377     {
378         return array_slice($this->elements, $offset, $length, true);
379     }
380
381     /**
382      * {@inheritDoc}
383      */
384     public function matching(Criteria $criteria)
385     {
386         $expr     = $criteria->getWhereExpression();
387         $filtered = $this->elements;
388
389         if ($expr) {
390             $visitor  = new ClosureExpressionVisitor();
391             $filter   = $visitor->dispatch($expr);
392             $filtered = array_filter($filtered, $filter);
393         }
394
395         if ($orderings = $criteria->getOrderings()) {
396             $next = null;
397             foreach (array_reverse($orderings) as $field => $ordering) {
398                 $next = ClosureExpressionVisitor::sortByField($field, $ordering == Criteria::DESC ? -1 : 1, $next);
399             }
400
401             uasort($filtered, $next);
402         }
403
404         $offset = $criteria->getFirstResult();
405         $length = $criteria->getMaxResults();
406
407         if ($offset || $length) {
408             $filtered = array_slice($filtered, (int)$offset, $length);
409         }
410
411         return $this->createFrom($filtered);
412     }
413 }