IteratorDataSource::findOne()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
3
/**
4
 * This file is part of the Cubiche package.
5
 *
6
 * Copyright (c) Cubiche
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
namespace Cubiche\Core\Collections\DataSource;
12
13
use Cubiche\Core\Comparable\ComparatorInterface;
14
use Cubiche\Core\Specification\SpecificationInterface;
15
16
/**
17
 * Iterator Data Source Class.
18
 *
19
 * @author Karel Osorio Ramírez <[email protected]>
20
 */
21
class IteratorDataSource extends DataSource
22
{
23
    /**
24
     * @var \Traversable
25
     */
26
    protected $iterator;
27
28
    /**
29
     * @var bool
30
     */
31
    private $iteratorSorted;
32
33
    /**
34
     * @param \Traversable           $iterator
35
     * @param SpecificationInterface $searchCriteria
36
     * @param ComparatorInterface    $sortCriteria
37
     * @param int                    $offset
38
     * @param int                    $length
39
     */
40
    public function __construct(
41
        \Traversable $iterator,
42
        SpecificationInterface $searchCriteria = null,
43
        ComparatorInterface $sortCriteria = null,
44
        $offset = null,
45
        $length = null
46
    ) {
47
        parent::__construct($searchCriteria, $sortCriteria, $offset, $length);
48
49
        $this->iterator = $iterator;
50
        $this->iteratorSorted = false;
51
    }
52
53
    /**
54
     * {@inheritdoc}
55
     */
56
    public function getIterator()
57
    {
58
        $this->sort();
59
60
        $count = 0;
61
        $offset = 0;
62
        foreach ($this->iterator as $item) {
63
            if (!$this->checkLenght($count)) {
64
                break;
65
            }
66
            if ($this->evaluate($item) === true) {
67
                if ($this->checkOffset($offset)) {
68
                    ++$count;
69
                    yield $item;
70
                } else {
71
                    ++$offset;
72
                }
73
            }
74
        }
75
    }
76
77
    /**
78
     * {@inheritdoc}
79
     */
80
    public function findOne()
81
    {
82
        foreach ($this->getIterator() as $item) {
83
            return $item;
84
        }
85
86
        return;
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     */
92
    public function filteredDataSource(SpecificationInterface $criteria)
93
    {
94
        if ($this->isFiltered()) {
95
            $criteria = $this->searchCriteria()->andX($criteria);
96
        }
97
98
        return new self(
99
            $this->iterator,
100
            $criteria,
101
            $this->iteratorSorted ? null : $this->sortCriteria(),
102
            $this->offset(),
103
            $this->length()
104
        );
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110
    public function slicedDataSource($offset, $length = null)
111
    {
112
        return new self(
113
            $this->iterator,
114
            $this->searchCriteria(),
115
            $this->iteratorSorted ? null : $this->sortCriteria(),
116
            $this->actualOffset($offset),
117
            $this->actualLength($offset, $length)
118
        );
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124
    public function sortedDataSource(ComparatorInterface $sortCriteria)
125
    {
126
        return new self(
127
            $this->iterator,
128
            $this->searchCriteria(),
129
            $sortCriteria,
130
            $this->offset(),
131
            $this->length()
132
        );
133
    }
134
135
    /**
136
     * {@inheritdoc}
137
     */
138
    protected function calculateCount()
139
    {
140
        return \iterator_count($this->getIterator());
141
    }
142
143
    /**
144
     * @param mixed $item
145
     *
146
     * @return bool
147
     */
148
    protected function evaluate($item)
149
    {
150
        return $this->searchCriteria() === null || $this->searchCriteria()->evaluate($item);
151
    }
152
153
    /**
154
     * @param int $offset
155
     *
156
     * @return bool
157
     */
158
    private function checkOffset($offset)
159
    {
160
        return $this->offset === null || $offset === $this->offset;
161
    }
162
163
    /**
164
     * @param int $count
165
     *
166
     * @return bool
167
     */
168
    private function checkLenght($count)
169
    {
170
        return $this->length === null || $count < $this->length;
171
    }
172
173
    private function sort()
174
    {
175
        if (!$this->iteratorSorted && $this->isSorted()) {
176
            if (!($this->iterator instanceof \ArrayIterator)) {
177
                $this->iterator = new \ArrayIterator(iterator_to_array($this->iterator));
178
            }
179
            $this->iterator->uasort(function ($a, $b) {
180
                return $this->sortCriteria()->compare($a, $b);
181
            });
182
183
            $this->iteratorSorted = true;
184
        }
185
    }
186
}
187