Skip to content

Commit aaa2379

Browse files
committed
stage in array for middleware
1 parent 3361373 commit aaa2379

File tree

5 files changed

+128
-10
lines changed

5 files changed

+128
-10
lines changed

src/Commands/RmqStatsCommand.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Console\Command;
66
use Illuminate\Support\Facades\DB;
7+
use Medilies\RmQ\Facades\RmqException;
78
use Medilies\RmQ\Models\RmqFile;
89

910
class RmqStatsCommand extends Command
@@ -41,7 +42,7 @@ private function getStatusLabel(int $status): string
4142
RmqFile::STAGED => 'Staged',
4243
RmqFile::DELETED => 'Deleted',
4344
RmqFile::FAILED => 'Failed',
44-
default => 'Unknown',
45+
default => throw new RmqException("Unhandled status '{$status}'"),
4546
};
4647
}
4748
}

src/Middleware/RmqMiddleware.php

+11-3
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,26 @@
44

55
use Closure;
66
use Illuminate\Http\Request;
7-
use Medilies\RmQ\Facades\RmQ;
7+
use Illuminate\Support\Facades\Log;
8+
use Medilies\RmQ\RmQ;
89
use Symfony\Component\HttpFoundation\Response;
10+
use Throwable;
911

1012
class RmqMiddleware
1113
{
14+
public function __construct(private RmQ $rmq) {}
15+
1216
public function handle(Request $request, Closure $next): Response
1317
{
14-
// ? set singleton to stage in array
18+
$this->rmq->useArray();
1519

1620
$response = $next($request);
1721

18-
RmQ::delete();
22+
try {
23+
$this->rmq->delete();
24+
} catch (Throwable $th) {
25+
Log::error('Failed while deleting the following files ['.implode(', ', $this->rmq->getStore()).'] with error: '.$th->getMessage());
26+
}
1927

2028
return $response;
2129
}

src/RmQ.php

+80-6
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,58 @@ class RmQ
1212
{
1313
private string $instance;
1414

15+
private bool $useArray = false;
16+
17+
/** @var string[] */
18+
private array $store = [];
19+
1520
public function __construct()
1621
{
1722
$this->instance = (new Ulid)->toRfc4122();
1823
}
1924

25+
public function useArray(): static
26+
{
27+
$this->useArray = true;
28+
29+
return $this;
30+
}
31+
2032
/** @param string[]|string $paths */
2133
public function stage(array|string $paths): void
2234
{
23-
// TODO: take query builder with one selected column
35+
// TODO: take query builder with one selected column => force stageInDb
2436
// ? validate not empty or exists?
25-
// ? Stage in array and persist by the end of the process. The middleware can parametrize the singleton
2637
38+
$this->useArray ?
39+
$this->stageInArray($paths) :
40+
$this->stageInDb($paths);
41+
}
42+
43+
/** @param string[]|string $paths */
44+
private function stageInArray(array|string $paths): void
45+
{
46+
if (is_string($paths)) {
47+
$this->store[] = $paths;
48+
49+
return;
50+
}
51+
52+
/** @var string[] */
53+
$newPaths = collect($paths)
54+
->filter(fn (mixed $path) => is_string($path))
55+
->toArray();
56+
57+
$this->store = array_merge($this->store, $newPaths);
58+
}
59+
60+
/** @param string[]|string $paths */
61+
private function stageInDb(array|string $paths): void
62+
{
2763
$data = match (true) {
2864
is_string($paths) => $this->pathToRecord($paths),
2965
is_array($paths) => collect($paths)
66+
->filter(fn (mixed $path) => is_string($path))
3067
->map(fn (string $path) => $this->pathToRecord($path))
3168
->toArray(),
3269
};
@@ -36,7 +73,9 @@ public function stage(array|string $paths): void
3673

3774
public function delete(): void
3875
{
39-
$this->performDelete(true);
76+
$this->useArray ?
77+
$this->performDeleteUsingArray() :
78+
$this->performDeleteUsingDb(true);
4079
}
4180

4281
public function deleteAll(): void
@@ -47,19 +86,20 @@ public function deleteAll(): void
4786
throw new TypeError('rm-q.after must be an integer');
4887
}
4988

50-
$this->performDelete(false, $after);
89+
$this->performDeleteUsingDb(false, $after);
5190
}
5291

5392
/** @return array{path: string, instance: string} */
54-
private function pathToRecord(string $path): array
93+
private function pathToRecord(string $path, int $status = RmqFile::STAGED): array
5594
{
5695
return [
5796
'path' => $path,
5897
'instance' => $this->instance,
98+
'status' => $status,
5999
];
60100
}
61101

62-
private function performDelete(bool $filterInstance = false, int $beforeSeconds = 0): void
102+
private function performDeleteUsingDb(bool $filterInstance = false, int $beforeSeconds = 0): void
63103
{
64104
$now = Date::now();
65105

@@ -92,4 +132,38 @@ private function performDelete(bool $filterInstance = false, int $beforeSeconds
92132
]);
93133
}
94134
}
135+
136+
private function performDeleteUsingArray(): void
137+
{
138+
$now = Date::now();
139+
140+
$data = [];
141+
142+
foreach ($this->store as $path) {
143+
if (@unlink($path)) {
144+
$data[] = [
145+
'path' => $path,
146+
'instance' => $this->instance,
147+
'status' => RmqFile::DELETED,
148+
'processed_at' => $now,
149+
'deleted_at' => $now,
150+
];
151+
} else {
152+
$data[] = [
153+
'path' => $path,
154+
'instance' => $this->instance,
155+
'status' => RmqFile::FAILED,
156+
'processed_at' => $now,
157+
];
158+
}
159+
}
160+
161+
RmqFile::insert($data);
162+
}
163+
164+
/** @return string[] */
165+
public function getStore(): array
166+
{
167+
return $this->store;
168+
}
95169
}

tests/laravel/MiddlewareTest.php

+22
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,27 @@
1212
->assertStatus(200);
1313

1414
$this->assertDatabaseCount(RmqFile::tableName(), $filesCount)
15+
->assertDatabaseHas(RmqFile::tableName(), [
16+
'path' => $files[0],
17+
'status' => RmqFile::DELETED,
18+
])
1519
->assertFileDoesNotExist($files[0]);
1620
});
21+
22+
test('/test-middleware-exception', function () {
23+
/** @var OrchestraTestCase $this */
24+
$files = populateFiles(3);
25+
$filesCount = count($files);
26+
27+
$this->post('/test-middleware-exception', ['files' => $files])
28+
->assertStatus(500);
29+
30+
$this->assertDatabaseCount(RmqFile::tableName(), $filesCount)
31+
->assertDatabaseHas(RmqFile::tableName(), [
32+
'path' => $files[0],
33+
'status' => RmqFile::DELETED,
34+
])
35+
->assertFileDoesNotExist($files[0]);
36+
37+
depopulateFiles($files);
38+
});

tests/test-app/TestServiceProvider.php

+13
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Illuminate\Http\Request;
66
use Illuminate\Support\Facades\Route;
77
use Illuminate\Support\ServiceProvider;
8+
use Medilies\RmQ\Facades\RmqException;
89
use Medilies\RmQ\Middleware\RmqMiddleware;
910
use Medilies\RmQ\RmQ;
1011

@@ -21,5 +22,17 @@ public function boot(): void
2122

2223
$rmQ->stage($files);
2324
})->middleware(RmqMiddleware::class);
25+
26+
Route::post('test-middleware-exception', function (Request $request, RmQ $rmQ) {
27+
/** @var array */
28+
$files = $request->validate([
29+
'files' => 'array',
30+
'files.*' => 'string',
31+
])['files'];
32+
33+
$rmQ->stage($files);
34+
35+
throw new RmqException;
36+
})->middleware(RmqMiddleware::class);
2437
}
2538
}

0 commit comments

Comments
 (0)