1<?php 2 3namespace ILIAS\BackgroundTasks\Implementation\TaskManager; 4 5use ILIAS\BackgroundTasks\Bucket; 6use ILIAS\BackgroundTasks\Exceptions\Exception; 7use ILIAS\BackgroundTasks\Implementation\Bucket\State; 8use ILIAS\BackgroundTasks\Implementation\Tasks\UserInteraction\UserInteractionRequiredException; 9use ILIAS\BackgroundTasks\Implementation\Tasks\UserInteraction\UserInteractionSkippedException; 10use ILIAS\BackgroundTasks\Implementation\Values\ThunkValue; 11use ILIAS\BackgroundTasks\Observer; 12use ILIAS\BackgroundTasks\Persistence; 13use ILIAS\BackgroundTasks\Task; 14use ILIAS\BackgroundTasks\Task\UserInteraction\Option; 15use ILIAS\BackgroundTasks\TaskManager; 16use ILIAS\BackgroundTasks\Value; 17 18/** 19 * Class BasicTaskManager 20 * 21 * @package ILIAS\BackgroundTasks\Implementation 22 * 23 * @author Oskar Truffer <ot@studer-raimann.ch> 24 * 25 * Basic Task manager. Will execute tasks immediately. 26 * 27 * Some important infos: 28 * - The bucket and its tasks are not saved into the db upon execution 29 * - The percentage and current task are not updated during execution. 30 * - The bucket and its tasks inkl. percentage and current task are only saved into the DB 31 * when a user interaction occurs. 32 * 33 */ 34abstract class BasicTaskManager implements TaskManager 35{ 36 37 /** 38 * @var Persistence 39 */ 40 protected $persistence; 41 42 43 public function __construct(Persistence $persistence) 44 { 45 $this->persistence = $persistence; 46 } 47 48 49 /** 50 * @param Task $task 51 * @param Observer $observer 52 * 53 * @return Value 54 * @throws Exception 55 */ 56 public function executeTask(Task $task, Observer $observer) 57 { 58 $observer->notifyState(State::RUNNING); 59 /** @var Value[] $values */ 60 $values = $task->getInput(); 61 $final_values = []; 62 $replace_thunk_values = false; 63 foreach ($values as $value) { 64 if (is_a($value, ThunkValue::class)) { 65 $value = $this->executeTask($value->getParentTask(), $observer); 66 $replace_thunk_values = true; 67 } 68 $final_values[] = $value; 69 } 70 71 if ($replace_thunk_values) { 72 $task->setInput($final_values); 73 } 74 75 if (is_a($task, Task\Job::class)) { 76 /** @var Task\Job $job */ 77 $job = $task; 78 $observer->notifyCurrentTask($job); 79 $value = $job->run($final_values, $observer); 80 if (!$value->getType()->isExtensionOf($job->getOutputType())) { 81 throw new Exception("The job " . $job->getType() 82 . " did state to output a value of type " 83 . $job->getOutputType() . " but outputted a value of type " 84 . $value->getType()); 85 } 86 $observer->notifyPercentage($job, 100); 87 88 return $value; 89 } 90 91 if (is_a($task, Task\UserInteraction::class)) { 92 /** @var Task\UserInteraction $userInteraction */ 93 $userInteraction = $task; 94 95 if ($userInteraction->canBeSkipped($final_values)) { 96 $observer->notifyState(State::FINISHED); 97 throw new UserInteractionSkippedException("User interaction skipped."); 98 } else { 99 $observer->notifyCurrentTask($userInteraction); 100 $observer->notifyState(State::USER_INTERACTION); 101 throw new UserInteractionRequiredException("User interaction required."); 102 } 103 } 104 105 throw new Exception("You need to execute a Job or a UserInteraction."); 106 } 107 108 109 /** 110 * Continue a task with a given option. 111 * 112 * @param Bucket $bucket 113 * @param Option $option 114 * 115 * @return mixed 116 */ 117 public function continueTask(Bucket $bucket, Option $option) 118 { 119 // We do the user interaction 120 $bucket->userInteraction($option); 121 if ($bucket->getState() != State::FINISHED) { // The job is not done after the user interaction, so we continue to run it. 122 $this->run($bucket); 123 } else { 124 $this->persistence->deleteBucket($bucket); 125 } 126 } 127 128 129 /** 130 * @inheritdoc 131 */ 132 public function quitBucket(Bucket $bucket) 133 { 134 $this->persistence->deleteBucket($bucket); 135 } 136} 137