Rajout de doctrine/orm
[zf2.biz/galerie.git] / vendor / doctrine / common / 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 Closure, ArrayIterator;
23 use Doctrine\Common\Collections\Expr\Expression;
24 use Doctrine\Common\Collections\Expr\ClosureExpressionVisitor;
25
26 /**
27  * An ArrayCollection is a Collection implementation that wraps a regular PHP array.
28  *
29  * @since   2.0
30  * @author  Guilherme Blanco <guilhermeblanco@hotmail.com>
31  * @author  Jonathan Wage <jonwage@gmail.com>
32  * @author  Roman Borschel <roman@code-factory.org>
33  */
34 class ArrayCollection implements Collection, Selectable
35 {
36     /**
37      * An array containing the entries of this collection.
38      *
39      * @var array
40      */
41     private $_elements;
42
43     /**
44      * Initializes a new ArrayCollection.
45      *
46      * @param array $elements
47      */
48     public function __construct(array $elements = array())
49     {
50         $this->_elements = $elements;
51     }
52
53     /**
54      * Gets the PHP array representation of this collection.
55      *
56      * @return array The PHP array representation of this collection.
57      */
58     public function toArray()
59     {
60         return $this->_elements;
61     }
62
63     /**
64      * Sets the internal iterator to the first element in the collection and
65      * returns this element.
66      *
67      * @return mixed
68      */
69     public function first()
70     {
71         return reset($this->_elements);
72     }
73
74     /**
75      * Sets the internal iterator to the last element in the collection and
76      * returns this element.
77      *
78      * @return mixed
79      */
80     public function last()
81     {
82         return end($this->_elements);
83     }
84
85     /**
86      * Gets the current key/index at the current internal iterator position.
87      *
88      * @return mixed
89      */
90     public function key()
91     {
92         return key($this->_elements);
93     }
94
95     /**
96      * Moves the internal iterator position to the next element.
97      *
98      * @return mixed
99      */
100     public function next()
101     {
102         return next($this->_elements);
103     }
104
105     /**
106      * Gets the element of the collection at the current internal iterator position.
107      *
108      * @return mixed
109      */
110     public function current()
111     {
112         return current($this->_elements);
113     }
114
115     /**
116      * Removes an element with a specific key/index from the collection.
117      *
118      * @param mixed $key
119      * @return mixed The removed element or NULL, if no element exists for the given key.
120      */
121     public function remove($key)
122     {
123         if (isset($this->_elements[$key])) {
124             $removed = $this->_elements[$key];
125             unset($this->_elements[$key]);
126
127             return $removed;
128         }
129
130         return null;
131     }
132
133     /**
134      * Removes the specified element from the collection, if it is found.
135      *
136      * @param mixed $element The element to remove.
137      * @return boolean TRUE if this collection contained the specified element, FALSE otherwise.
138      */
139     public function removeElement($element)
140     {
141         $key = array_search($element, $this->_elements, true);
142
143         if ($key !== false) {
144             unset($this->_elements[$key]);
145
146             return true;
147         }
148
149         return false;
150     }
151
152     /**
153      * ArrayAccess implementation of offsetExists()
154      *
155      * @see containsKey()
156      *
157      * @param mixed $offset
158      * @return bool
159      */
160     public function offsetExists($offset)
161     {
162         return $this->containsKey($offset);
163     }
164
165     /**
166      * ArrayAccess implementation of offsetGet()
167      *
168      * @see get()
169      *
170      * @param mixed $offset
171      * @return mixed
172      */
173     public function offsetGet($offset)
174     {
175         return $this->get($offset);
176     }
177
178     /**
179      * ArrayAccess implementation of offsetSet()
180      *
181      * @see add()
182      * @see set()
183      *
184      * @param mixed $offset
185      * @param mixed $value
186      * @return bool
187      */
188     public function offsetSet($offset, $value)
189     {
190         if ( ! isset($offset)) {
191             return $this->add($value);
192         }
193         return $this->set($offset, $value);
194     }
195
196     /**
197      * ArrayAccess implementation of offsetUnset()
198      *
199      * @see remove()
200      *
201      * @param mixed $offset
202      * @return mixed
203      */
204     public function offsetUnset($offset)
205     {
206         return $this->remove($offset);
207     }
208
209     /**
210      * Checks whether the collection contains a specific key/index.
211      *
212      * @param mixed $key The key to check for.
213      * @return boolean TRUE if the given key/index exists, FALSE otherwise.
214      */
215     public function containsKey($key)
216     {
217         return isset($this->_elements[$key]);
218     }
219
220     /**
221      * Checks whether the given element is contained in the collection.
222      * Only element values are compared, not keys. The comparison of two elements
223      * is strict, that means not only the value but also the type must match.
224      * For objects this means reference equality.
225      *
226      * @param mixed $element
227      * @return boolean TRUE if the given element is contained in the collection,
228      *          FALSE otherwise.
229      */
230     public function contains($element)
231     {
232         foreach ($this->_elements as $collectionElement) {
233             if ($element === $collectionElement) {
234                 return true;
235             }
236         }
237
238         return false;
239     }
240
241     /**
242      * Tests for the existence of an element that satisfies the given predicate.
243      *
244      * @param Closure $p The predicate.
245      * @return boolean TRUE if the predicate is TRUE for at least one element, FALSE otherwise.
246      */
247     public function exists(Closure $p)
248     {
249         foreach ($this->_elements as $key => $element) {
250             if ($p($key, $element)) {
251                 return true;
252             }
253         }
254         return false;
255     }
256
257     /**
258      * Searches for a given element and, if found, returns the corresponding key/index
259      * of that element. The comparison of two elements is strict, that means not
260      * only the value but also the type must match.
261      * For objects this means reference equality.
262      *
263      * @param mixed $element The element to search for.
264      * @return mixed The key/index of the element or FALSE if the element was not found.
265      */
266     public function indexOf($element)
267     {
268         return array_search($element, $this->_elements, true);
269     }
270
271     /**
272      * Gets the element with the given key/index.
273      *
274      * @param mixed $key The key.
275      * @return mixed The element or NULL, if no element exists for the given key.
276      */
277     public function get($key)
278     {
279         if (isset($this->_elements[$key])) {
280             return $this->_elements[$key];
281         }
282         return null;
283     }
284
285     /**
286      * Gets all keys/indexes of the collection elements.
287      *
288      * @return array
289      */
290     public function getKeys()
291     {
292         return array_keys($this->_elements);
293     }
294
295     /**
296      * Gets all elements.
297      *
298      * @return array
299      */
300     public function getValues()
301     {
302         return array_values($this->_elements);
303     }
304
305     /**
306      * Returns the number of elements in the collection.
307      *
308      * Implementation of the Countable interface.
309      *
310      * @return integer The number of elements in the collection.
311      */
312     public function count()
313     {
314         return count($this->_elements);
315     }
316
317     /**
318      * Adds/sets an element in the collection at the index / with the specified key.
319      *
320      * When the collection is a Map this is like put(key,value)/add(key,value).
321      * When the collection is a List this is like add(position,value).
322      *
323      * @param mixed $key
324      * @param mixed $value
325      */
326     public function set($key, $value)
327     {
328         $this->_elements[$key] = $value;
329     }
330
331     /**
332      * Adds an element to the collection.
333      *
334      * @param mixed $value
335      * @return boolean Always TRUE.
336      */
337     public function add($value)
338     {
339         $this->_elements[] = $value;
340         return true;
341     }
342
343     /**
344      * Checks whether the collection is empty.
345      *
346      * Note: This is preferable over count() == 0.
347      *
348      * @return boolean TRUE if the collection is empty, FALSE otherwise.
349      */
350     public function isEmpty()
351     {
352         return ! $this->_elements;
353     }
354
355     /**
356      * Gets an iterator for iterating over the elements in the collection.
357      *
358      * @return ArrayIterator
359      */
360     public function getIterator()
361     {
362         return new ArrayIterator($this->_elements);
363     }
364
365     /**
366      * Applies the given function to each element in the collection and returns
367      * a new collection with the elements returned by the function.
368      *
369      * @param Closure $func
370      * @return Collection
371      */
372     public function map(Closure $func)
373     {
374         return new static(array_map($func, $this->_elements));
375     }
376
377     /**
378      * Returns all the elements of this collection that satisfy the predicate p.
379      * The order of the elements is preserved.
380      *
381      * @param Closure $p The predicate used for filtering.
382      * @return Collection A collection with the results of the filter operation.
383      */
384     public function filter(Closure $p)
385     {
386         return new static(array_filter($this->_elements, $p));
387     }
388
389     /**
390      * Applies the given predicate p to all elements of this collection,
391      * returning true, if the predicate yields true for all elements.
392      *
393      * @param Closure $p The predicate.
394      * @return boolean TRUE, if the predicate yields TRUE for all elements, FALSE otherwise.
395      */
396     public function forAll(Closure $p)
397     {
398         foreach ($this->_elements as $key => $element) {
399             if ( ! $p($key, $element)) {
400                 return false;
401             }
402         }
403
404         return true;
405     }
406
407     /**
408      * Partitions this collection in two collections according to a predicate.
409      * Keys are preserved in the resulting collections.
410      *
411      * @param Closure $p The predicate on which to partition.
412      * @return array An array with two elements. The first element contains the collection
413      *               of elements where the predicate returned TRUE, the second element
414      *               contains the collection of elements where the predicate returned FALSE.
415      */
416     public function partition(Closure $p)
417     {
418         $coll1 = $coll2 = array();
419         foreach ($this->_elements as $key => $element) {
420             if ($p($key, $element)) {
421                 $coll1[$key] = $element;
422             } else {
423                 $coll2[$key] = $element;
424             }
425         }
426         return array(new static($coll1), new static($coll2));
427     }
428
429     /**
430      * Returns a string representation of this object.
431      *
432      * @return string
433      */
434     public function __toString()
435     {
436         return __CLASS__ . '@' . spl_object_hash($this);
437     }
438
439     /**
440      * Clears the collection.
441      */
442     public function clear()
443     {
444         $this->_elements = array();
445     }
446
447     /**
448      * Extract a slice of $length elements starting at position $offset from the Collection.
449      *
450      * If $length is null it returns all elements from $offset to the end of the Collection.
451      * Keys have to be preserved by this method. Calling this method will only return the
452      * selected slice and NOT change the elements contained in the collection slice is called on.
453      *
454      * @param int $offset
455      * @param int $length
456      * @return array
457      */
458     public function slice($offset, $length = null)
459     {
460         return array_slice($this->_elements, $offset, $length, true);
461     }
462
463     /**
464      * Select all elements from a selectable that match the criteria and
465      * return a new collection containing these elements.
466      *
467      * @param  Criteria $criteria
468      * @return Collection
469      */
470     public function matching(Criteria $criteria)
471     {
472         $expr     = $criteria->getWhereExpression();
473         $filtered = $this->_elements;
474
475         if ($expr) {
476             $visitor  = new ClosureExpressionVisitor();
477             $filter   = $visitor->dispatch($expr);
478             $filtered = array_filter($filtered, $filter);
479         }
480
481         if ($orderings = $criteria->getOrderings()) {
482             $next = null;
483             foreach (array_reverse($orderings) as $field => $ordering) {
484                 $next = ClosureExpressionVisitor::sortByField($field, $ordering == 'DESC' ? -1 : 1, $next);
485             }
486
487             usort($filtered, $next);
488         }
489
490         $offset = $criteria->getFirstResult();
491         $length = $criteria->getMaxResults();
492
493         if ($offset || $length) {
494             $filtered = array_slice($filtered, (int)$offset, $length);
495         }
496
497         return new static($filtered);
498     }
499 }
500