Skip to content

Commit 33b0f63

Browse files
implemented prototype of system-tasks
1 parent a5a7535 commit 33b0f63

File tree

9 files changed

+320
-0
lines changed

9 files changed

+320
-0
lines changed

src/Builder/NotSupportedException.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace Task\TaskBundle\Builder;
4+
5+
use Task\TaskInterface;
6+
7+
/**
8+
* TODO add description here
9+
*/
10+
class NotSupportedException extends \Exception
11+
{
12+
/**
13+
* @var string
14+
*/
15+
private $property;
16+
17+
/**
18+
* @var TaskInterface
19+
*/
20+
private $task;
21+
22+
/**
23+
* @param string $property
24+
* @param TaskInterface $task
25+
*/
26+
public function __construct($property, TaskInterface $task)
27+
{
28+
parent::__construct(
29+
sprintf('Property "%s" is not supported for task-class "%s".', $property, get_class($task))
30+
);
31+
32+
$this->property = $property;
33+
$this->task = $task;
34+
}
35+
36+
/**
37+
* Returns property.
38+
*
39+
* @return string
40+
*/
41+
public function getProperty()
42+
{
43+
return $this->property;
44+
}
45+
46+
/**
47+
* Returns task.
48+
*
49+
* @return TaskInterface
50+
*/
51+
public function getTask()
52+
{
53+
return $this->task;
54+
}
55+
}

src/Builder/TaskBuilder.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace Task\TaskBundle\Builder;
4+
5+
use Task\Builder\TaskBuilder as BaseTaskBuilder;
6+
use Task\Builder\TaskBuilderInterface;
7+
use Task\TaskBundle\Entity\Task;
8+
9+
/**
10+
* TODO add description here
11+
*/
12+
class TaskBuilder extends BaseTaskBuilder
13+
{
14+
/**
15+
* Set system-key.
16+
*
17+
* @param string $systemKey
18+
*
19+
* @return TaskBuilderInterface
20+
*
21+
* @throws NotSupportedException
22+
*/
23+
public function setSystemKey($systemKey)
24+
{
25+
if (!$this->task instanceof Task) {
26+
throw new NotSupportedException('systemKey', $this->task);
27+
}
28+
29+
$this->task->setSystemKey($systemKey);
30+
31+
return $this;
32+
}
33+
}

src/Builder/TaskBuilderFactory.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Task\TaskBundle\Builder;
4+
5+
use Task\Builder\TaskBuilderFactoryInterface;
6+
use Task\Scheduler\TaskSchedulerInterface;
7+
use Task\TaskInterface;
8+
9+
/**
10+
* TODO add description here
11+
*/
12+
class TaskBuilderFactory implements TaskBuilderFactoryInterface
13+
{
14+
/**
15+
* {@inheritdoc}
16+
*/
17+
public function createTaskBuilder(TaskInterface $task, TaskSchedulerInterface $taskScheduler)
18+
{
19+
return new TaskBuilder($task, $taskScheduler);
20+
}
21+
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
<?php
2+
3+
namespace 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+
14+
/**
15+
* TODO add description here
16+
*/
17+
class ScheduleSystemTasksCommand extends Command
18+
{
19+
/**
20+
* @var array
21+
*/
22+
private $systemTasks;
23+
24+
/**
25+
* @var string
26+
*/
27+
private $storage;
28+
29+
/**
30+
* @var TaskSchedulerInterface
31+
*/
32+
private $scheduler;
33+
34+
/**
35+
* @var TaskRepository
36+
*/
37+
private $taskRepository;
38+
39+
/**
40+
* @var TaskExecutionRepositoryInterface
41+
*/
42+
private $taskExecutionRepository;
43+
44+
/**
45+
* @param string $name
46+
* @param array $systemTasks
47+
* @param string $storage
48+
* @param TaskSchedulerInterface $scheduler
49+
* @param TaskRepository $taskRepository
50+
* @param TaskExecutionRepositoryInterface $taskExecutionRepository
51+
*/
52+
public function __construct(
53+
$name,
54+
array $systemTasks,
55+
$storage,
56+
TaskSchedulerInterface $scheduler,
57+
TaskRepository $taskRepository,
58+
TaskExecutionRepositoryInterface $taskExecutionRepository
59+
) {
60+
parent::__construct($name);
61+
62+
$this->systemTasks = $systemTasks;
63+
$this->storage = $storage;
64+
$this->scheduler = $scheduler;
65+
$this->taskRepository = $taskRepository;
66+
$this->taskExecutionRepository = $taskExecutionRepository;
67+
}
68+
69+
/**
70+
* {@inheritdoc}
71+
*/
72+
protected function configure()
73+
{
74+
$this->setDescription('Schedule task')->setHelp(
75+
<<<'EOT'
76+
The <info>%command.name%</info> command schedules configured system tasks.
77+
78+
$ %command.full_name%
79+
80+
You can configure them by extending the <info>task.system_task</info> array in your config file.
81+
EOT
82+
);
83+
}
84+
85+
/**
86+
* {@inheritdoc}
87+
*/
88+
protected function execute(InputInterface $input, OutputInterface $output)
89+
{
90+
foreach ($this->systemTasks as $systemKey => $systemTask) {
91+
if (!$systemTask['enabled']) {
92+
if ($task = $this->taskRepository->findBySystemKey($systemKey)) {
93+
$task->setInterval($task->getInterval(), $task->getFirstExecution(), new \DateTime());
94+
95+
if ($execution = $this->taskExecutionRepository->findPending($task)) {
96+
$this->taskExecutionRepository->remove($execution);
97+
}
98+
}
99+
100+
continue;
101+
}
102+
103+
if ($task = $this->taskRepository->findBySystemKey($systemKey)) {
104+
if ($task->getHandlerClass() !== $systemTask['handler_class']
105+
|| $task->getWorkload() !== $systemTask['workload']
106+
) {
107+
throw new \InvalidArgumentException(
108+
sprintf('No update of handle-class or workload is supported for system-task "%s".', $systemKey)
109+
);
110+
}
111+
112+
if ($task->getInterval() !== $systemTask['cron_expression']) {
113+
$task->setInterval(CronExpression::factory($systemTask['cron_expression']));
114+
115+
if ($execution = $this->taskExecutionRepository->findPending($task)) {
116+
$this->taskExecutionRepository->remove($execution);
117+
}
118+
119+
$this->scheduler->scheduleTasks();
120+
}
121+
122+
continue;
123+
}
124+
125+
/** @var TaskBuilder $builder */
126+
$builder = $this->scheduler->createTask($systemTask['handler_class'], $systemTask['workload']);
127+
$builder->setSystemKey($systemKey);
128+
if ($systemTask['cron_expression']) {
129+
$builder->cron($systemTask['cron_expression']);
130+
}
131+
132+
$builder->schedule();
133+
}
134+
}
135+
136+
/**
137+
* {@inheritdoc}
138+
*/
139+
public function isEnabled()
140+
{
141+
return $this->storage === 'doctrine';
142+
}
143+
}

src/DependencyInjection/Configuration.php

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

5465
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');

src/Entity/Task.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ class Task extends BaseTask
2424
*/
2525
private $intervalExpression;
2626

27+
/**
28+
* @var string
29+
*/
30+
private $systemKey;
31+
2732
/**
2833
* @return mixed
2934
*/
@@ -32,6 +37,9 @@ public function getIntervalExpression()
3237
return $this->intervalExpression;
3338
}
3439

40+
/**
41+
* {@inheritdoc}
42+
*/
3543
public function getInterval()
3644
{
3745
if (null === $this->interval && null !== $this->intervalExpression) {
@@ -50,4 +58,28 @@ public function setInterval(CronExpression $interval, \DateTime $firstExecution
5058

5159
$this->intervalExpression = $interval->getExpression();
5260
}
61+
62+
/**
63+
* Returns system-key.
64+
*
65+
* @return string
66+
*/
67+
public function getSystemKey()
68+
{
69+
return $this->systemKey;
70+
}
71+
72+
/**
73+
* Set system-key.
74+
*
75+
* @param string $systemKey
76+
*
77+
* @return $this
78+
*/
79+
public function setSystemKey($systemKey)
80+
{
81+
$this->systemKey = $systemKey;
82+
83+
return $this;
84+
}
5385
}

src/Entity/TaskRepository.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Task\TaskBundle\Entity;
1313

1414
use Doctrine\ORM\EntityRepository;
15+
use Doctrine\ORM\NoResultException;
1516
use Task\Storage\TaskRepositoryInterface;
1617
use Task\TaskInterface;
1718

@@ -97,4 +98,24 @@ public function findEndBefore(\DateTime $dateTime)
9798
->getQuery()
9899
->getResult();
99100
}
101+
102+
/**
103+
* Returns task identified by system-key.
104+
*
105+
* @param string $systemKey
106+
*
107+
* @return TaskInterface
108+
*/
109+
public function findBySystemKey($systemKey)
110+
{
111+
try {
112+
return $this->createQueryBuilder('t')
113+
->where('t.systemKey = :systemKey')
114+
->setParameter('systemKey', $systemKey)
115+
->getQuery()
116+
->getSingleResult();
117+
} catch (NoResultException $exception) {
118+
return;
119+
}
120+
}
100121
}

src/Resources/config/doctrine/Task.orm.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<field name="intervalExpression" type="string" length="255" nullable="true"/>
1818
<field name="firstExecution" type="datetime" nullable="true"/>
1919
<field name="lastExecution" type="datetime" nullable="true"/>
20+
<field name="systemKey" type="string" nullable="true" unique="true"/>
2021
<field name="workload" type="object"/>
2122

2223
</entity>

0 commit comments

Comments
 (0)