Skip to content

Commit 657748a

Browse files
committed
handle transactions properly
1 parent aaa2379 commit 657748a

File tree

3 files changed

+78
-31
lines changed

3 files changed

+78
-31
lines changed

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,4 @@
8686
},
8787
"minimum-stability": "stable",
8888
"prefer-stable": true
89-
}
89+
}

src/Middleware/RmqMiddleware.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ public function __construct(private RmQ $rmq) {}
1515

1616
public function handle(Request $request, Closure $next): Response
1717
{
18-
$this->rmq->useArray();
18+
$this->rmq->usingMiddleware();
1919

2020
$response = $next($request);
2121

2222
try {
2323
$this->rmq->delete();
2424
} catch (Throwable $th) {
25-
Log::error('Failed while deleting the following files ['.implode(', ', $this->rmq->getStore()).'] with error: '.$th->getMessage());
25+
Log::error('Failed while deleting the following files ['.implode(', ', $this->rmq->getStorage()).'] with error: '.$th->getMessage());
2626
}
2727

2828
return $response;

src/RmQ.php

+75-28
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,55 @@
22

33
namespace Medilies\RmQ;
44

5+
use Closure;
56
use Illuminate\Support\Facades\Config;
67
use Illuminate\Support\Facades\Date;
8+
use Illuminate\Support\Facades\DB;
79
use Medilies\RmQ\Models\RmqFile;
810
use Symfony\Component\Uid\Ulid;
11+
use Throwable;
912
use TypeError;
1013

1114
class RmQ
1215
{
1316
private string $instance;
1417

15-
private bool $useArray = false;
18+
private bool $isUsingMiddleware = false;
19+
20+
private bool $isWithinTransaction = false;
21+
22+
private bool $hasFilesInDb = false;
1623

1724
/** @var string[] */
18-
private array $store = [];
25+
private array $arrayStorage = []; // ? Dto[]
26+
27+
/** @var string[] */
28+
private array $transactionStorage = [];
1929

2030
public function __construct()
2131
{
2232
$this->instance = (new Ulid)->toRfc4122();
2333
}
2434

25-
public function useArray(): static
35+
public function transaction(Closure $callback): static
2636
{
27-
$this->useArray = true;
37+
$this->withinTransaction();
38+
39+
try {
40+
DB::transaction($callback); // @phpstan-ignore-line
41+
42+
if ($this->isUsingMiddleware) {
43+
$this->arrayStorage = array_merge($this->arrayStorage, $this->transactionStorage);
44+
} else {
45+
$this->stageInDb($this->transactionStorage);
46+
}
47+
} catch (Throwable $th) {
48+
throw $th;
49+
} finally {
50+
$this->transactionStorage = [];
51+
52+
$this->withinTransaction(false);
53+
}
2854

2955
return $this;
3056
}
@@ -35,16 +61,16 @@ public function stage(array|string $paths): void
3561
// TODO: take query builder with one selected column => force stageInDb
3662
// ? validate not empty or exists?
3763
38-
$this->useArray ?
39-
$this->stageInArray($paths) :
64+
$this->isWithinTransaction ?
65+
$this->stageInTransactionStorage($paths) :
4066
$this->stageInDb($paths);
4167
}
4268

4369
/** @param string[]|string $paths */
44-
private function stageInArray(array|string $paths): void
70+
private function stageInTransactionStorage(array|string $paths): void
4571
{
4672
if (is_string($paths)) {
47-
$this->store[] = $paths;
73+
$this->transactionStorage[] = $paths;
4874

4975
return;
5076
}
@@ -54,28 +80,29 @@ private function stageInArray(array|string $paths): void
5480
->filter(fn (mixed $path) => is_string($path))
5581
->toArray();
5682

57-
$this->store = array_merge($this->store, $newPaths);
83+
$this->transactionStorage = array_merge($this->transactionStorage, $newPaths);
5884
}
5985

6086
/** @param string[]|string $paths */
6187
private function stageInDb(array|string $paths): void
6288
{
6389
$data = match (true) {
64-
is_string($paths) => $this->pathToRecord($paths),
90+
is_string($paths) => $this->pathToStagedRecord($paths),
6591
is_array($paths) => collect($paths)
6692
->filter(fn (mixed $path) => is_string($path))
67-
->map(fn (string $path) => $this->pathToRecord($path))
93+
->map(fn (string $path) => $this->pathToStagedRecord($path))
6894
->toArray(),
6995
};
7096

7197
RmqFile::insert($data);
98+
99+
$this->hasFilesInDb = true;
72100
}
73101

74102
public function delete(): void
75103
{
76-
$this->useArray ?
77-
$this->performDeleteUsingArray() :
78-
$this->performDeleteUsingDb(true);
104+
$this->performDeleteUsingDb(true);
105+
$this->performDeleteUsingArrayStorage();
79106
}
80107

81108
public function deleteAll(): void
@@ -86,17 +113,11 @@ public function deleteAll(): void
86113
throw new TypeError('rm-q.after must be an integer');
87114
}
88115

89-
$this->performDeleteUsingDb(false, $after);
90-
}
116+
if ($this->hasFilesInDb) {
117+
$this->performDeleteUsingDb(false, $after);
118+
}
91119

92-
/** @return array{path: string, instance: string} */
93-
private function pathToRecord(string $path, int $status = RmqFile::STAGED): array
94-
{
95-
return [
96-
'path' => $path,
97-
'instance' => $this->instance,
98-
'status' => $status,
99-
];
120+
$this->performDeleteUsingArrayStorage();
100121
}
101122

102123
private function performDeleteUsingDb(bool $filterInstance = false, int $beforeSeconds = 0): void
@@ -131,15 +152,17 @@ private function performDeleteUsingDb(bool $filterInstance = false, int $beforeS
131152
'processed_at' => $now,
132153
]);
133154
}
155+
156+
$this->hasFilesInDb = false;
134157
}
135158

136-
private function performDeleteUsingArray(): void
159+
private function performDeleteUsingArrayStorage(): void
137160
{
138161
$now = Date::now();
139162

140163
$data = [];
141164

142-
foreach ($this->store as $path) {
165+
foreach ($this->arrayStorage as $path) {
143166
if (@unlink($path)) {
144167
$data[] = [
145168
'path' => $path,
@@ -161,9 +184,33 @@ private function performDeleteUsingArray(): void
161184
RmqFile::insert($data);
162185
}
163186

187+
public function usingMiddleware(bool $flag = true): static
188+
{
189+
$this->isUsingMiddleware = $flag;
190+
191+
return $this;
192+
}
193+
194+
public function withinTransaction(bool $flag = true): static
195+
{
196+
$this->isWithinTransaction = $flag;
197+
198+
return $this;
199+
}
200+
201+
/** @return array{path: string} */
202+
private function pathToStagedRecord(string $path): array
203+
{
204+
return [
205+
'path' => $path,
206+
'instance' => $this->instance,
207+
'status' => RmqFile::STAGED,
208+
];
209+
}
210+
164211
/** @return string[] */
165-
public function getStore(): array
212+
public function getStorage(): array
166213
{
167-
return $this->store;
214+
return $this->arrayStorage;
168215
}
169216
}

0 commit comments

Comments
 (0)