1: <?php
2: /**
3: * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
4: * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
5: *
6: * Licensed under The MIT License
7: * For full copyright and license information, please see the LICENSE.txt
8: * Redistributions of files must retain the above copyright notice.
9: *
10: * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
11: * @link https://cakephp.org CakePHP(tm) Project
12: * @since 3.0.0
13: * @license https://opensource.org/licenses/mit-license.php MIT License
14: */
15: namespace Cake\Collection\Iterator;
16:
17: use ArrayIterator;
18: use Cake\Collection\Collection;
19: use Cake\Collection\CollectionInterface;
20: use CallbackFilterIterator;
21: use Iterator;
22:
23: /**
24: * Creates a filtered iterator from another iterator. The filtering is done by
25: * passing a callback function to each of the elements and taking them out if
26: * it does not return true.
27: */
28: class FilterIterator extends Collection
29: {
30: /**
31: * The callback used to filter the elements in this collection
32: *
33: * @var callable
34: */
35: protected $_callback;
36:
37: /**
38: * Creates a filtered iterator using the callback to determine which items are
39: * accepted or rejected.
40: *
41: * Each time the callback is executed it will receive the value of the element
42: * in the current iteration, the key of the element and the passed $items iterator
43: * as arguments, in that order.
44: *
45: * @param \Traversable|array $items The items to be filtered.
46: * @param callable $callback Callback.
47: */
48: public function __construct($items, callable $callback)
49: {
50: if (!$items instanceof Iterator) {
51: $items = new Collection($items);
52: }
53:
54: $this->_callback = $callback;
55: $wrapper = new CallbackFilterIterator($items, $callback);
56: parent::__construct($wrapper);
57: }
58:
59: /**
60: * {@inheritDoc}
61: *
62: * We perform here some strictness analysis so that the
63: * iterator logic is bypassed entirely.
64: *
65: * @return \Iterator
66: */
67: public function unwrap()
68: {
69: /** @var \IteratorIterator $filter */
70: $filter = $this->getInnerIterator();
71: $iterator = $filter->getInnerIterator();
72:
73: if ($iterator instanceof CollectionInterface) {
74: $iterator = $iterator->unwrap();
75: }
76:
77: if (get_class($iterator) !== ArrayIterator::class) {
78: return $filter;
79: }
80:
81: // ArrayIterator can be traversed strictly.
82: // Let's do that for performance gains
83:
84: $callback = $this->_callback;
85: $res = [];
86:
87: foreach ($iterator as $k => $v) {
88: if ($callback($v, $k, $iterator)) {
89: $res[$k] = $v;
90: }
91: }
92:
93: return new ArrayIterator($res);
94: }
95: }
96: