Completed
Push — master ( c8f254...58a54b )
by Wachter
11:56 queued 07:10
created

Scheduler::createTaskAndSchedule()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 2
Bugs 0 Features 2
Metric Value
c 2
b 0
f 2
dl 0
loc 14
ccs 6
cts 6
cp 1
rs 9.4286
cc 3
eloc 7
nc 4
nop 4
crap 3
1
<?php
2
/*
3
 * This file is part of PHP-Task library.
4
 *
5
 * (c) php-task
6
 *
7
 * This source file is subject to the MIT license that is bundled
8
 * with this source code in the file LICENSE.
9
 */
10
11
namespace Task;
12
13
use Psr\Log\LoggerInterface;
14
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
15
use Task\Event\Events;
16
use Task\Event\TaskEvent;
17
use Task\Event\TaskFailedEvent;
18
use Task\FrequentTask\FrequentTaskInterface;
19
use Task\Handler\RegistryInterface;
20
use Task\Storage\StorageInterface;
21
22
/**
23
 * Central component which handles tasks.
24
 *
25
 * Allows to create and run tasks.
26
 *
27
 * @author Johannes Wachter <@wachterjohannes>
28
 */
29
class Scheduler implements SchedulerInterface
30
{
31
    /**
32
     * @var StorageInterface
33
     */
34
    private $storage;
35
36
    /**
37
     * @var RegistryInterface
38
     */
39
    private $registry;
40
41
    /**
42
     * @var TaskBuilderFactoryInterface
43
     */
44
    private $factory;
45
46
    /**
47
     * @var EventDispatcherInterface
48
     */
49
    private $eventDispatcher;
50
51
    /**
52
     * @var LoggerInterface
53
     */
54
    private $logger;
55
56 11
    public function __construct(
57
        StorageInterface $storage,
58
        RegistryInterface $registry,
59
        TaskBuilderFactoryInterface $factory,
60
        EventDispatcherInterface $eventDispatcher,
61
        LoggerInterface $logger = null
62
    ) {
63 11
        $this->storage = $storage;
64 11
        $this->registry = $registry;
65 11
        $this->factory = $factory;
66 11
        $this->eventDispatcher = $eventDispatcher;
67 11
        $this->logger = $logger;
68 11
    }
69
70
    /**
71
     * {@inheritdoc}
72
     */
73 1
    public function createTask($handlerName, $workload = null)
74
    {
75 1
        return $this->factory->create($this, $handlerName, $workload);
0 ignored issues
show
Bug introduced by
It seems like $workload defined by parameter $workload on line 73 can also be of type null; however, Task\TaskBuilderFactoryInterface::create() does only seem to accept string|object<Serializable>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
76
    }
77
78
    /**
79
     * {@inheritdoc}
80
     */
81 4
    public function createTaskAndSchedule($handlerName, $workload = null, $interval = null, $key = null)
82
    {
83 4
        $taskBuilder = $this->createTask($handlerName, $workload);
84 2
85
        if ($interval) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $interval of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
86
            $taskBuilder->{$interval}();
87 2
        }
88 2
89
        if ($key) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $key of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
90
            $taskBuilder->setKey($key);
91
        }
92
93 6
        return $taskBuilder->schedule();
94
    }
95
96 6
    /**
97 4
     * {@inheritdoc}
98
     */
99
    public function schedule(TaskInterface $task)
100
    {
101
        if (!$this->registry->has($task->getTaskName())) {
102 4
            throw new \Exception($this->getNoHandlerFoundMessage($task));
103
        }
104
105 4
        $this->storage->store($task);
106
107 4
        return $task;
108 4
    }
109
110 4
    /**
111
     * {@inheritdoc}
112 4
     */
113 4
    public function run()
114
    {
115
        /** @var TaskInterface $task */
116
        foreach ($this->storage->findScheduled() as $task) {
117
            if (!$this->registry->has($task->getTaskName())) {
118
                $this->warning($this->getNoHandlerFoundMessage($task));
119
                continue;
120
            }
121 4
122
            $this->eventDispatcher->dispatch(Events::TASK_BEFORE, new TaskEvent($task));
123
124 4
            try {
125 2
                $result = $this->registry->run($task->getTaskName(), $task->getWorkload());
126 2
127 6
                $task->setResult($result);
128 6
                $task->setCompleted();
129
130
                $this->storage->persist($task);
131
132
                $this->eventDispatcher->dispatch(Events::TASK_PASSED, new TaskEvent($task));
133
            } catch (\Exception $ex) {
134
                // TODO set task failed. failed tasks, can be restarted by adding a flag to run command.
135
136
                $this->eventDispatcher->dispatch(Events::TASK_FAILED, new TaskFailedEvent($task, $ex));
137 2
138
                throw $ex;
139 2
            }
140
141
            $this->eventDispatcher->dispatch(Events::TASK_AFTER, new TaskEvent($task));
142
143
            // TODO move to event-dispatcher
144
            if ($task instanceof FrequentTaskInterface) {
145
                $task->scheduleNext($this);
146
            }
147
        }
148
    }
149
150
    /**
151
     * Returns message for "no handler found".
152
     *
153
     * @param TaskInterface $task
154
     *
155
     * @return string
156
     */
157
    private function getNoHandlerFoundMessage(TaskInterface $task)
158
    {
159
        return sprintf('No handler found handler for "%s" task.', $task->getTaskName());
160
    }
161
162
    /**
163
     * Write a warning into log.
164
     *
165
     * @param string $message
166
     */
167
    private function warning($message)
168
    {
169
        if (null !== $this->logger) {
170
            return;
171
        }
172
173
        $this->logger->warning($message);
174
    }
175
}
176