From 48f890274a18fac525ac97b34343298ffb139695 Mon Sep 17 00:00:00 2001 From: Daniel Lienert Date: Mon, 1 Aug 2016 08:43:58 +0200 Subject: [PATCH] TASK: Reformat code to psr-2 --- .../Ttree/Scheduler/Annotations/Schedule.php | 36 +- .../Ttree/Scheduler/Aspect/LoggingAspect.php | 98 ++-- .../Command/TaskCommandController.php | 219 +++++---- Classes/Ttree/Scheduler/Domain/Model/Task.php | 450 ++++++++--------- .../Domain/Repository/TaskRepository.php | 113 ++--- .../Ttree/Scheduler/Service/TaskService.php | 455 +++++++++--------- .../Ttree/Scheduler/Task/TaskInterface.php | 21 +- Migrations/Mysql/Version20141223003023.php | 47 +- Migrations/Mysql/Version20141223013606.php | 49 +- .../Postgresql/Version20160308124216.php | 47 +- 10 files changed, 799 insertions(+), 736 deletions(-) diff --git a/Classes/Ttree/Scheduler/Annotations/Schedule.php b/Classes/Ttree/Scheduler/Annotations/Schedule.php index fabc9dd..463fcad 100644 --- a/Classes/Ttree/Scheduler/Annotations/Schedule.php +++ b/Classes/Ttree/Scheduler/Annotations/Schedule.php @@ -1,5 +1,6 @@ expression = (string)$values['expression']; - } else { - $this->expression = '* * * * *'; - } - } + /** + * @var string + */ + public $expression; -} \ No newline at end of file + /** + * @param array $values + */ + public function __construct(array $values) + { + if (isset($values['expression'])) { + $this->expression = (string)$values['expression']; + } else { + $this->expression = '* * * * *'; + } + } +} diff --git a/Classes/Ttree/Scheduler/Aspect/LoggingAspect.php b/Classes/Ttree/Scheduler/Aspect/LoggingAspect.php index b67a89e..b4d6006 100644 --- a/Classes/Ttree/Scheduler/Aspect/LoggingAspect.php +++ b/Classes/Ttree/Scheduler/Aspect/LoggingAspect.php @@ -1,5 +1,6 @@ execute())") - */ - public function allTasks() {} + /** + * @Flow\Inject + * @var PersistenceManagerInterface + */ + protected $persistenceManager; - /** - * @Flow\Before("Ttree\Scheduler\Aspect\LoggingAspect->allTasks") - * @param JoinPoint $jointPoint - */ - public function logTaskExecutionBegin(JoinPoint $jointPoint) { - /** @var TaskInterface $task */ - $task = $jointPoint->getProxy(); - $this->systemLogger->log(sprintf('Task "%s" execution started', get_class($task))); - } + /** + * @Flow\Pointcut("within(Ttree\Scheduler\Task\TaskInterface) && method(.*->execute())") + */ + public function allTasks() + { + } - /** - * @Flow\After("Ttree\Scheduler\Aspect\LoggingAspect->allTasks") - * @param JoinPoint $jointPoint - */ - public function logTaskExecutionEnd(JoinPoint $jointPoint) { - /** @var Task $task */ - $task = $jointPoint->getProxy(); - $this->systemLogger->log(sprintf('Task "%s" execution finished', get_class($task))); - } + /** + * @Flow\Before("Ttree\Scheduler\Aspect\LoggingAspect->allTasks") + * @param JoinPoint $jointPoint + */ + public function logTaskExecutionBegin(JoinPoint $jointPoint) + { + /** @var TaskInterface $task */ + $task = $jointPoint->getProxy(); + $this->systemLogger->log(sprintf('Task "%s" execution started', get_class($task))); + } - /** - * @Flow\AfterThrowing("Ttree\Scheduler\Aspect\LoggingAspect->allTasks") - * @param JoinPoint $jointPoint - * @throws \Exception - */ - public function logTaskException(JoinPoint $jointPoint) { - /** @var Task $task */ - $exception = $jointPoint->getException(); - $this->systemLogger->logException($exception, array( - 'task' => $jointPoint->getClassName() - )); - } + /** + * @Flow\After("Ttree\Scheduler\Aspect\LoggingAspect->allTasks") + * @param JoinPoint $jointPoint + */ + public function logTaskExecutionEnd(JoinPoint $jointPoint) + { + /** @var Task $task */ + $task = $jointPoint->getProxy(); + $this->systemLogger->log(sprintf('Task "%s" execution finished', get_class($task))); + } + /** + * @Flow\AfterThrowing("Ttree\Scheduler\Aspect\LoggingAspect->allTasks") + * @param JoinPoint $jointPoint + * @throws \Exception + */ + public function logTaskException(JoinPoint $jointPoint) + { + /** @var Task $task */ + $exception = $jointPoint->getException(); + $this->systemLogger->logException($exception, [ + 'task' => $jointPoint->getClassName() + ]); + } } diff --git a/Classes/Ttree/Scheduler/Command/TaskCommandController.php b/Classes/Ttree/Scheduler/Command/TaskCommandController.php index 0192775..2d24514 100644 --- a/Classes/Ttree/Scheduler/Command/TaskCommandController.php +++ b/Classes/Ttree/Scheduler/Command/TaskCommandController.php @@ -1,5 +1,6 @@ taskService->getDueTasks() as $taskDescriptor) { - /** @var Task $task */ - $task = $taskDescriptor['object']; - $arguments = array($task->getImplementation(), $taskDescriptor['identifier'] ?: $taskDescriptor['type']); - try { - if (!$dryRun) { - $task->execute($this->objectManager); - $this->taskService->update($task, $taskDescriptor['type']); - $this->tellStatus('[Success] Run "%s" (%s)', $arguments); - } else { - $this->tellStatus('[Skipped, dry run] Skipped "%s" (%s)', $arguments); - } - } catch (\Exception $exception) { - $this->tellStatus('[Error] Task "%s" (%s) throw an exception, check your log', $arguments); - } - } - } + /** + * @Flow\Inject(lazy=false) + * @var ObjectManagerInterface + */ + protected $objectManager; - /** - * List all tasks - */ - public function listCommand() { - $tasks = array(); - foreach ($this->taskService->getTasks() as $task) { - $taskDescriptor = $task; - unset($taskDescriptor['object']); - $tasks[] = $taskDescriptor; - } - if (count($tasks)) { - $this->output->outputTable($tasks, array( - 'Type', - 'Status', - 'Identifier', - 'Interval', - 'Implementation', - 'Next Execution Date', - 'Last Execution Date', - )); - } else { - $this->outputLine('Empty task list ...'); - } - } + /** + * Run all pending task + * + * @param boolean $dryRun do not execute tasks + */ + public function runCommand($dryRun = false) + { + foreach ($this->taskService->getDueTasks() as $taskDescriptor) { + /** @var Task $task */ + $task = $taskDescriptor['object']; + $arguments = [$task->getImplementation(), $taskDescriptor['identifier'] ?: $taskDescriptor['type']]; + try { + if (!$dryRun) { + $task->execute($this->objectManager); + $this->taskService->update($task, $taskDescriptor['type']); + $this->tellStatus('[Success] Run "%s" (%s)', $arguments); + } else { + $this->tellStatus('[Skipped, dry run] Skipped "%s" (%s)', $arguments); + } + } catch (\Exception $exception) { + $this->tellStatus('[Error] Task "%s" (%s) throw an exception, check your log', $arguments); + } + } + } - /** - * @param Task $task - */ - public function removeCommand(Task $task) - { - $this->taskService->remove($task); - } + /** + * List all tasks + */ + public function listCommand() + { + $tasks = []; + foreach ($this->taskService->getTasks() as $task) { + $taskDescriptor = $task; + unset($taskDescriptor['object']); + $tasks[] = $taskDescriptor; + } + if (count($tasks)) { + $this->output->outputTable($tasks, [ + 'Type', + 'Status', + 'Identifier', + 'Interval', + 'Implementation', + 'Next Execution Date', + 'Last Execution Date', + ]); + } else { + $this->outputLine('Empty task list ...'); + } + } /** * Run a single persisted task ignoring status and schedule. @@ -108,48 +104,59 @@ public function runSingleCommand(Task $task) { } } - /** - * Enable the given persistent class - * - * @param Task $task persistent task identifier, see task:list - */ - public function enableCommand(Task $task) { - $task->enable(); - $this->taskService->update($task, TaskInterface::TYPE_PERSISTED); - } + /** + * @param Task $task + */ + public function removeCommand(Task $task) + { + $this->taskService->remove($task); + } - /** - * Disable the given persistent class - * - * @param Task $task persistent task identifier, see task:list - */ - public function disableCommand(Task $task) { - $task->disable(); - $this->taskService->update($task, TaskInterface::TYPE_PERSISTED); - } + /** + * Enable the given persistent class + * + * @param Task $task persistent task identifier, see task:list + */ + public function enableCommand(Task $task) + { + $task->enable(); + $this->taskService->update($task, TaskInterface::TYPE_PERSISTED); + } - /** - * Register a persistent task - * - * @param string $expression cron expression for the task scheduling - * @param string $task task class implementation - * @param string $arguments task arguments, can be a valid JSON array - */ - public function registerCommand($expression, $task, $arguments = NULL) { - if ($arguments !== NULL) { - $arguments = json_decode($arguments, TRUE); - Assertion::isArray($arguments, 'Arguments is not a valid JSON array'); - } - $this->taskService->create($expression, $task, $arguments ?: array()); - } + /** + * Disable the given persistent class + * + * @param Task $task persistent task identifier, see task:list + */ + public function disableCommand(Task $task) + { + $task->disable(); + $this->taskService->update($task, TaskInterface::TYPE_PERSISTED); + } - /** - * @param string $message - * @param array $arguments - */ - protected function tellStatus($message, array $arguments = NULL) { - $message = vsprintf($message, $arguments); - $this->outputLine('%s: %s', array(date(\DateTime::ISO8601), $message)); - } + /** + * Register a persistent task + * + * @param string $expression cron expression for the task scheduling + * @param string $task task class implementation + * @param string $arguments task arguments, can be a valid JSON array + */ + public function registerCommand($expression, $task, $arguments = null) + { + if ($arguments !== null) { + $arguments = json_decode($arguments, true); + Assertion::isArray($arguments, 'Arguments is not a valid JSON array'); + } + $this->taskService->create($expression, $task, $arguments ?: []); + } + /** + * @param string $message + * @param array $arguments + */ + protected function tellStatus($message, array $arguments = null) + { + $message = vsprintf($message, $arguments); + $this->outputLine('%s: %s', [date(\DateTime::ISO8601), $message]); + } } diff --git a/Classes/Ttree/Scheduler/Domain/Model/Task.php b/Classes/Ttree/Scheduler/Domain/Model/Task.php index 20680a0..5c3358b 100644 --- a/Classes/Ttree/Scheduler/Domain/Model/Task.php +++ b/Classes/Ttree/Scheduler/Domain/Model/Task.php @@ -1,5 +1,6 @@ disable(); - $this->setExpression($expression); - $this->setImplementation($implementation); - $this->setArguments($arguments); - $this->creationDate = new \DateTime('now'); - $this->initializeNextExecution(); - } - - /** - * Initialize Object - */ - public function getCronExpression() { - if ($this->cronExpression === NULL) { - $this->cronExpression = CronExpression::factory($this->expression); - } - return $this->cronExpression; - } - - /** - * @return boolean - */ - public function isDue() { - $now = new Now(); - return $this->nextExecution <= $now; - } - - /** - * @return \DateTime - */ - public function getPreviousRunDate() { - return $this->getCronExpression()->getPreviousRunDate(); - } - - /** - * @return boolean - */ - public function isDisabled() { - return $this->status === self::STATUS_DISABLED; - } - - /** - * @return boolean - */ - public function isEnabled() { - return $this->status === self::STATUS_ENABLED; - } - - /** - * @return void - */ - public function enable() { - $this->status = self::STATUS_ENABLED; - } - - /** - * @return void - */ - public function disable() { - $this->status = self::STATUS_DISABLED; - } - - /** - * {@inheritdoc} - * - * @return string - */ - public function getExpression() { - return $this->expression; - } - - /** - * @param string $expression - */ - public function setExpression($expression) { - $this->expression = $expression; - $this->initializeNextExecution(); - } - - /** - * @return string - */ - public function getImplementation() { - return $this->implementation; - } - - /** - * @param string $implementation - */ - public function setImplementation($implementation) { - $this->implementation = $implementation; - } - - /** - * @return array - */ - public function getArguments() { - return $this->arguments; - } - - /** - * @param array $arguments - */ - public function setArguments($arguments) { - $this->arguments = $arguments; - $this->argumentsHash = sha1(serialize($arguments)); - } - - /** - * {@inheritdoc} - * - * @return void - */ - public function execute(ObjectManagerInterface $objectManager) { - /** @var TaskInterface $task */ - $task = $objectManager->get($this->implementation, $this); - $task->execute($this->arguments); - $this->lastExecution = new \DateTime('now'); - $this->initializeNextExecution(); - } - - /** - * @return void - */ - public function initializeNextExecution() { - $this->nextExecution = $this->getCronExpression()->getNextRunDate(); - } - - /** - * @return \DateTime - */ - public function getCreationDate() { - return clone $this->creationDate; - } - - /** - * @return \DateTime - */ - public function getLastExecution() { - return $this->lastExecution ? clone $this->lastExecution : NULL; - } - - /** - * @param string - * @return \DateTime - */ - public function getNextExecution($currentTime = NULL) { - if ($currentTime) { - return $this->getCronExpression()->getNextRunDate($currentTime); - } else { - return clone $this->nextExecution; - } - } - +class Task +{ + + const STATUS_DISABLED = 0; + const STATUS_ENABLED = 1; + + /** + * @var integer + */ + protected $status; + + /** + * @var string + * @Flow\Identity + */ + protected $expression; + + /** + * @var string + * @Flow\Identity + */ + protected $implementation; + + /** + * @var array + */ + protected $arguments; + + /** + * @var string + * @Flow\Identity + */ + protected $argumentsHash; + + /** + * @var \DateTime + */ + protected $creationDate; + + /** + * @var \DateTime + * @ORM\Column(nullable=true) + */ + protected $lastExecution; + + /** + * @var \DateTime + * @ORM\Column(nullable=true) + */ + protected $nextExecution; + + /** + * @var CronExpression + * @Flow\Transient + */ + protected $cronExpression; + + /** + * @param string $expression + * @param string $implementation + * @param array $arguments + */ + public function __construct($expression, $implementation, array $arguments = []) + { + $this->disable(); + $this->setExpression($expression); + $this->setImplementation($implementation); + $this->setArguments($arguments); + $this->creationDate = new \DateTime('now'); + $this->initializeNextExecution(); + } + + /** + * Initialize Object + */ + public function getCronExpression() + { + if ($this->cronExpression === null) { + $this->cronExpression = CronExpression::factory($this->expression); + } + return $this->cronExpression; + } + + /** + * @return boolean + */ + public function isDue() + { + $now = new Now(); + return $this->nextExecution <= $now; + } + + /** + * @return \DateTime + */ + public function getPreviousRunDate() + { + return $this->getCronExpression()->getPreviousRunDate(); + } + + /** + * @return boolean + */ + public function isDisabled() + { + return $this->status === self::STATUS_DISABLED; + } + + /** + * @return boolean + */ + public function isEnabled() + { + return $this->status === self::STATUS_ENABLED; + } + + /** + * @return void + */ + public function enable() + { + $this->status = self::STATUS_ENABLED; + } + + /** + * @return void + */ + public function disable() + { + $this->status = self::STATUS_DISABLED; + } + + /** + * {@inheritdoc} + * + * @return string + */ + public function getExpression() + { + return $this->expression; + } + + /** + * @param string $expression + */ + public function setExpression($expression) + { + $this->expression = $expression; + $this->initializeNextExecution(); + } + + /** + * @return string + */ + public function getImplementation() + { + return $this->implementation; + } + + /** + * @param string $implementation + */ + public function setImplementation($implementation) + { + $this->implementation = $implementation; + } + + /** + * @return array + */ + public function getArguments() + { + return $this->arguments; + } + + /** + * @param array $arguments + */ + public function setArguments($arguments) + { + $this->arguments = $arguments; + $this->argumentsHash = sha1(serialize($arguments)); + } + + /** + * {@inheritdoc} + * + * @return void + */ + public function execute(ObjectManagerInterface $objectManager) + { + /** @var TaskInterface $task */ + $task = $objectManager->get($this->implementation, $this); + $task->execute($this->arguments); + $this->lastExecution = new \DateTime('now'); + $this->initializeNextExecution(); + } + + /** + * @return void + */ + public function initializeNextExecution() + { + $this->nextExecution = $this->getCronExpression()->getNextRunDate(); + } + + /** + * @return \DateTime + */ + public function getCreationDate() + { + return clone $this->creationDate; + } + + /** + * @return \DateTime + */ + public function getLastExecution() + { + return $this->lastExecution ? clone $this->lastExecution : null; + } + + /** + * @param string + * @return \DateTime + */ + public function getNextExecution($currentTime = null) + { + if ($currentTime) { + return $this->getCronExpression()->getNextRunDate($currentTime); + } else { + return clone $this->nextExecution; + } + } } diff --git a/Classes/Ttree/Scheduler/Domain/Repository/TaskRepository.php b/Classes/Ttree/Scheduler/Domain/Repository/TaskRepository.php index ba8d623..40cb071 100644 --- a/Classes/Ttree/Scheduler/Domain/Repository/TaskRepository.php +++ b/Classes/Ttree/Scheduler/Domain/Repository/TaskRepository.php @@ -1,5 +1,6 @@ QueryInterface::ORDER_ASCENDING, - 'nextExecution' => QueryInterface::ORDER_ASCENDING - ); +class TaskRepository extends Repository +{ - /** - * @param string $identifier - * @return Task - */ - public function findByIdentifier($identifier) { - return parent::findByIdentifier($identifier); - } + /** + * @var array + */ + protected $defaultOrderings = [ + 'status' => QueryInterface::ORDER_ASCENDING, + 'nextExecution' => QueryInterface::ORDER_ASCENDING + ]; - /** - * @return \TYPO3\Flow\Persistence\QueryResultInterface - */ - public function findDueTasks() { - $query = $this->createQuery(); + /** + * @param string $identifier + * @return Task + */ + public function findByIdentifier($identifier) + { + return parent::findByIdentifier($identifier); + } - $now = new Now(); + /** + * @return \TYPO3\Flow\Persistence\QueryResultInterface + */ + public function findDueTasks() + { + $query = $this->createQuery(); - $query->matching($query->logicalAnd( - $query->equals('status', Task::STATUS_ENABLED), - $query->lessThanOrEqual('nextExecution', $now) - )); + $now = new Now(); - return $query->execute(); - } + $query->matching($query->logicalAnd( + $query->equals('status', Task::STATUS_ENABLED), + $query->lessThanOrEqual('nextExecution', $now) + )); - /** - * @param boolean $showDisabled - * @return \TYPO3\Flow\Persistence\QueryResultInterface - */ - public function findAllTasks($showDisabled = FALSE) { - $query = $this->createQuery(); + return $query->execute(); + } - if (!$showDisabled) { - $query->matching($query->equals('status', Task::STATUS_ENABLED)); - } + /** + * @param boolean $showDisabled + * @return \TYPO3\Flow\Persistence\QueryResultInterface + */ + public function findAllTasks($showDisabled = false) + { + $query = $this->createQuery(); - return $query->execute(); - } + if (!$showDisabled) { + $query->matching($query->equals('status', Task::STATUS_ENABLED)); + } - /** - * @param string $implementation - * @param array $arguments - * @return Task - */ - public function findOneByImplementationAndArguments($implementation, array $arguments) { - $argumentsHash = sha1(serialize($arguments)); - $query = $this->createQuery(); + return $query->execute(); + } - $query->matching($query->logicalAnd( - $query->equals('implementation', $implementation), - $query->equals('argumentsHash', $argumentsHash) - )); + /** + * @param string $implementation + * @param array $arguments + * @return Task + */ + public function findOneByImplementationAndArguments($implementation, array $arguments) + { + $argumentsHash = sha1(serialize($arguments)); + $query = $this->createQuery(); - return $query->execute()->getFirst(); - } + $query->matching($query->logicalAnd( + $query->equals('implementation', $implementation), + $query->equals('argumentsHash', $argumentsHash) + )); -} \ No newline at end of file + return $query->execute()->getFirst(); + } +} diff --git a/Classes/Ttree/Scheduler/Service/TaskService.php b/Classes/Ttree/Scheduler/Service/TaskService.php index c5c823c..f60a4ff 100644 --- a/Classes/Ttree/Scheduler/Service/TaskService.php +++ b/Classes/Ttree/Scheduler/Service/TaskService.php @@ -1,5 +1,6 @@ get('TYPO3\Flow\Reflection\ReflectionService'); - return $reflectionService->getAllImplementationClassNamesForInterface(self::TASK_INTERFACE); - } - - /** - * @param ObjectManagerInterface $objectManager - * @return array - * @Flow\CompileStatic - */ - static public function getAllDynamicTaskImplementations(ObjectManagerInterface $objectManager) { - $tasks = array(); - /** @var ReflectionService $reflectionService */ - $reflectionService = $objectManager->get('TYPO3\Flow\Reflection\ReflectionService'); - foreach (self::getAllTaskImplementations($objectManager) as $className) { - if (!$reflectionService->isClassAnnotatedWith($className, 'Ttree\Scheduler\Annotations\Schedule')) { - continue; - } - /** @var Schedule $scheduleAnnotation */ - $scheduleAnnotation = $reflectionService->getClassAnnotation($className, 'Ttree\Scheduler\Annotations\Schedule'); - $tasks[] = array( - 'implementation' => $className, - 'expression' => $scheduleAnnotation->expression - ); - } - - return $tasks; - } - - /** - * @return array - */ - public function getDueTasks() { - $tasks = array_merge($this->getDuePersistedTasks(), $this->getDynamicTasks(TRUE)); - - return $this->cleanupAndSortTaskList($tasks); - } - - /** - * @return array - */ - public function getDuePersistedTasks() { - $tasks = array(); - foreach ($this->taskRepository->findDueTasks() as $task) { - /** @var Task $task */ - $tasks[] = $this->getTaskDescriptor(TaskInterface::TYPE_PERSISTED, $task); - } - return $tasks; - } - - /** - * @return array - */ - public function getTasks() { - $tasks = array_merge($this->getPersistedTasks(), $this->getDynamicTasks()); - - return $this->cleanupAndSortTaskList($tasks); - } - - /** - * @return array - */ - public function getPersistedTasks() { - $tasks = array(); - foreach ($this->taskRepository->findAll() as $task) { - /** @var Task $task */ - $tasks[] = $this->getTaskDescriptor(TaskInterface::TYPE_PERSISTED, $task); - } - return $tasks; - } - - /** - * @param boolean - * @return array - */ - public function getDynamicTasks($dueOnly = FALSE) { - $tasks = array(); - $now = new Now(); - - foreach (self::getAllDynamicTaskImplementations($this->objectManager) as $dynamicTask) { - $task = new Task($dynamicTask['expression'], $dynamicTask['implementation']); - $cacheKey = md5($dynamicTask['implementation']); - $lastExecution = $this->dynamicTaskLastExecutionCache->get($cacheKey); - if ($dueOnly && ($lastExecution instanceof \DateTime && $now < $task->getNextExecution($lastExecution))) { - continue; - } - $task->enable(); - $taskDecriptor = $this->getTaskDescriptor(TaskInterface::TYPE_DYNAMIC, $task); - - $taskDecriptor['lastExecution'] = $lastExecution instanceof \DateTime ? $lastExecution->format(\DateTime::ISO8601) : ''; - $taskDecriptor['identifier'] = ''; - $tasks[] = $taskDecriptor; - } - return $tasks; - } - - /** - * @param string $type - * @param Task $task - * @return array - */ - public function getTaskDescriptor($type, Task $task) { - Assertion::string($type, 'Type must be a string'); - return array( - 'type' => $type, - 'enabled' => $task->isEnabled() ? 'On' : 'Off', - 'identifier' => $this->persistenceManager->getIdentifierByObject($task), - 'expression' => $task->getExpression(), - 'implementation' => $task->getImplementation(), - 'nextExecution' => $task->getNextExecution() ? $task->getNextExecution()->format(\DateTime::ISO8601) : '', - 'nextExecutionTimestamp' => $task->getNextExecution() ? $task->getNextExecution()->getTimestamp() : 0, - 'lastExecution' => $task->getLastExecution() ? $task->getLastExecution()->format(\DateTime::ISO8601) : '', - 'object' => $task - ); - } - - /** - * @param string $expression - * @param string $task - * @param array $arguments - * @return Task - */ - public function create($expression, $task, array $arguments) { - $task = new Task($expression, $task, $arguments); - $this->assertValidTask($task); - $this->taskRepository->add($task); - return $task; - } - - /** - * @param Task $task - */ - public function remove(Task $task) - { - $this->taskRepository->remove($task); - } - - /** - * @param Task $task - * @param string $type - */ - public function update(Task $task, $type) { - switch ($type) { - case TaskInterface::TYPE_DYNAMIC: - $cacheKey = md5($task->getImplementation()); - $this->dynamicTaskLastExecutionCache->set($cacheKey, $task->getLastExecution()); - break; - case TaskInterface::TYPE_PERSISTED: - $this->taskRepository->update($task); - break; - } - } - - /** - * @param array $tasks - * @return array - */ - protected function cleanupAndSortTaskList(array $tasks) { - usort($tasks, function($a, $b) { - return $a['nextExecutionTimestamp'] > $b['nextExecutionTimestamp']; - }); - - array_walk($tasks, function(&$task) { - unset($task['nextExecutionTimestamp']); - }); - - return $tasks; - } - - /** - * @param Task $task - * @return boolean - */ - protected function assertValidTask(Task $task) { - if (!class_exists($task->getImplementation())) { - throw new \InvalidArgumentException(sprintf('Task implementation "%s" must exist', $task->getImplementation()), 1419296545); - } - if (!$this->reflexionService->isClassImplementationOf($task->getImplementation(), self::TASK_INTERFACE)) { - throw new \InvalidArgumentException('Task must implement TaskInterface', 1419296485); - } - } +class TaskService +{ + + const TASK_INTERFACE = 'Ttree\Scheduler\Task\TaskInterface'; + + /** + * @Flow\Inject + * @var VariableFrontend + */ + protected $dynamicTaskLastExecutionCache; + + /** + * @Flow\Inject + * @var TaskRepository + */ + protected $taskRepository; + + /** + * @Flow\Inject + * @var PersistenceManagerInterface + */ + protected $persistenceManager; + + /** + * @Flow\Inject + * @var ReflectionService + */ + protected $reflexionService; + + /** + * @Flow\Inject + * @var ObjectManagerInterface + */ + protected $objectManager; + + /** + * @param ObjectManagerInterface $objectManager + * @return array + * @Flow\CompileStatic + */ + public static function getAllTaskImplementations(ObjectManagerInterface $objectManager) + { + /** @var ReflectionService $reflectionService */ + $reflectionService = $objectManager->get('TYPO3\Flow\Reflection\ReflectionService'); + return $reflectionService->getAllImplementationClassNamesForInterface(self::TASK_INTERFACE); + } + + /** + * @param ObjectManagerInterface $objectManager + * @return array + * @Flow\CompileStatic + */ + public static function getAllDynamicTaskImplementations(ObjectManagerInterface $objectManager) + { + $tasks = []; + /** @var ReflectionService $reflectionService */ + $reflectionService = $objectManager->get('TYPO3\Flow\Reflection\ReflectionService'); + foreach (self::getAllTaskImplementations($objectManager) as $className) { + if (!$reflectionService->isClassAnnotatedWith($className, 'Ttree\Scheduler\Annotations\Schedule')) { + continue; + } + /** @var Schedule $scheduleAnnotation */ + $scheduleAnnotation = $reflectionService->getClassAnnotation($className, 'Ttree\Scheduler\Annotations\Schedule'); + $tasks[] = [ + 'implementation' => $className, + 'expression' => $scheduleAnnotation->expression + ]; + } + + return $tasks; + } + + /** + * @return array + */ + public function getDueTasks() + { + $tasks = array_merge($this->getDuePersistedTasks(), $this->getDynamicTasks(true)); + + return $this->cleanupAndSortTaskList($tasks); + } + + /** + * @return array + */ + public function getDuePersistedTasks() + { + $tasks = []; + foreach ($this->taskRepository->findDueTasks() as $task) { + /** @var Task $task */ + $tasks[] = $this->getTaskDescriptor(TaskInterface::TYPE_PERSISTED, $task); + } + return $tasks; + } + + /** + * @return array + */ + public function getTasks() + { + $tasks = array_merge($this->getPersistedTasks(), $this->getDynamicTasks()); + + return $this->cleanupAndSortTaskList($tasks); + } + + /** + * @return array + */ + public function getPersistedTasks() + { + $tasks = []; + foreach ($this->taskRepository->findAll() as $task) { + /** @var Task $task */ + $tasks[] = $this->getTaskDescriptor(TaskInterface::TYPE_PERSISTED, $task); + } + return $tasks; + } + + /** + * @param boolean + * @return array + */ + public function getDynamicTasks($dueOnly = false) + { + $tasks = []; + $now = new Now(); + + foreach (self::getAllDynamicTaskImplementations($this->objectManager) as $dynamicTask) { + $task = new Task($dynamicTask['expression'], $dynamicTask['implementation']); + $cacheKey = md5($dynamicTask['implementation']); + $lastExecution = $this->dynamicTaskLastExecutionCache->get($cacheKey); + if ($dueOnly && ($lastExecution instanceof \DateTime && $now < $task->getNextExecution($lastExecution))) { + continue; + } + $task->enable(); + $taskDecriptor = $this->getTaskDescriptor(TaskInterface::TYPE_DYNAMIC, $task); + + $taskDecriptor['lastExecution'] = $lastExecution instanceof \DateTime ? $lastExecution->format(\DateTime::ISO8601) : ''; + $taskDecriptor['identifier'] = ''; + $tasks[] = $taskDecriptor; + } + return $tasks; + } + + /** + * @param string $type + * @param Task $task + * @return array + */ + public function getTaskDescriptor($type, Task $task) + { + Assertion::string($type, 'Type must be a string'); + return [ + 'type' => $type, + 'enabled' => $task->isEnabled() ? 'On' : 'Off', + 'identifier' => $this->persistenceManager->getIdentifierByObject($task), + 'expression' => $task->getExpression(), + 'implementation' => $task->getImplementation(), + 'nextExecution' => $task->getNextExecution() ? $task->getNextExecution()->format(\DateTime::ISO8601) : '', + 'nextExecutionTimestamp' => $task->getNextExecution() ? $task->getNextExecution()->getTimestamp() : 0, + 'lastExecution' => $task->getLastExecution() ? $task->getLastExecution()->format(\DateTime::ISO8601) : '', + 'object' => $task + ]; + } + + /** + * @param string $expression + * @param string $task + * @param array $arguments + * @return Task + */ + public function create($expression, $task, array $arguments) + { + $task = new Task($expression, $task, $arguments); + $this->assertValidTask($task); + $this->taskRepository->add($task); + return $task; + } + + /** + * @param Task $task + */ + public function remove(Task $task) + { + $this->taskRepository->remove($task); + } + + /** + * @param Task $task + * @param string $type + */ + public function update(Task $task, $type) + { + switch ($type) { + case TaskInterface::TYPE_DYNAMIC: + $cacheKey = md5($task->getImplementation()); + $this->dynamicTaskLastExecutionCache->set($cacheKey, $task->getLastExecution()); + break; + case TaskInterface::TYPE_PERSISTED: + $this->taskRepository->update($task); + break; + } + } + + /** + * @param array $tasks + * @return array + */ + protected function cleanupAndSortTaskList(array $tasks) + { + usort($tasks, function ($a, $b) { + return $a['nextExecutionTimestamp'] > $b['nextExecutionTimestamp']; + }); + + array_walk($tasks, function (&$task) { + unset($task['nextExecutionTimestamp']); + }); + + return $tasks; + } + /** + * @param Task $task + * @return boolean + */ + protected function assertValidTask(Task $task) + { + if (!class_exists($task->getImplementation())) { + throw new \InvalidArgumentException(sprintf('Task implementation "%s" must exist', $task->getImplementation()), 1419296545); + } + if (!$this->reflexionService->isClassImplementationOf($task->getImplementation(), self::TASK_INTERFACE)) { + throw new \InvalidArgumentException('Task must implement TaskInterface', 1419296485); + } + } } diff --git a/Classes/Ttree/Scheduler/Task/TaskInterface.php b/Classes/Ttree/Scheduler/Task/TaskInterface.php index 6eb10a7..e3e787a 100644 --- a/Classes/Ttree/Scheduler/Task/TaskInterface.php +++ b/Classes/Ttree/Scheduler/Task/TaskInterface.php @@ -1,5 +1,6 @@ abortIf($this->connection->getDatabasePlatform()->getName() != "mysql"); - - $this->addSql("CREATE TABLE ttree_scheduler_domain_model_task (persistence_object_identifier VARCHAR(40) NOT NULL, status INT NOT NULL, expression VARCHAR(255) NOT NULL, implementation VARCHAR(255) NOT NULL, arguments LONGTEXT NOT NULL COMMENT '(DC2Type:array)', argumentshash VARCHAR(255) NOT NULL , creationdate DATETIME NOT NULL, lastexecution DATETIME DEFAULT NULL, nextexecution DATETIME DEFAULT NULL, PRIMARY KEY(persistence_object_identifier)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB"); - } + /** + * @param Schema $schema + * @return void + */ + public function up(Schema $schema) + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql"); + + $this->addSql("CREATE TABLE ttree_scheduler_domain_model_task (persistence_object_identifier VARCHAR(40) NOT NULL, status INT NOT NULL, expression VARCHAR(255) NOT NULL, implementation VARCHAR(255) NOT NULL, arguments LONGTEXT NOT NULL COMMENT '(DC2Type:array)', argumentshash VARCHAR(255) NOT NULL , creationdate DATETIME NOT NULL, lastexecution DATETIME DEFAULT NULL, nextexecution DATETIME DEFAULT NULL, PRIMARY KEY(persistence_object_identifier)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB"); + } - /** - * @param Schema $schema - * @return void - */ - public function down(Schema $schema) { - $this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql"); - - $this->addSql("DROP TABLE ttree_scheduler_domain_model_task"); - } -} \ No newline at end of file + /** + * @param Schema $schema + * @return void + */ + public function down(Schema $schema) + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql"); + + $this->addSql("DROP TABLE ttree_scheduler_domain_model_task"); + } +} diff --git a/Migrations/Mysql/Version20141223013606.php b/Migrations/Mysql/Version20141223013606.php index 51561d1..9bc0ec9 100644 --- a/Migrations/Mysql/Version20141223013606.php +++ b/Migrations/Mysql/Version20141223013606.php @@ -1,32 +1,35 @@ abortIf($this->connection->getDatabasePlatform()->getName() != "mysql"); - - $this->addSql("CREATE UNIQUE INDEX flow_identity_ttree_scheduler_domain_model_task ON ttree_scheduler_domain_model_task (expression, implementation, argumentshash)"); - } + /** + * @param Schema $schema + * @return void + */ + public function up(Schema $schema) + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql"); + + $this->addSql("CREATE UNIQUE INDEX flow_identity_ttree_scheduler_domain_model_task ON ttree_scheduler_domain_model_task (expression, implementation, argumentshash)"); + } - /** - * @param Schema $schema - * @return void - */ - public function down(Schema $schema) { - // this down() migration is autogenerated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql"); - - $this->addSql("DROP INDEX flow_identity_ttree_scheduler_domain_model_task ON ttree_scheduler_domain_model_task"); - } -} \ No newline at end of file + /** + * @param Schema $schema + * @return void + */ + public function down(Schema $schema) + { + // this down() migration is autogenerated, please modify it to your needs + $this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql"); + + $this->addSql("DROP INDEX flow_identity_ttree_scheduler_domain_model_task ON ttree_scheduler_domain_model_task"); + } +} diff --git a/Migrations/Postgresql/Version20160308124216.php b/Migrations/Postgresql/Version20160308124216.php index a74a386..6fb986f 100644 --- a/Migrations/Postgresql/Version20160308124216.php +++ b/Migrations/Postgresql/Version20160308124216.php @@ -1,33 +1,36 @@ abortIf($this->connection->getDatabasePlatform()->getName() != "postgresql"); + /** + * @param Schema $schema + * @return void + */ + public function up(Schema $schema) + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() != "postgresql"); - $this->addSql("CREATE TABLE ttree_scheduler_domain_model_task (persistence_object_identifier VARCHAR(40) NOT NULL, status INT NOT NULL, expression VARCHAR(255) NOT NULL, implementation VARCHAR(255) NOT NULL, arguments TEXT NOT NULL, argumentshash VARCHAR(255) NOT NULL, creationdate TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, lastexecution TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, nextexecution TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY(persistence_object_identifier))"); - $this->addSql("CREATE UNIQUE INDEX flow_identity_ttree_scheduler_domain_model_task ON ttree_scheduler_domain_model_task (expression, implementation, argumentshash)"); - $this->addSql("COMMENT ON COLUMN ttree_scheduler_domain_model_task.arguments IS '(DC2Type:array)'"); - } + $this->addSql("CREATE TABLE ttree_scheduler_domain_model_task (persistence_object_identifier VARCHAR(40) NOT NULL, status INT NOT NULL, expression VARCHAR(255) NOT NULL, implementation VARCHAR(255) NOT NULL, arguments TEXT NOT NULL, argumentshash VARCHAR(255) NOT NULL, creationdate TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, lastexecution TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, nextexecution TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY(persistence_object_identifier))"); + $this->addSql("CREATE UNIQUE INDEX flow_identity_ttree_scheduler_domain_model_task ON ttree_scheduler_domain_model_task (expression, implementation, argumentshash)"); + $this->addSql("COMMENT ON COLUMN ttree_scheduler_domain_model_task.arguments IS '(DC2Type:array)'"); + } - /** - * @param Schema $schema - * @return void - */ - public function down(Schema $schema) { - $this->abortIf($this->connection->getDatabasePlatform()->getName() != "postgresql"); + /** + * @param Schema $schema + * @return void + */ + public function down(Schema $schema) + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() != "postgresql"); - $this->addSql("DROP TABLE ttree_scheduler_domain_model_task"); - } -} \ No newline at end of file + $this->addSql("DROP TABLE ttree_scheduler_domain_model_task"); + } +}