Task::getInput()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 0
1
<?php
2
3
/**
4
 * This file is part of tenside/core.
5
 *
6
 * (c) Christian Schiffler <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * This project is provided in good faith and hope to be usable by anyone.
12
 *
13
 * @package    tenside/core
14
 * @author     Christian Schiffler <[email protected]>
15
 * @copyright  2015 Christian Schiffler <[email protected]>
16
 * @license    https://github.com/tenside/core/blob/master/LICENSE MIT
17
 * @link       https://github.com/tenside/core
18
 * @filesource
19
 */
20
21
namespace Tenside\Core\Task;
22
23
use Composer\IO\ConsoleIO;
24
use Composer\IO\IOInterface;
25
use Symfony\Component\Console\Helper\HelperSet;
26
use Symfony\Component\Console\Input\ArrayInput;
27
use Symfony\Component\Console\Input\InputInterface;
28
use Tenside\Core\Util\JsonArray;
29
30
/**
31
 * Abstract base class for tasks.
32
 */
33
abstract class Task
34
{
35
    /**
36
     * The type of the task.
37
     */
38
    const SETTING_TYPE = 'type';
39
40
    /**
41
     * The id of the task.
42
     */
43
    const SETTING_ID = 'id';
44
45
    /**
46
     * The ISO 8601 date when the task got created.
47
     */
48
    const SETTING_CREATED_AT = 'created-at';
49
50
    /**
51
     * The user data.
52
     */
53
    const SETTING_USER_DATA = 'user-data';
54
55
    /**
56
     * This state determines that the task is still awaiting to be executed.
57
     */
58
    const STATE_PENDING = 'PENDING';
59
60
    /**
61
     * This state determines that the task is still running.
62
     */
63
    const STATE_RUNNING = 'RUNNING';
64
65
    /**
66
     * This state determines that the task has been finished.
67
     */
68
    const STATE_FINISHED = 'FINISHED';
69
70
    /**
71
     * This state determines that the task has been finished with errors.
72
     */
73
    const STATE_ERROR = 'ERROR';
74
75
    /**
76
     * The task file to write to.
77
     *
78
     * @var JsonArray
79
     */
80
    protected $file;
81
82
    /**
83
     * The log file to write to.
84
     *
85
     * @var string
86
     */
87
    protected $logFile;
88
89
    /**
90
     * The input/output handler.
91
     *
92
     * @var IOInterface
93
     */
94
    private $inputOutput;
95
96
    /**
97
     * Task constructor.
98
     *
99
     * @param JsonArray $file The json file to write to.
100
     */
101
    public function __construct(JsonArray $file)
102
    {
103
        $this->file = $file;
104
105
        if ($this->file->has('log')) {
106
            $this->logFile = $this->file->get('log');
107
        }
108
    }
109
110
    /**
111
     * Retrieve the task id.
112
     *
113
     * @return string
114
     */
115
    public function getId()
116
    {
117
        return $this->file->get('id');
118
    }
119
120
    /**
121
     * Retrieve the current output.
122
     *
123
     * @param null|int $offset The offset in bytes to read from.
124
     *
125
     * @return string
126
     */
127
    public function getOutput($offset = null)
128
    {
129
        if (!$this->logFile) {
130
            return '';
131
        }
132
133
        return (string) file_get_contents($this->logFile, FILE_BINARY, null, $offset);
134
    }
135
136
    /**
137
     * Retrieve the task type name.
138
     *
139
     * @return string
140
     */
141
    abstract public function getType();
142
143
    /**
144
     * Perform the task.
145
     *
146
     * @param string $logFile The log file to write to.
147
     *
148
     * @return void
149
     *
150
     * @throws \LogicException   When the task has already been run.
151
     *
152
     * @throws \RuntimeException When the execution. failed.
153
     */
154
    public function perform($logFile)
155
    {
156
        if (self::STATE_PENDING !== $this->getStatus()) {
157
            throw new \LogicException('Attempted to run task ' . $this->getId() . ' twice.');
158
        }
159
160
        try {
161
            if (!is_dir(dirname($logFile))) {
162
                mkdir(dirname($logFile), 0777, true);
163
            }
164
165
            file_put_contents($logFile, '', FILE_BINARY);
166
167
            $this->logFile = $logFile;
168
            $this->file->set('log', $logFile);
169
170
            $this->setStatus(self::STATE_RUNNING);
171
            $this->addOutput('Task ' . $this->getId() . ' started.' . "\n");
172
173
            $this->doPerform();
174
        } catch (\Exception $exception) {
175
            $this->addOutput('--------------------------------------------------------' . "\n");
176
            $this->addOutput('Exception occured: ' . $exception->getMessage() . "\n");
177
            $this->addOutput($exception->getTraceAsString() . "\n");
178
            $loopException = $exception;
179
            while ($loopException = $loopException->getPrevious()) {
180
                $this->addOutput('Chained exception: ' . $loopException->getMessage() . "\n");
181
                $this->addOutput($loopException->getTraceAsString() . "\n");
182
            }
183
            $this->addOutput('--------------------------------------------------------' . "\n");
184
185
            $this->setStatus(self::STATE_ERROR);
186
187
            throw new \RuntimeException(
188
                'Task ' . $this->getId() . ' errored: ' . $exception->getMessage(),
189
                1,
190
                $exception
191
            );
192
        }
193
194
        $this->addOutput('Finished without error.' . "\n");
195
        $this->setStatus(self::STATE_FINISHED);
196
    }
197
198
    /**
199
     * Perform the task.
200
     *
201
     * @return void
202
     */
203
    abstract public function doPerform();
204
205
    /**
206
     * Add some output.
207
     *
208
     * @param string $string The output string to append to the output.
209
     *
210
     * @return void
211
     *
212
     * @throws \LogicException When called prior to perform().
213
     */
214
    public function addOutput($string)
215
    {
216
        if (!$this->logFile) {
217
            throw new \LogicException('The has not started to run yet.');
218
        }
219
220
        file_put_contents($this->logFile, $string, (FILE_APPEND | FILE_BINARY));
221
    }
222
223
    /**
224
     * Retrieve the IO interface.
225
     *
226
     * @return IOInterface
227
     */
228
    public function getIO()
229
    {
230
        if (!isset($this->inputOutput)) {
231
            $this->inputOutput = new ConsoleIO($this->getInput(), new TaskOutput($this), new HelperSet([]));
232
        }
233
234
        return $this->inputOutput;
235
    }
236
237
    /**
238
     * Retrieve the current status of a task.
239
     *
240
     * @return string
241
     */
242
    public function getStatus()
243
    {
244
        return $this->file->get('status');
245
    }
246
247
    /**
248
     * Retrieve when this task got created as ISO 8601 date string.
249
     *
250
     * @return \DateTime
251
     */
252
    public function getCreatedAt()
253
    {
254
        return \DateTime::createFromFormat(DATE_ISO8601, $this->file->get(self::SETTING_CREATED_AT));
255
    }
256
257
    /**
258
     * Retrieve the user submitted payload.
259
     *
260
     * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be array|string|integer|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
261
     */
262
    public function getUserData()
263
    {
264
        return $this->file->get(self::SETTING_USER_DATA);
265
    }
266
267
    /**
268
     * Remove the attached files for this task from disk.
269
     *
270
     * @return void
271
     */
272
    public function removeAssets()
273
    {
274
        // Base implementation does only know about log file.
275
        if ($this->logFile) {
276
            if (file_exists($this->logFile)) {
277
                unlink($this->logFile);
278
            }
279
            $this->logFile = null;
280
            $this->file->remove('log');
281
        }
282
    }
283
284
    /**
285
     * Mark the task errored.
286
     *
287
     * @return void
288
     */
289
    public function markError()
290
    {
291
        $this->setStatus(self::STATE_ERROR);
292
    }
293
294
    /**
295
     * Set the task state.
296
     *
297
     * @param string $status The status code.
298
     *
299
     * @return void
300
     */
301
    protected function setStatus($status)
302
    {
303
        $this->file->set('status', $status);
304
    }
305
306
    /**
307
     * Retrieve the Input handler.
308
     *
309
     * @return InputInterface
310
     */
311
    private function getInput()
312
    {
313
        $input = new ArrayInput([]);
314
315
        $input->setInteractive(false);
316
317
        return $input;
318
    }
319
}
320