Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 130 |
|
0.00% |
0 / 23 |
CRAP | |
0.00% |
0 / 1 |
TaskLog | |
0.00% |
0 / 130 |
|
0.00% |
0 / 23 |
3660 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
getBroker | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
isRds | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
createContainer | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
add | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
setStatus | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 | |||
getStatus | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
setReport | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
getReport | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
updateParent | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
132 | |||
search | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getDataTablePayload | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getById | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
getByIdAndUser | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
findAvailableByUser | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
getStats | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
archive | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
archiveCollection | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
42 | |||
linkTaskToCategory | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 | |||
getCategoryForTask | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
getTaskCategories | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
validateStatus | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
6 | |||
assertCanArchive | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
12 |
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) 2017 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT); |
19 | * |
20 | */ |
21 | |
22 | namespace oat\taoTaskQueue\model; |
23 | |
24 | use common_report_Report as Report; |
25 | use oat\oatbox\event\EventManager; |
26 | use oat\oatbox\service\ConfigurableService; |
27 | use oat\taoTaskQueue\model\Entity\TaskLogEntity; |
28 | use oat\taoTaskQueue\model\Entity\TaskLogEntityInterface; |
29 | use oat\taoTaskQueue\model\Event\TaskLogArchivedEvent; |
30 | use oat\taoTaskQueue\model\Task\TaskInterface; |
31 | use oat\taoTaskQueue\model\TaskLog\DataTablePayload; |
32 | use oat\taoTaskQueue\model\TaskLog\TaskLogCollection; |
33 | use oat\taoTaskQueue\model\TaskLog\TaskLogCollectionInterface; |
34 | use oat\taoTaskQueue\model\TaskLog\TaskLogFilter; |
35 | use oat\taoTaskQueue\model\TaskLogBroker\RdsTaskLogBroker; |
36 | use oat\taoTaskQueue\model\TaskLogBroker\TaskLogBrokerInterface; |
37 | use oat\oatbox\log\LoggerAwareTrait; |
38 | |
39 | /** |
40 | * Managing task logs: |
41 | * - storing every information for a task like dates, status changes, reports etc. |
42 | * - each task has one record in the container identified by its id |
43 | * |
44 | * @deprecated Use \oat\tao\model\taskQueue\TaskLog |
45 | * |
46 | * @author Gyula Szucs <gyula@taotesting.com> |
47 | */ |
48 | class TaskLog extends ConfigurableService implements TaskLogInterface |
49 | { |
50 | use LoggerAwareTrait; |
51 | |
52 | /** |
53 | * @var TaskLogBrokerInterface |
54 | */ |
55 | private $broker; |
56 | |
57 | /** |
58 | * TaskLog constructor. |
59 | * |
60 | * @param array $options |
61 | */ |
62 | public function __construct(array $options) |
63 | { |
64 | parent::__construct($options); |
65 | |
66 | if (!$this->hasOption(self::OPTION_TASK_LOG_BROKER) || empty($this->getOption(self::OPTION_TASK_LOG_BROKER))) { |
67 | throw new \InvalidArgumentException("Task Log Broker service needs to be set."); |
68 | } |
69 | } |
70 | |
71 | /** |
72 | * Gets the task log broker. It will be created if it has not been initialized. |
73 | * |
74 | * @return TaskLogBrokerInterface |
75 | */ |
76 | public function getBroker() |
77 | { |
78 | if (is_null($this->broker)) { |
79 | $this->broker = $this->getOption(self::OPTION_TASK_LOG_BROKER); |
80 | $this->broker->setServiceLocator($this->getServiceLocator()); |
81 | } |
82 | |
83 | return $this->broker; |
84 | } |
85 | |
86 | /** |
87 | * @inheritdoc |
88 | */ |
89 | public function isRds() |
90 | { |
91 | return $this->getBroker() instanceof RdsTaskLogBroker; |
92 | } |
93 | |
94 | /** |
95 | * @inheritdoc |
96 | */ |
97 | public function createContainer() |
98 | { |
99 | $this->getBroker()->createContainer(); |
100 | } |
101 | |
102 | /** |
103 | * @inheritdoc |
104 | */ |
105 | public function add(TaskInterface $task, $status, $label = null) |
106 | { |
107 | try { |
108 | $this->validateStatus($status); |
109 | |
110 | $this->getBroker()->add($task, $status, $label); |
111 | } catch (\Exception $e) { |
112 | $this->logError('Adding result for task ' . $task->getId() . ' failed with MSG: ' . $e->getMessage()); |
113 | } |
114 | |
115 | return $this; |
116 | } |
117 | |
118 | /** |
119 | * @inheritdoc |
120 | */ |
121 | public function setStatus($taskId, $newStatus, $prevStatus = null) |
122 | { |
123 | try { |
124 | $this->validateStatus($newStatus); |
125 | |
126 | if (!is_null($prevStatus)) { |
127 | $this->validateStatus($prevStatus); |
128 | } |
129 | |
130 | return $this->getBroker()->updateStatus($taskId, $newStatus, $prevStatus); |
131 | } catch (\Exception $e) { |
132 | $this->logError('Setting the status for task ' . $taskId . ' failed with MSG: ' . $e->getMessage()); |
133 | } |
134 | |
135 | return 0; |
136 | } |
137 | |
138 | /** |
139 | * @inheritdoc |
140 | */ |
141 | public function getStatus($taskId) |
142 | { |
143 | try { |
144 | return $this->getBroker()->getStatus($taskId); |
145 | } catch (\Exception $e) { |
146 | $this->logError('Getting status for task ' . $taskId . ' failed with MSG: ' . $e->getMessage()); |
147 | } |
148 | |
149 | return self::STATUS_UNKNOWN; |
150 | } |
151 | |
152 | /** |
153 | * @inheritdoc |
154 | */ |
155 | public function setReport($taskId, Report $report, $newStatus = null) |
156 | { |
157 | try { |
158 | $this->validateStatus($newStatus); |
159 | |
160 | if (!$this->getBroker()->addReport($taskId, $report, $newStatus)) { |
161 | throw new \RuntimeException("Report is not saved."); |
162 | } |
163 | } catch (\Exception $e) { |
164 | $this->logError('Setting report for item ' . $taskId . ' failed with MSG: ' . $e->getMessage()); |
165 | } |
166 | |
167 | return $this; |
168 | } |
169 | |
170 | /** |
171 | * @inheritdoc |
172 | */ |
173 | public function getReport($taskId) |
174 | { |
175 | try { |
176 | return $this->getBroker()->getReport($taskId); |
177 | } catch (\Exception $e) { |
178 | $this->logError('Getting report for task ' . $taskId . ' failed with MSG: ' . $e->getMessage()); |
179 | } |
180 | |
181 | return null; |
182 | } |
183 | |
184 | /** |
185 | * @inheritdoc |
186 | */ |
187 | public function updateParent($parentTaskId) |
188 | { |
189 | try { |
190 | $filter = (new TaskLogFilter()) |
191 | ->eq(TaskLogBrokerInterface::COLUMN_PARENT_ID, $parentTaskId) |
192 | ->neq(TaskLogBrokerInterface::COLUMN_STATUS, TaskLogInterface::STATUS_ARCHIVED); |
193 | |
194 | $children = $this->search($filter); |
195 | if (!$children->isEmpty()) { |
196 | $processedOnes = 0; |
197 | $failedOnes = 0; |
198 | foreach ($children as $child) { |
199 | // no need update if any child is still in progress |
200 | if ($child->getStatus()->isInProgress() || $child->getStatus()->isCreated()) { |
201 | break; |
202 | } |
203 | |
204 | if ($child->getStatus()->isCompleted() || $child->getStatus()->isFailed()) { |
205 | $processedOnes++; |
206 | } |
207 | |
208 | if ($child->getStatus()->isFailed()) { |
209 | $failedOnes++; |
210 | } |
211 | } |
212 | |
213 | // we can update the parent status if every child has been processed |
214 | if ($processedOnes == $children->count()) { |
215 | $this->setStatus($parentTaskId, $failedOnes > 0 ? self::STATUS_FAILED : self::STATUS_COMPLETED); |
216 | } |
217 | } |
218 | } catch (\Exception $e) { |
219 | $this->logError('Updating parent task "' . $parentTaskId . '"" failed with MSG: ' . $e->getMessage()); |
220 | } |
221 | |
222 | return $this; |
223 | } |
224 | |
225 | /** |
226 | * @inheritdoc |
227 | */ |
228 | public function search(TaskLogFilter $filter) |
229 | { |
230 | return $this->getBroker()->search($filter); |
231 | } |
232 | |
233 | /** |
234 | * @inheritdoc |
235 | */ |
236 | public function getDataTablePayload(TaskLogFilter $filter) |
237 | { |
238 | return new DataTablePayload($filter, $this->getBroker()); |
239 | } |
240 | |
241 | /** |
242 | * @inheritdoc |
243 | */ |
244 | public function getById($taskId) |
245 | { |
246 | $filter = (new TaskLogFilter()) |
247 | ->eq(TaskLogBrokerInterface::COLUMN_ID, $taskId); |
248 | |
249 | $collection = $this->search($filter); |
250 | |
251 | if ($collection->isEmpty()) { |
252 | throw new \common_exception_NotFound('Task log for task "' . $taskId . '" not found'); |
253 | } |
254 | |
255 | return $collection->first(); |
256 | } |
257 | |
258 | /** |
259 | * @inheritdoc |
260 | */ |
261 | public function getByIdAndUser($taskId, $userId) |
262 | { |
263 | $filter = (new TaskLogFilter()) |
264 | ->addAvailableFilters($userId) |
265 | ->eq(TaskLogBrokerInterface::COLUMN_ID, $taskId); |
266 | |
267 | $collection = $this->search($filter); |
268 | |
269 | if ($collection->isEmpty()) { |
270 | throw new \common_exception_NotFound('Task log for task "' . $taskId . '" not found'); |
271 | } |
272 | |
273 | return $collection->first(); |
274 | } |
275 | |
276 | /** |
277 | * @inheritdoc |
278 | */ |
279 | public function findAvailableByUser($userId, $limit = null, $offset = null) |
280 | { |
281 | $filter = (new TaskLogFilter()) |
282 | ->addAvailableFilters($userId) |
283 | ->setLimit(is_null($limit) ? self::DEFAULT_LIMIT : $limit) |
284 | ->setOffset(is_null($offset) ? 0 : $offset); |
285 | |
286 | return $this->getBroker()->search($filter); |
287 | } |
288 | |
289 | /** |
290 | * @inheritdoc |
291 | */ |
292 | public function getStats($userId) |
293 | { |
294 | $filter = (new TaskLogFilter()) |
295 | ->addAvailableFilters($userId); |
296 | |
297 | return $this->getBroker()->getStats($filter); |
298 | } |
299 | |
300 | /** |
301 | * @inheritdoc |
302 | */ |
303 | public function archive(TaskLogEntity $entity, $forceArchive = false) |
304 | { |
305 | $this->assertCanArchive($entity, $forceArchive); |
306 | |
307 | $isArchived = $this->getBroker()->archive($entity); |
308 | |
309 | if ($isArchived) { |
310 | $this->getServiceManager()->get(EventManager::SERVICE_ID) |
311 | ->trigger(new TaskLogArchivedEvent($entity, $forceArchive)); |
312 | } |
313 | |
314 | return $isArchived; |
315 | } |
316 | |
317 | /** |
318 | * @param TaskLogCollectionInterface $collection |
319 | * @param bool $forceArchive |
320 | * @return bool |
321 | */ |
322 | public function archiveCollection(TaskLogCollectionInterface $collection, $forceArchive = false) |
323 | { |
324 | $tasksAbleToArchive = []; |
325 | |
326 | /** @var TaskLogEntityInterface $entity */ |
327 | foreach ($collection as $entity) { |
328 | try { |
329 | $this->assertCanArchive($entity, $forceArchive); |
330 | $tasksAbleToArchive[] = $entity; |
331 | } catch (\Exception $exception) { |
332 | $this->logDebug('Task Log: ' . $entity->getId() . ' cannot be archived.'); |
333 | } |
334 | } |
335 | |
336 | $collectionArchived = $this->getBroker()->archiveCollection(new TaskLogCollection($tasksAbleToArchive)); |
337 | |
338 | if ($collectionArchived) { |
339 | foreach ($tasksAbleToArchive as $entity) { |
340 | $this->getServiceManager() |
341 | ->get(EventManager::SERVICE_ID) |
342 | ->trigger(new TaskLogArchivedEvent($entity, $forceArchive)); |
343 | } |
344 | } |
345 | |
346 | return count($collection) === count($tasksAbleToArchive) && $collectionArchived; |
347 | } |
348 | |
349 | /** |
350 | * @inheritdoc |
351 | */ |
352 | public function linkTaskToCategory($taskName, $category) |
353 | { |
354 | if (is_object($taskName)) { |
355 | $taskName = get_class($taskName); |
356 | } |
357 | |
358 | if (!in_array($category, $this->getTaskCategories())) { |
359 | throw new \InvalidArgumentException('Category "' . $category . '" is not a valid category.'); |
360 | } |
361 | |
362 | $associations = (array) $this->getOption(self::OPTION_TASK_TO_CATEGORY_ASSOCIATIONS); |
363 | |
364 | $associations[ (string) $taskName ] = $category; |
365 | |
366 | $this->setOption(self::OPTION_TASK_TO_CATEGORY_ASSOCIATIONS, $associations); |
367 | } |
368 | |
369 | /** |
370 | * @inheritdoc |
371 | */ |
372 | public function getCategoryForTask($taskName) |
373 | { |
374 | if (is_object($taskName)) { |
375 | $taskName = get_class($taskName); |
376 | } |
377 | |
378 | $associations = (array) $this->getOption(self::OPTION_TASK_TO_CATEGORY_ASSOCIATIONS); |
379 | |
380 | if (array_key_exists($taskName, $associations)) { |
381 | return $associations[$taskName]; |
382 | } |
383 | |
384 | return self::CATEGORY_UNKNOWN; |
385 | } |
386 | |
387 | /** |
388 | * @return array |
389 | */ |
390 | public function getTaskCategories() |
391 | { |
392 | return [ |
393 | self::CATEGORY_CREATE, |
394 | self::CATEGORY_UPDATE, |
395 | self::CATEGORY_DELETE, |
396 | self::CATEGORY_IMPORT, |
397 | self::CATEGORY_EXPORT, |
398 | self::CATEGORY_DELIVERY_COMPILATION, |
399 | ]; |
400 | } |
401 | |
402 | /** |
403 | * @param string $status |
404 | */ |
405 | protected function validateStatus($status) |
406 | { |
407 | $statuses = [ |
408 | self::STATUS_ENQUEUED, |
409 | self::STATUS_DEQUEUED, |
410 | self::STATUS_RUNNING, |
411 | self::STATUS_CHILD_RUNNING, |
412 | self::STATUS_COMPLETED, |
413 | self::STATUS_FAILED, |
414 | self::STATUS_ARCHIVED |
415 | ]; |
416 | |
417 | if (!in_array($status, $statuses)) { |
418 | throw new \InvalidArgumentException('Status "' . $status . '"" is not a valid task queue status.'); |
419 | } |
420 | } |
421 | |
422 | /** |
423 | * @param TaskLogEntityInterface $entity |
424 | * @param $forceArchive |
425 | * @throws \Exception |
426 | */ |
427 | protected function assertCanArchive($entity, $forceArchive) |
428 | { |
429 | if ($entity->getStatus()->isInProgress() && $forceArchive === false) { |
430 | throw new \Exception('Task cannot be archived because it is in progress.'); |
431 | } |
432 | } |
433 | } |