Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 73 |
|
0.00% |
0 / 11 |
CRAP | |
0.00% |
0 / 1 |
ResultIndexIterator | |
0.00% |
0 / 73 |
|
0.00% |
0 / 11 |
552 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
rewind | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
current | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
key | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
next | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
30 | |||
valid | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
ensureNotEmpty | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
ensureValidResult | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
12 | |||
load | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
20 | |||
createDocument | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
2 | |||
getIndexDocumentBuilder | |
0.00% |
0 / 1 |
|
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) 2018 (original work) Open Assessment Technologies SA; |
19 | */ |
20 | |
21 | namespace oat\taoOutcomeUi\model\search; |
22 | |
23 | use oat\tao\helpers\UserHelper; |
24 | use oat\tao\model\search\index\DocumentBuilder\IndexDocumentBuilderInterface; |
25 | use oat\tao\model\search\index\IndexDocument; |
26 | use oat\taoDelivery\model\execution\DeliveryExecutionInterface; |
27 | use oat\taoDelivery\model\execution\ServiceProxy; |
28 | use oat\taoDelivery\model\execution\DeliveryExecution; |
29 | use oat\taoResultServer\models\classes\ResultServerService; |
30 | use oat\taoResultServer\models\classes\ResultService; |
31 | use Slim\Exception\NotFoundException; |
32 | use Zend\ServiceManager\ServiceLocatorAwareTrait; |
33 | use Zend\ServiceManager\ServiceLocatorInterface; |
34 | |
35 | class ResultIndexIterator implements \Iterator |
36 | { |
37 | use ServiceLocatorAwareTrait; |
38 | |
39 | public const CACHE_SIZE = 100; |
40 | |
41 | private $resourceIterator; |
42 | |
43 | /** @var ResultServerService */ |
44 | private $resultService; |
45 | |
46 | /** |
47 | * Id of the current instance |
48 | * |
49 | * @var int |
50 | */ |
51 | private $currentInstance = 0; |
52 | |
53 | /** |
54 | * List of resource uris currently being iterated over |
55 | * |
56 | * @var array |
57 | */ |
58 | private $instanceCache = null; |
59 | |
60 | /** |
61 | * Indicater whenever the end of the current cache is also the end of the current class |
62 | * |
63 | * @var boolean |
64 | */ |
65 | private $endOfResource = false; |
66 | |
67 | /** |
68 | * Whenever we already moved the pointer, used to prevent unnecessary rewinds |
69 | * |
70 | * @var boolean |
71 | */ |
72 | private $unmoved = true; |
73 | |
74 | /** |
75 | * Constructor of the iterator expecting a class or classes as argument |
76 | * |
77 | * @param mixed $classes array/instance of class(es) to iterate over |
78 | * @param ServiceLocatorInterface $serviceLocator |
79 | */ |
80 | public function __construct($classes, ServiceLocatorInterface $serviceLocator) |
81 | { |
82 | $this->setServiceLocator($serviceLocator); |
83 | $this->resourceIterator = new \core_kernel_classes_ResourceIterator($classes); |
84 | /** @var ResultServerService $resultService */ |
85 | $this->resultService = $this->getServiceLocator()->get(ResultServerService::SERVICE_ID); |
86 | |
87 | $this->ensureNotEmpty(); |
88 | $this->ensureValidResult(); |
89 | } |
90 | |
91 | /** |
92 | * (non-PHPdoc) |
93 | * @see Iterator::rewind() |
94 | */ |
95 | public function rewind() |
96 | { |
97 | if (!$this->unmoved) { |
98 | $this->resourceIterator->rewind(); |
99 | $this->ensureNotEmpty(); |
100 | $this->unmoved = true; |
101 | } |
102 | } |
103 | |
104 | /** |
105 | * (non-PHPdoc) |
106 | * @see Iterator::current() |
107 | */ |
108 | public function current() |
109 | { |
110 | $deliveryExecution = ServiceProxy::singleton()->getDeliveryExecution( |
111 | $this->instanceCache[$this->currentInstance] |
112 | ); |
113 | |
114 | return $this->createDocument($deliveryExecution); |
115 | } |
116 | |
117 | /** |
118 | * (non-PHPdoc) |
119 | * @see Iterator::key() |
120 | */ |
121 | public function key() |
122 | { |
123 | return $this->resourceIterator->key() . '#' . $this->currentInstance; |
124 | } |
125 | |
126 | /** |
127 | * (non-PHPdoc) |
128 | * @see Iterator::next() |
129 | */ |
130 | public function next() |
131 | { |
132 | $this->unmoved = false; |
133 | if ($this->valid()) { |
134 | $this->currentInstance++; |
135 | if (!isset($this->instanceCache[$this->currentInstance])) { |
136 | // try to load next block (unless we know it's empty) |
137 | $remainingInstances = !$this->endOfResource |
138 | && $this->load($this->resourceIterator->current(), $this->currentInstance); |
139 | |
140 | // endOfClass or failed loading |
141 | if (!$remainingInstances) { |
142 | $this->resourceIterator->next(); |
143 | $this->ensureNotEmpty(); |
144 | } |
145 | } |
146 | $this->ensureValidResult(); |
147 | } |
148 | } |
149 | |
150 | /** |
151 | * While there are remaining classes there are instances to load |
152 | * |
153 | * (non-PHPdoc) |
154 | * @see Iterator::valid() |
155 | */ |
156 | public function valid() |
157 | { |
158 | return $this->resourceIterator->valid(); |
159 | } |
160 | |
161 | // Helpers |
162 | |
163 | /** |
164 | * Ensure the class iterator is pointin to a non empty class |
165 | * Loads the first resource block to test this |
166 | */ |
167 | protected function ensureNotEmpty() |
168 | { |
169 | $this->currentInstance = 0; |
170 | while ($this->resourceIterator->valid() && !$this->load($this->resourceIterator->current(), 0)) { |
171 | $this->resourceIterator->next(); |
172 | } |
173 | } |
174 | |
175 | /** |
176 | * Ensure the current item is valid result |
177 | */ |
178 | protected function ensureValidResult() |
179 | { |
180 | try { |
181 | $deliveryExecution = ServiceProxy::singleton()->getDeliveryExecution( |
182 | $this->instanceCache[$this->currentInstance] |
183 | ); |
184 | $deliveryExecution->getDelivery(); |
185 | } catch (\common_exception_NotFound $e) { |
186 | $message = 'Skip result ' . $deliveryExecution->getIdentifier() . ' with message ' . $e->getMessage(); |
187 | \common_Logger::e($message); |
188 | $this->next(); |
189 | } catch (\Exception $e) { |
190 | \common_Logger::e($e->getMessage()); |
191 | $this->next(); |
192 | } |
193 | } |
194 | |
195 | /** |
196 | * @param \core_kernel_classes_Resource $delivery |
197 | * @param $offset |
198 | * @return bool |
199 | * @throws \common_exception_Error |
200 | */ |
201 | protected function load(\core_kernel_classes_Resource $delivery, $offset) |
202 | { |
203 | |
204 | $options = [ |
205 | 'recursive' => true, |
206 | 'offset' => $offset, |
207 | 'limit' => self::CACHE_SIZE |
208 | ]; |
209 | |
210 | $resultsImplementation = $this->resultService->getResultStorage(null); |
211 | |
212 | $this->instanceCache = []; |
213 | $results = $resultsImplementation->getResultByDelivery([$delivery->getUri()], $options); |
214 | foreach ($results as $result) { |
215 | $id = isset($result['deliveryResultIdentifier']) ? $result['deliveryResultIdentifier'] : null; |
216 | if ($id) { |
217 | $this->instanceCache[$offset] = $id; |
218 | $offset++; |
219 | } |
220 | } |
221 | |
222 | $this->endOfResource = count($results) < self::CACHE_SIZE; |
223 | |
224 | return count($results) > 0; |
225 | } |
226 | |
227 | /** |
228 | * @param DeliveryExecution $execution |
229 | * @return IndexDocument |
230 | * @throws \common_Exception |
231 | * @throws \common_exception_NotFound |
232 | * @throws \oat\oatbox\extension\script\MissingOptionException |
233 | */ |
234 | protected function createDocument(DeliveryExecution $execution) |
235 | { |
236 | /** @var ResultCustomFieldsService $customFieldService */ |
237 | $customFieldService = $this->getServiceLocator()->get(ResultCustomFieldsService::SERVICE_ID); |
238 | $customBody = $customFieldService->getCustomFields($execution); |
239 | |
240 | $user = UserHelper::getUser($execution->getUserIdentifier()); |
241 | $userName = UserHelper::getUserName($user, true); |
242 | |
243 | $body = [ |
244 | 'label' => $execution->getLabel(), |
245 | ResultsWatcher::INDEX_DELIVERY => $execution->getDelivery()->getUri(), |
246 | 'type' => ResultService::DELIVERY_RESULT_CLASS_URI, |
247 | ResultsWatcher::INDEX_TEST_TAKER => $user->getIdentifier(), |
248 | ResultsWatcher::INDEX_TEST_TAKER_NAME => $userName, |
249 | ResultsWatcher::INDEX_DELIVERY_EXECUTION => $execution->getIdentifier(), |
250 | ]; |
251 | |
252 | $body = array_merge($body, $customBody); |
253 | $document = [ |
254 | 'id' => $execution->getIdentifier(), |
255 | 'body' => $body |
256 | ]; |
257 | |
258 | return $this->getIndexDocumentBuilder()->createDocumentFromArray($document); |
259 | } |
260 | |
261 | private function getIndexDocumentBuilder(): IndexDocumentBuilderInterface |
262 | { |
263 | return $this->getServiceLocator()->getContainer()->get(IndexDocumentBuilderInterface::class); |
264 | } |
265 | } |