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