Completed
Push — master ( 3776e9...4c421f )
by Anton
01:27
created

JobFileRepository   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 164
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 25
lcom 1
cbo 4
dl 0
loc 164
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A all() 0 11 2
A getById() 0 14 3
A deleteById() 0 22 4
A store() 0 8 1
A changeJobStatus() 0 25 4
A changeJobExitCode() 0 13 3
A getIndex() 0 8 2
A putIndex() 0 4 1
A getJobProcessOutput() 0 10 2
A deleteJobProcessOutput() 0 5 1
A getIndexFilePath() 0 4 1
1
<?php
2
3
/*
4
 * This file is part of Laravel Paket.
5
 *
6
 * (c) Anton Komarev <[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
12
declare(strict_types=1);
13
14
namespace Cog\Laravel\Paket\Job\Repositories;
15
16
use Cog\Contracts\Paket\Job\Entities\Job as JobContract;
17
use Cog\Contracts\Paket\Job\Repositories\Job as JobRepositoryContract;
18
use Cog\Laravel\Paket\Job\Entities\Job;
19
use Illuminate\Contracts\Filesystem\FileNotFoundException;
20
use Illuminate\Filesystem\Filesystem;
21
use RuntimeException;
22
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
23
24
final class JobFileRepository implements JobRepositoryContract
25
{
26
    /**
27
     * The filesystem instance.
28
     *
29
     * @var \Illuminate\Filesystem\Filesystem
30
     */
31
    private $files;
32
33
    /**
34
     * The path to store jobs data.
35
     *
36
     * @var string
37
     */
38
    private $storagePath;
39
40
    /**
41
     * Create a new job file repository instance.
42
     *
43
     * @param \Illuminate\Filesystem\Filesystem $files
44
     * @param string $storagePath
45
     */
46
    public function __construct(Filesystem $files, string $storagePath)
47
    {
48
        $this->files = $files;
49
        $this->storagePath = $storagePath;
50
    }
51
52
    public function all(): iterable
53
    {
54
        $index = $this->getIndex();
55
56
        $jobs = [];
57
        foreach ($index as $job) {
58
            $jobs[] = Job::fromArray($job);
59
        }
60
61
        return $jobs;
62
    }
63
64
    public function getById(string $id): JobContract
65
    {
66
        $index = $this->getIndex();
67
68
        foreach ($index as $job) {
69
            if ($job['id'] === $id) {
70
                $job['process']['output'] = $this->getJobProcessOutput($job['id']);
71
72
                return Job::fromArray($job);
73
            }
74
        }
75
76
        throw new NotFoundHttpException("Job with id `{$id}` not found.");
77
    }
78
79
    // TODO: [v2.0] Add to contract
80
    public function deleteById(string $id): void
81
    {
82
        $index = $this->getIndex();
83
84
        foreach ($index as $key => $job) {
85
            if ($job['id'] === $id) {
86
                $jobKey = $key;
87
                break;
88
            }
89
        }
90
91
        if (!isset($jobKey)) {
92
            throw new NotFoundHttpException("Job with id `{$id}` not found.");
93
        }
94
95
        unset($index[$jobKey]);
96
        $index = array_values($index);
97
98
        $this->deleteJobProcessOutput($id);
99
100
        $this->putIndex($index);
101
    }
102
103
    public function store(JobContract $job): void
104
    {
105
        $index = $this->getIndex();
106
107
        $index[] = $job->toArray();
108
109
        $this->putIndex($index);
110
    }
111
112
    public function changeJobStatus(JobContract $job, string $statusName): void
113
    {
114
        $names = [
115
            'Pending',
116
            'Running',
117
            'Success',
118
            'Failed',
119
        ];
120
121
        if (!in_array($statusName, $names)) {
122
            // TODO: Throw custom exception
123
            throw new RuntimeException('Unknown job status');
124
        }
125
126
        $index = $this->getIndex();
127
128
        foreach ($index as $key => $record) {
129
            if ($record['id'] === $job->getId()) {
130
                $index[$key]['status'] = $statusName;
131
                break;
132
            }
133
        }
134
135
        $this->putIndex($index);
136
    }
137
138
    public function changeJobExitCode(JobContract $job, int $exitCode): void
139
    {
140
        $index = $this->getIndex();
141
142
        foreach ($index as $key => $record) {
143
            if ($record['id'] === $job->getId()) {
144
                $index[$key]['process']['exitCode'] = $exitCode;
145
                break;
146
            }
147
        }
148
149
        $this->putIndex($index);
150
    }
151
152
    private function getIndex(): array
153
    {
154
        try {
155
            return json_decode($this->files->get($this->getIndexFilePath(), $isLocked = true), true);
156
        } catch (FileNotFoundException $exception) {
157
            return [];
158
        }
159
    }
160
161
    private function putIndex(iterable $index): void
162
    {
163
        $this->files->put($this->getIndexFilePath(), json_encode($index));
164
    }
165
166
    private function getJobProcessOutput(string $jobId): string
167
    {
168
        $path = sprintf('%s/jobs/%s.log', $this->storagePath, $jobId);
169
170
        try {
171
            return $this->files->get($path);
172
        } catch (FileNotFoundException $exception) {
173
            return '';
174
        }
175
    }
176
177
    private function deleteJobProcessOutput(string $jobId): void
178
    {
179
        $path = sprintf('%s/jobs/%s.log', $this->storagePath, $jobId);
180
        $this->files->delete($path);
181
    }
182
183
    private function getIndexFilePath(): string
184
    {
185
        return $this->storagePath . '/jobs.json';
186
    }
187
}
188