From aaa2379a867c6cc49e536feb6e723a0fa6cc94c8 Mon Sep 17 00:00:00 2001 From: medilies Date: Sun, 25 Aug 2024 21:04:23 +0100 Subject: [PATCH] stage in array for middleware --- src/Commands/RmqStatsCommand.php | 3 +- src/Middleware/RmqMiddleware.php | 14 ++++- src/RmQ.php | 86 ++++++++++++++++++++++++-- tests/laravel/MiddlewareTest.php | 22 +++++++ tests/test-app/TestServiceProvider.php | 13 ++++ 5 files changed, 128 insertions(+), 10 deletions(-) diff --git a/src/Commands/RmqStatsCommand.php b/src/Commands/RmqStatsCommand.php index 62200eb..1c6ce6d 100644 --- a/src/Commands/RmqStatsCommand.php +++ b/src/Commands/RmqStatsCommand.php @@ -4,6 +4,7 @@ use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; +use Medilies\RmQ\Facades\RmqException; use Medilies\RmQ\Models\RmqFile; class RmqStatsCommand extends Command @@ -41,7 +42,7 @@ private function getStatusLabel(int $status): string RmqFile::STAGED => 'Staged', RmqFile::DELETED => 'Deleted', RmqFile::FAILED => 'Failed', - default => 'Unknown', + default => throw new RmqException("Unhandled status '{$status}'"), }; } } diff --git a/src/Middleware/RmqMiddleware.php b/src/Middleware/RmqMiddleware.php index ba7ca3f..9cf51aa 100644 --- a/src/Middleware/RmqMiddleware.php +++ b/src/Middleware/RmqMiddleware.php @@ -4,18 +4,26 @@ use Closure; use Illuminate\Http\Request; -use Medilies\RmQ\Facades\RmQ; +use Illuminate\Support\Facades\Log; +use Medilies\RmQ\RmQ; use Symfony\Component\HttpFoundation\Response; +use Throwable; class RmqMiddleware { + public function __construct(private RmQ $rmq) {} + public function handle(Request $request, Closure $next): Response { - // ? set singleton to stage in array + $this->rmq->useArray(); $response = $next($request); - RmQ::delete(); + try { + $this->rmq->delete(); + } catch (Throwable $th) { + Log::error('Failed while deleting the following files ['.implode(', ', $this->rmq->getStore()).'] with error: '.$th->getMessage()); + } return $response; } diff --git a/src/RmQ.php b/src/RmQ.php index 4f05ea1..856a25f 100755 --- a/src/RmQ.php +++ b/src/RmQ.php @@ -12,21 +12,58 @@ class RmQ { private string $instance; + private bool $useArray = false; + + /** @var string[] */ + private array $store = []; + public function __construct() { $this->instance = (new Ulid)->toRfc4122(); } + public function useArray(): static + { + $this->useArray = true; + + return $this; + } + /** @param string[]|string $paths */ public function stage(array|string $paths): void { - // TODO: take query builder with one selected column + // TODO: take query builder with one selected column => force stageInDb // ? validate not empty or exists? - // ? Stage in array and persist by the end of the process. The middleware can parametrize the singleton + $this->useArray ? + $this->stageInArray($paths) : + $this->stageInDb($paths); + } + + /** @param string[]|string $paths */ + private function stageInArray(array|string $paths): void + { + if (is_string($paths)) { + $this->store[] = $paths; + + return; + } + + /** @var string[] */ + $newPaths = collect($paths) + ->filter(fn (mixed $path) => is_string($path)) + ->toArray(); + + $this->store = array_merge($this->store, $newPaths); + } + + /** @param string[]|string $paths */ + private function stageInDb(array|string $paths): void + { $data = match (true) { is_string($paths) => $this->pathToRecord($paths), is_array($paths) => collect($paths) + ->filter(fn (mixed $path) => is_string($path)) ->map(fn (string $path) => $this->pathToRecord($path)) ->toArray(), }; @@ -36,7 +73,9 @@ public function stage(array|string $paths): void public function delete(): void { - $this->performDelete(true); + $this->useArray ? + $this->performDeleteUsingArray() : + $this->performDeleteUsingDb(true); } public function deleteAll(): void @@ -47,19 +86,20 @@ public function deleteAll(): void throw new TypeError('rm-q.after must be an integer'); } - $this->performDelete(false, $after); + $this->performDeleteUsingDb(false, $after); } /** @return array{path: string, instance: string} */ - private function pathToRecord(string $path): array + private function pathToRecord(string $path, int $status = RmqFile::STAGED): array { return [ 'path' => $path, 'instance' => $this->instance, + 'status' => $status, ]; } - private function performDelete(bool $filterInstance = false, int $beforeSeconds = 0): void + private function performDeleteUsingDb(bool $filterInstance = false, int $beforeSeconds = 0): void { $now = Date::now(); @@ -92,4 +132,38 @@ private function performDelete(bool $filterInstance = false, int $beforeSeconds ]); } } + + private function performDeleteUsingArray(): void + { + $now = Date::now(); + + $data = []; + + foreach ($this->store as $path) { + if (@unlink($path)) { + $data[] = [ + 'path' => $path, + 'instance' => $this->instance, + 'status' => RmqFile::DELETED, + 'processed_at' => $now, + 'deleted_at' => $now, + ]; + } else { + $data[] = [ + 'path' => $path, + 'instance' => $this->instance, + 'status' => RmqFile::FAILED, + 'processed_at' => $now, + ]; + } + } + + RmqFile::insert($data); + } + + /** @return string[] */ + public function getStore(): array + { + return $this->store; + } } diff --git a/tests/laravel/MiddlewareTest.php b/tests/laravel/MiddlewareTest.php index e9ac9ff..64b50f7 100644 --- a/tests/laravel/MiddlewareTest.php +++ b/tests/laravel/MiddlewareTest.php @@ -12,5 +12,27 @@ ->assertStatus(200); $this->assertDatabaseCount(RmqFile::tableName(), $filesCount) + ->assertDatabaseHas(RmqFile::tableName(), [ + 'path' => $files[0], + 'status' => RmqFile::DELETED, + ]) ->assertFileDoesNotExist($files[0]); }); + +test('/test-middleware-exception', function () { + /** @var OrchestraTestCase $this */ + $files = populateFiles(3); + $filesCount = count($files); + + $this->post('/test-middleware-exception', ['files' => $files]) + ->assertStatus(500); + + $this->assertDatabaseCount(RmqFile::tableName(), $filesCount) + ->assertDatabaseHas(RmqFile::tableName(), [ + 'path' => $files[0], + 'status' => RmqFile::DELETED, + ]) + ->assertFileDoesNotExist($files[0]); + + depopulateFiles($files); +}); diff --git a/tests/test-app/TestServiceProvider.php b/tests/test-app/TestServiceProvider.php index 0b67aa7..229a30b 100644 --- a/tests/test-app/TestServiceProvider.php +++ b/tests/test-app/TestServiceProvider.php @@ -5,6 +5,7 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; use Illuminate\Support\ServiceProvider; +use Medilies\RmQ\Facades\RmqException; use Medilies\RmQ\Middleware\RmqMiddleware; use Medilies\RmQ\RmQ; @@ -21,5 +22,17 @@ public function boot(): void $rmQ->stage($files); })->middleware(RmqMiddleware::class); + + Route::post('test-middleware-exception', function (Request $request, RmQ $rmQ) { + /** @var array */ + $files = $request->validate([ + 'files' => 'array', + 'files.*' => 'string', + ])['files']; + + $rmQ->stage($files); + + throw new RmqException; + })->middleware(RmqMiddleware::class); } }