Passed
Pull Request — master (#18)
by Harry
04:35 queued 23s
created

CallbackRun::start()   A

Complexity

Conditions 4
Paths 30

Size

Total Lines 29
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 4.1878

Importance

Changes 0
Metric Value
eloc 23
dl 0
loc 29
rs 9.552
c 0
b 0
f 0
ccs 17
cts 22
cp 0.7727
cc 4
nc 30
nop 0
crap 4.1878
1
<?php
2
/**
3
 * This file is part of graze/parallel-process.
4
 *
5
 * Copyright © 2018 Nature Delivered Ltd. <https://www.graze.com>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license https://github.com/graze/parallel-process/blob/master/LICENSE.md
11
 * @link    https://github.com/graze/parallel-process
12
 */
13
14
namespace Graze\ParallelProcess;
15
16
use Exception;
17
use Graze\ParallelProcess\Event\EventDispatcherTrait;
18
use Graze\ParallelProcess\Event\RunEvent;
19
use Throwable;
20
21
class CallbackRun implements RunInterface, OutputterInterface
22
{
23
    use EventDispatcherTrait;
24
    use RunningStateTrait;
25
26
    /** @var callable */
27
    private $callback;
28
    /** @var bool */
29
    private $successful = false;
30
    /** @var string[] */
31
    private $tags;
32
    /** @var Exception|Throwable|null */
33
    private $exception = null;
34
    /** @var string */
35
    private $last;
36
    /** @var float */
37
    private $priority;
38
39
    /**
40
     * Run constructor.
41
     *
42
     * @param callable $callback A callback to run, if this returns a string, it can be accessed from the
43
     *                           `->getLastMessage()` calls
44
     * @param string[] $tags     List of key value tags associated with this run
45
     * @param float    $priority
46
     */
47 24
    public function __construct(callable $callback, array $tags = [], $priority = 1.0)
48
    {
49 24
        $this->callback = $callback;
50 24
        $this->tags = $tags;
51 24
        $this->priority = $priority;
52 24
    }
53
54
    /**
55
     * @param float $priority
56
     *
57
     * @return CallbackRun
58
     */
59
    public function setPriority($priority)
60
    {
61
        $this->priority = $priority;
62
        return $this;
63
    }
64
65
    /**
66
     * @return string[]
67
     */
68 22
    protected function getEventNames()
69
    {
70
        return [
71 22
            RunEvent::STARTED,
72 22
            RunEvent::COMPLETED,
73 22
            RunEvent::SUCCESSFUL,
74 22
            RunEvent::FAILED,
75 22
            RunEvent::UPDATED,
76
        ];
77
    }
78
79
    /**
80
     * Start the process
81
     *
82
     * @return $this
83
     */
84 19
    public function start()
85
    {
86 19
        if (!$this->hasStarted()) {
87 19
            $this->setStarted();
88 19
            $this->dispatch(RunEvent::STARTED, new RunEvent($this));
89
            try {
90
                try {
91 19
                    $output = call_user_func($this->callback);
92 15
                    $this->handleOutput($output);
93 15
                    $this->setFinished();
94 15
                    $this->successful = true;
95 15
                    $this->dispatch(RunEvent::SUCCESSFUL, new RunEvent($this));
96 4
                } catch (Exception $e) {
97 4
                    $this->setFinished();
98 4
                    $this->successful = false;
99 4
                    $this->exception = $e;
100 4
                    $this->dispatch(RunEvent::FAILED, new RunEvent($this));
101
                } catch (Throwable $e) {
102
                    $this->setFinished();
103
                    $this->successful = false;
104
                    $this->exception = $e;
105
                    $this->dispatch(RunEvent::FAILED, new RunEvent($this));
106
                }
107 19
            } finally {
108 19
                $this->dispatch(RunEvent::COMPLETED, new RunEvent($this));
109
            }
110
        }
111
112 19
        return $this;
113
    }
114
115
    /**
116
     * @param mixed $output The output from the callback, if you want to send this back, return a string|string[]
117
     */
118 15
    private function handleOutput($output)
119
    {
120 15
        if (is_string($output)) {
121 1
            $output = explode("\n", $output);
122
        }
123 15
        if (is_array($output)) {
124 2
            foreach ($output as $line) {
125 2
                if (is_string($line)) {
126 2
                    $line = rtrim($line);
127 2
                    if (mb_strlen($line) > 0) {
128 2
                        $this->last = $line;
129 2
                        $this->dispatch(RunEvent::UPDATED, new RunEvent($this));
130
                    }
131
                }
132
            }
133
        }
134 15
    }
135
136
    /**
137
     * Poll to see if the callback is still running (hint: it is not)
138
     *
139
     * @return bool
140
     */
141 6
    public function poll()
142
    {
143
        // non async process, so it will have finished when calling start
144 6
        return false;
145
    }
146
147
    /**
148
     * Return if the underlying process is running
149
     *
150
     * @return bool
151
     */
152 18
    public function isRunning()
153
    {
154 18
        return false;
155
    }
156
157
    /**
158
     * @return bool
159
     */
160 16
    public function isSuccessful()
161
    {
162 16
        return $this->successful;
163
    }
164
165
    /**
166
     * @return bool
167
     */
168 23
    public function hasStarted()
169
    {
170 23
        return $this->getState() !== RunInterface::STATE_NOT_STARTED;
171
    }
172
173
    /**
174
     * @return array
175
     */
176 8
    public function getTags()
177
    {
178 8
        return $this->tags;
179
    }
180
181
    /**
182
     * @return float[]|null the process between 0 and 1 if the run supports it, otherwise null
183
     */
184 8
    public function getProgress()
185
    {
186 8
        return null;
187
    }
188
189
    /**
190
     * If the run was unsuccessful, get the error if applicable
191
     *
192
     * @return Exception[]|Throwable[]
193
     */
194 5
    public function getExceptions()
195
    {
196 5
        if ($this->exception !== null) {
197 4
            return [$this->exception];
198
        }
199 1
        return [];
200
    }
201
202
    /**
203
     * Get the last message that this thing produced
204
     *
205
     * @return string
206
     */
207 3
    public function getLastMessage()
208
    {
209 3
        return $this->last;
210
    }
211
212
    /**
213
     * @return string
214
     */
215 1
    public function getLastMessageType()
216
    {
217 1
        return '';
218
    }
219
220
    /**
221
     * @return float The priority for this run, where the larger the number the higher the priority
222
     */
223 8
    public function getPriority()
224
    {
225 8
        return $this->priority;
226
    }
227
}
228