Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 56 |
|
0.00% |
0 / 15 |
CRAP | |
0.00% |
0 / 1 |
ResourceCollection | |
0.00% |
0 / 56 |
|
0.00% |
0 / 15 |
930 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
load | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
loadResources | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
56 | |||
addFilter | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
addTypeFilter | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
count | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
current | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
next | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
key | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
valid | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
30 | |||
rewind | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
useLimit | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isLimitReached | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
getEndReached | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
addClassFilter | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | /** |
4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License |
6 | * as published by the Free Software Foundation; under version 2 |
7 | * of the License (non-upgradable). |
8 | * |
9 | * This program is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write to the Free Software |
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | * |
18 | * Copyright (c) 2019 (original work) Open Assessment Technologies SA; |
19 | */ |
20 | |
21 | namespace oat\generis\model\resource; |
22 | |
23 | use common_persistence_SqlPersistence; |
24 | use core_kernel_classes_Class; |
25 | use Countable; |
26 | use Iterator; |
27 | use common_persistence_sql_Filter as Filter; |
28 | use oat\generis\model\OntologyAwareTrait; |
29 | use oat\generis\model\OntologyRdf; |
30 | use Zend\ServiceManager\ServiceLocatorAwareTrait; |
31 | |
32 | /** |
33 | * Collection for resources. |
34 | * |
35 | * @author Martijn Swinkels <martijn@taotesting.com> |
36 | */ |
37 | class ResourceCollection implements Iterator, Countable |
38 | { |
39 | use ServiceLocatorAwareTrait; |
40 | use OntologyAwareTrait; |
41 | |
42 | public const CACHE_SIZE = 100; |
43 | |
44 | /** |
45 | * @var string[] |
46 | */ |
47 | private $resources; |
48 | |
49 | /** |
50 | * @var int |
51 | */ |
52 | private $index = 0; |
53 | |
54 | /** |
55 | * @var Filter |
56 | */ |
57 | private $filter; |
58 | |
59 | /** |
60 | * @var bool |
61 | */ |
62 | private $endOfClass; |
63 | |
64 | /** |
65 | * @var core_kernel_classes_Class |
66 | */ |
67 | private $class; |
68 | |
69 | /** |
70 | * @var int |
71 | */ |
72 | private $cacheSize; |
73 | |
74 | /** |
75 | * @var int |
76 | */ |
77 | private $lastId = 0; |
78 | |
79 | /** |
80 | * @var bool |
81 | */ |
82 | private $classFilterSet = false; |
83 | |
84 | /** |
85 | * @var int |
86 | */ |
87 | private $limit; |
88 | |
89 | /** |
90 | * ResourceCollection constructor. |
91 | * |
92 | * @param null|string|core_kernel_classes_Class $class |
93 | * @param int $cacheSize |
94 | */ |
95 | public function __construct($class = null, $cacheSize = self::CACHE_SIZE) |
96 | { |
97 | if ($class !== null) { |
98 | $class = $this->getClass($class); |
99 | } |
100 | $this->class = $class; |
101 | $this->filter = new Filter(); |
102 | $this->cacheSize = $cacheSize; |
103 | } |
104 | |
105 | /** |
106 | * Load a collection of resources |
107 | * |
108 | * @return bool |
109 | */ |
110 | protected function load() |
111 | { |
112 | if ($this->resources !== null) { |
113 | return $this->count() > 0; |
114 | } |
115 | |
116 | $this->resources = null; |
117 | $this->index = 0; |
118 | $this->loadResources(); |
119 | |
120 | return $this->count() > 0; |
121 | } |
122 | |
123 | /** |
124 | * Load resources from storage |
125 | */ |
126 | private function loadResources() |
127 | { |
128 | if ($this->class !== null && $this->classFilterSet === false) { |
129 | $this->addClassFilter(); |
130 | } |
131 | |
132 | /** @var common_persistence_SqlPersistence $persistence */ |
133 | $persistence = $this->getModel()->getPersistence(); |
134 | $platform = $persistence->getPlatForm(); |
135 | $query = $platform->getQueryBuilder() |
136 | ->select('*') |
137 | ->from('statements') |
138 | ->andWhere('id > ' . $this->lastId) |
139 | ->orderBy('id'); |
140 | |
141 | if ($this->cacheSize > 0) { |
142 | $query->setMaxResults($this->cacheSize); |
143 | } |
144 | |
145 | $query = $this->filter->applyFilters($query); |
146 | $results = $query->execute(); |
147 | |
148 | if ($this->cacheSize > 0) { |
149 | $this->endOfClass = $results->rowCount() < $this->cacheSize; |
150 | } |
151 | |
152 | foreach ($results->fetchAll() as $result) { |
153 | $this->resources[] = $result; |
154 | $this->lastId = $result['id'] > $this->lastId ? $result['id'] : $this->lastId; |
155 | } |
156 | } |
157 | |
158 | /** |
159 | * Add a filter to filter the resources we should iterate over. |
160 | * |
161 | * @param string $column |
162 | * @param string $operator |
163 | * @param mixed $value |
164 | * @return ResourceCollection |
165 | */ |
166 | public function addFilter($column, $operator, $value) |
167 | { |
168 | $this->filter->addFilter($column, $operator, $value); |
169 | return $this; |
170 | } |
171 | |
172 | /** |
173 | * Add a type resource filter. |
174 | * |
175 | * @param string $type |
176 | * @return ResourceCollection |
177 | */ |
178 | public function addTypeFilter($type) |
179 | { |
180 | $this->filter->eq('predicate', OntologyRdf::RDF_TYPE) |
181 | ->eq('object', $type); |
182 | return $this; |
183 | } |
184 | |
185 | /** |
186 | * @inheritdoc |
187 | */ |
188 | public function count() |
189 | { |
190 | if (!is_array($this->resources) && !$this->resources instanceof Countable) { |
191 | return 0; |
192 | } |
193 | |
194 | return count($this->resources); |
195 | } |
196 | |
197 | /** |
198 | * @inheritdoc |
199 | */ |
200 | public function current() |
201 | { |
202 | return $this->resources[$this->index]; |
203 | } |
204 | |
205 | /** |
206 | * @inheritdoc |
207 | */ |
208 | public function next() |
209 | { |
210 | $this->index++; |
211 | } |
212 | |
213 | /** |
214 | * @inheritdoc |
215 | */ |
216 | public function key() |
217 | { |
218 | return $this->index; |
219 | } |
220 | |
221 | /** |
222 | * @inheritdoc |
223 | */ |
224 | public function valid() |
225 | { |
226 | if ($this->resources === null) { |
227 | return $this->load(); |
228 | } |
229 | |
230 | if ($this->endOfClass === false && !isset($this->resources[$this->index])) { |
231 | if ($this->isLimitReached()) { |
232 | $this->resources = null; |
233 | return false; |
234 | } |
235 | $this->resources = null; |
236 | return $this->load(); |
237 | } |
238 | |
239 | return isset($this->resources[$this->index]); |
240 | } |
241 | |
242 | /** |
243 | * @inheritdoc |
244 | */ |
245 | public function rewind() |
246 | { |
247 | $this->index = 0; |
248 | } |
249 | |
250 | /** |
251 | * Activate a limitation of how many resources should be processed. This is different from cache size, since it |
252 | * limits the amount of items that are processed in e.g. a foreach loop without loading remaining resources. |
253 | */ |
254 | public function useLimit() |
255 | { |
256 | $this->limit = $this->cacheSize; |
257 | } |
258 | |
259 | /** |
260 | * Check if we reached the limit of the amount of items we should process. |
261 | * |
262 | * @return bool |
263 | */ |
264 | private function isLimitReached() |
265 | { |
266 | return $this->limit !== null && $this->count() >= $this->limit; |
267 | } |
268 | |
269 | /** |
270 | * Check if the end of the current class is reached (no more records available) |
271 | * @return bool |
272 | */ |
273 | public function getEndReached() |
274 | { |
275 | return $this->endOfClass; |
276 | } |
277 | |
278 | /** |
279 | * Adds a filter for a class |
280 | */ |
281 | private function addClassFilter() |
282 | { |
283 | $this->addTypeFilter($this->class->getUri()); |
284 | $this->classFilterSet = true; |
285 | } |
286 | } |