Skip to content

Commit 1f80722

Browse files
implemented system-tasks
1 parent a5a7535 commit 1f80722

22 files changed

+740
-33
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
/*
4+
* This file is part of php-task library.
5+
*
6+
* (c) php-task
7+
*
8+
* This source file is subject to the MIT license that is bundled
9+
* with this source code in the file LICENSE.
10+
*/
11+
12+
namespace Task\TaskBundle\Builder;
13+
14+
use Task\TaskInterface;
15+
16+
/**
17+
* Indicates not supported method.
18+
*/
19+
class NotSupportedMethodException extends \Exception
20+
{
21+
/**
22+
* @var string
23+
*/
24+
private $property;
25+
26+
/**
27+
* @var TaskInterface
28+
*/
29+
private $task;
30+
31+
/**
32+
* @param string $property
33+
* @param TaskInterface $task
34+
*/
35+
public function __construct($property, TaskInterface $task)
36+
{
37+
parent::__construct(
38+
sprintf('Property "%s" is not supported for task-class "%s".', $property, get_class($task))
39+
);
40+
41+
$this->property = $property;
42+
$this->task = $task;
43+
}
44+
45+
/**
46+
* Returns property.
47+
*
48+
* @return string
49+
*/
50+
public function getProperty()
51+
{
52+
return $this->property;
53+
}
54+
55+
/**
56+
* Returns task.
57+
*
58+
* @return TaskInterface
59+
*/
60+
public function getTask()
61+
{
62+
return $this->task;
63+
}
64+
}

src/Builder/TaskBuilder.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
/*
4+
* This file is part of php-task library.
5+
*
6+
* (c) php-task
7+
*
8+
* This source file is subject to the MIT license that is bundled
9+
* with this source code in the file LICENSE.
10+
*/
11+
12+
namespace Task\TaskBundle\Builder;
13+
14+
use Task\Builder\TaskBuilder as BaseTaskBuilder;
15+
use Task\Builder\TaskBuilderInterface;
16+
use Task\Scheduler\TaskSchedulerInterface;
17+
use Task\TaskBundle\Entity\Task;
18+
use Task\TaskInterface;
19+
20+
/**
21+
* Extends base task-builder.
22+
*/
23+
class TaskBuilder extends BaseTaskBuilder
24+
{
25+
/**
26+
* @var TaskInterface
27+
*/
28+
private $task;
29+
30+
/**
31+
* @param TaskInterface $task
32+
* @param TaskSchedulerInterface $taskScheduler
33+
*/
34+
public function __construct(TaskInterface $task, TaskSchedulerInterface $taskScheduler)
35+
{
36+
parent::__construct($task, $taskScheduler);
37+
38+
$this->task = $task;
39+
}
40+
41+
/**
42+
* Set system-key.
43+
*
44+
* @param string $systemKey
45+
*
46+
* @return TaskBuilderInterface
47+
*
48+
* @throws NotSupportedMethodException
49+
*/
50+
public function setSystemKey($systemKey)
51+
{
52+
if (!$this->task instanceof Task) {
53+
throw new NotSupportedMethodException('systemKey', $this->task);
54+
}
55+
56+
$this->task->setSystemKey($systemKey);
57+
58+
return $this;
59+
}
60+
}

src/Builder/TaskBuilderFactory.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/*
4+
* This file is part of php-task library.
5+
*
6+
* (c) php-task
7+
*
8+
* This source file is subject to the MIT license that is bundled
9+
* with this source code in the file LICENSE.
10+
*/
11+
12+
namespace Task\TaskBundle\Builder;
13+
14+
use Task\Builder\TaskBuilderFactoryInterface;
15+
use Task\Scheduler\TaskSchedulerInterface;
16+
use Task\TaskInterface;
17+
18+
/**
19+
* Factory to create new task-builders.
20+
*/
21+
class TaskBuilderFactory implements TaskBuilderFactoryInterface
22+
{
23+
/**
24+
* {@inheritdoc}
25+
*/
26+
public function createTaskBuilder(TaskInterface $task, TaskSchedulerInterface $taskScheduler)
27+
{
28+
return new TaskBuilder($task, $taskScheduler);
29+
}
30+
}
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
<?php
2+
3+
namespace Task\TaskBundle\Command;
4+
5+
use Cron\CronExpression;
6+
use Symfony\Component\Console\Command\Command;
7+
use Symfony\Component\Console\Input\InputInterface;
8+
use Symfony\Component\Console\Output\OutputInterface;
9+
use Task\Scheduler\TaskSchedulerInterface;
10+
use Task\Storage\TaskExecutionRepositoryInterface;
11+
use Task\TaskBundle\Builder\TaskBuilder;
12+
use Task\TaskBundle\Entity\TaskRepository;
13+
use Task\TaskInterface;
14+
15+
/**
16+
* Schedules configured system-tasks.
17+
*/
18+
class ScheduleSystemTasksCommand extends Command
19+
{
20+
/**
21+
* @var array
22+
*/
23+
private $systemTasks;
24+
25+
/**
26+
* @var TaskSchedulerInterface
27+
*/
28+
private $scheduler;
29+
30+
/**
31+
* @var TaskRepository
32+
*/
33+
private $taskRepository;
34+
35+
/**
36+
* @var TaskExecutionRepositoryInterface
37+
*/
38+
private $taskExecutionRepository;
39+
40+
/**
41+
* @param string $name
42+
* @param array $systemTasks
43+
* @param TaskSchedulerInterface $scheduler
44+
* @param TaskRepository $taskRepository
45+
* @param TaskExecutionRepositoryInterface $taskExecutionRepository
46+
*/
47+
public function __construct(
48+
$name,
49+
array $systemTasks,
50+
TaskSchedulerInterface $scheduler,
51+
TaskRepository $taskRepository,
52+
TaskExecutionRepositoryInterface $taskExecutionRepository
53+
) {
54+
parent::__construct($name);
55+
56+
$this->systemTasks = $systemTasks;
57+
$this->scheduler = $scheduler;
58+
$this->taskRepository = $taskRepository;
59+
$this->taskExecutionRepository = $taskExecutionRepository;
60+
}
61+
62+
/**
63+
* {@inheritdoc}
64+
*/
65+
protected function configure()
66+
{
67+
$this->setDescription('Schedule system-tasks')->setHelp(
68+
<<<'EOT'
69+
The <info>%command.name%</info> command schedules configured system tasks.
70+
71+
$ %command.full_name%
72+
73+
You can configure them by extending the <info>task.system_task</info> array in your config file.
74+
EOT
75+
);
76+
}
77+
78+
/**
79+
* {@inheritdoc}
80+
*/
81+
protected function execute(InputInterface $input, OutputInterface $output)
82+
{
83+
$output->writeln(sprintf('Schedule %s system-tasks:', count($this->systemTasks)));
84+
$output->writeln('');
85+
86+
foreach ($this->systemTasks as $systemKey => $systemTask) {
87+
try {
88+
$this->processSystemTask($systemKey, $systemTask, $output);
89+
} catch (\Exception $exception) {
90+
$output->writeln(
91+
sprintf(
92+
' * System-task "%s" failed because of: <exception>%s</exception>',
93+
$systemKey,
94+
$exception->getMessage()
95+
)
96+
);
97+
}
98+
}
99+
100+
101+
$output->writeln('');
102+
$output->writeln('System-tasks successfully scheduled');
103+
}
104+
105+
/**
106+
* Process single system task.
107+
*
108+
* @param string $systemKey
109+
* @param array $systemTask
110+
* @param OutputInterface $output
111+
*/
112+
private function processSystemTask($systemKey, array $systemTask, OutputInterface $output)
113+
{
114+
if (!$systemTask['enabled']) {
115+
$this->disableTask($systemKey);
116+
117+
$output->writeln(sprintf(' * System-task "%s" was <info>disabled</info>.', $systemKey));
118+
119+
return;
120+
}
121+
122+
if ($task = $this->taskRepository->findBySystemKey($systemKey)) {
123+
$this->updateTask($systemKey, $systemTask, $task);
124+
125+
$output->writeln(sprintf(' * System-task "%s" was <info>updated</info>.', $systemKey));
126+
127+
return;
128+
}
129+
130+
/** @var TaskBuilder $builder */
131+
$builder = $this->scheduler->createTask($systemTask['handler_class'], $systemTask['workload']);
132+
$builder->setSystemKey($systemKey);
133+
if ($systemTask['cron_expression']) {
134+
$builder->cron($systemTask['cron_expression']);
135+
}
136+
137+
$builder->schedule();
138+
139+
$output->writeln(sprintf(' * System-task "%s" was <info>created</info>.', $systemKey));
140+
}
141+
142+
/**
143+
* Disable task identified by system-key.
144+
*
145+
* @param string $systemKey
146+
*/
147+
private function disableTask($systemKey)
148+
{
149+
if (!$task = $this->taskRepository->findBySystemKey($systemKey)) {
150+
return;
151+
}
152+
153+
$task->setInterval($task->getInterval(), $task->getFirstExecution(), new \DateTime());
154+
$this->removePending($task);
155+
}
156+
157+
/**
158+
* Update given task.
159+
*
160+
* @param string $systemKey
161+
* @param array $systemTask
162+
* @param TaskInterface $task
163+
*/
164+
private function updateTask($systemKey, array $systemTask, TaskInterface $task)
165+
{
166+
if ($task->getHandlerClass() !== $systemTask['handler_class']
167+
|| $task->getWorkload() !== $systemTask['workload']
168+
) {
169+
throw new \InvalidArgumentException(
170+
sprintf('No update of handle-class or workload is supported for system-task "%s".', $systemKey)
171+
);
172+
}
173+
174+
if ($task->getInterval() === $systemTask['cron_expression']) {
175+
return;
176+
}
177+
178+
$task->setInterval(CronExpression::factory($systemTask['cron_expression']), $task->getFirstExecution());
179+
180+
$this->removePending($task);
181+
$this->scheduler->scheduleTasks();
182+
}
183+
184+
/**
185+
* Remove pending execution for given task.
186+
*
187+
* @param TaskInterface $task
188+
*/
189+
private function removePending(TaskInterface $task)
190+
{
191+
if (!$execution = $this->taskExecutionRepository->findPending($task)) {
192+
return;
193+
}
194+
195+
$this->taskExecutionRepository->remove($execution);
196+
}
197+
}

src/DependencyInjection/Configuration.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ public function getConfigTreeBuilder()
4949
->end()
5050
->end()
5151
->end()
52+
->arrayNode('system_tasks')
53+
->prototype('array')
54+
->children()
55+
->booleanNode('enabled')->defaultTrue()->end()
56+
->scalarNode('handler_class')->end()
57+
->variableNode('workload')->defaultNull()->end()
58+
->scalarNode('cron_expression')->end()
59+
->end()
60+
->end()
61+
->end()
5262
->end();
5363

5464
return $treeBuilder;

src/DependencyInjection/TaskExtension.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ public function load(array $configs, ContainerBuilder $container)
3434
$configuration = new Configuration();
3535
$config = $this->processConfiguration($configuration, $configs);
3636

37+
$container->setParameter('task.system_tasks', $config['system_tasks']);
38+
$container->setParameter('task.storage', $config['storage']);
39+
3740
$loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
3841
$loader->load(sprintf('storage/%s.xml', $config['storage']));
3942
$loader->load('task_event_listener.xml');

0 commit comments

Comments
 (0)