1 | <?php declare(strict_types=1); |
||||
2 | |||||
3 | namespace Initx\Querabilis\Driver; |
||||
4 | |||||
5 | use Initx\Querabilis\Envelope; |
||||
6 | use Initx\Querabilis\Exception\IllegalStateException; |
||||
7 | use Initx\Querabilis\Queue; |
||||
8 | use JMS\Serializer\SerializerInterface; |
||||
9 | |||||
10 | final class FilesystemQueue implements Queue |
||||
11 | { |
||||
12 | use HasFallbackSerializer; |
||||
13 | use HasDefaultRemoveAndElement; |
||||
14 | |||||
15 | /** |
||||
16 | * @var string |
||||
17 | */ |
||||
18 | private $path; |
||||
19 | |||||
20 | /** |
||||
21 | * @var SerializerInterface |
||||
22 | */ |
||||
23 | private $serializer; |
||||
24 | |||||
25 | 11 | public function __construct(string $path, ?SerializerInterface $serializer = null) |
|||
26 | { |
||||
27 | 11 | $this->serializer = $this->fallbackSerializer($serializer); |
|||
28 | 11 | $this->path = $path; |
|||
29 | 11 | } |
|||
30 | |||||
31 | 5 | public function add(Envelope $envelope): bool |
|||
32 | { |
||||
33 | 5 | if (!$this->offer($envelope)) { |
|||
34 | $this->throwItIsNotWriteable(); |
||||
35 | } |
||||
36 | |||||
37 | 4 | return true; |
|||
38 | } |
||||
39 | |||||
40 | 7 | public function offer(Envelope $envelope): bool |
|||
41 | { |
||||
42 | 7 | $content = $this->serializer->serialize($envelope, 'json').PHP_EOL; |
|||
43 | |||||
44 | 7 | $result = (bool)@file_put_contents( |
|||
45 | 7 | $this->path, |
|||
46 | 7 | $content, |
|||
47 | 7 | FILE_APPEND |
|||
48 | ); |
||||
49 | |||||
50 | 7 | if (!$result) { |
|||
51 | 2 | $this->throwItIsNotWriteable(); |
|||
52 | } |
||||
53 | |||||
54 | 5 | return true; |
|||
55 | } |
||||
56 | |||||
57 | 3 | public function poll(): ?Envelope |
|||
58 | { |
||||
59 | 3 | $firstLine = $this->removeFirstLine(); |
|||
0 ignored issues
–
show
|
|||||
60 | |||||
61 | 2 | if (!$firstLine) { |
|||
0 ignored issues
–
show
|
|||||
62 | 1 | return null; |
|||
63 | } |
||||
64 | |||||
65 | 1 | return $this->serializer->deserialize($firstLine, Envelope::class, 'json'); |
|||
66 | } |
||||
67 | |||||
68 | 4 | public function peek(): ?Envelope |
|||
69 | { |
||||
70 | 4 | $firstLine = $this->readFirstLine(); |
|||
71 | |||||
72 | 4 | if (!$firstLine) { |
|||
73 | 2 | return null; |
|||
74 | } |
||||
75 | |||||
76 | 2 | return $this->serializer->deserialize($firstLine, Envelope::class, 'json'); |
|||
77 | } |
||||
78 | |||||
79 | 3 | private function removeFirstLine(): ?string |
|||
80 | { |
||||
81 | 3 | if (!file_exists($this->path)) { |
|||
82 | 1 | $this->throwItNotExists(); |
|||
83 | } |
||||
84 | |||||
85 | 2 | $firstLine = null; |
|||
86 | |||||
87 | 2 | $handle = fopen($this->path, 'cb+'); |
|||
88 | |||||
89 | 2 | if ($handle) { |
|||
0 ignored issues
–
show
|
|||||
90 | 2 | if (!flock($handle, LOCK_EX)) { |
|||
91 | fclose($handle); |
||||
92 | } |
||||
93 | |||||
94 | 2 | $offset = 0; |
|||
95 | 2 | $len = filesize($this->path); |
|||
96 | |||||
97 | 2 | while (($line = fgets($handle, 4096)) !== false) { |
|||
98 | 1 | if (!$firstLine) { |
|||
99 | 1 | $firstLine = $line; |
|||
100 | 1 | $offset = strlen($firstLine); |
|||
101 | |||||
102 | 1 | continue; |
|||
103 | } |
||||
104 | |||||
105 | 1 | $pos = ftell($handle); |
|||
106 | 1 | fseek($handle, $pos - strlen($line) - $offset); |
|||
107 | 1 | fwrite($handle, $line); |
|||
108 | 1 | fseek($handle, $pos); |
|||
109 | } |
||||
110 | |||||
111 | 2 | fflush($handle); |
|||
112 | 2 | ftruncate($handle, $len - $offset); |
|||
113 | 2 | flock($handle, LOCK_UN); |
|||
114 | 2 | fclose($handle); |
|||
115 | } |
||||
116 | |||||
117 | 2 | return $firstLine; |
|||
118 | } |
||||
119 | |||||
120 | 4 | private function readFirstLine(): ?string |
|||
121 | { |
||||
122 | 4 | if (!file_exists($this->path)) { |
|||
123 | $this->throwItNotExists(); |
||||
124 | } |
||||
125 | |||||
126 | 4 | $firstLine = fgets(fopen($this->path, 'rb')); |
|||
0 ignored issues
–
show
It seems like
fopen($this->path, 'rb') can also be of type false ; however, parameter $handle of fgets() does only seem to accept resource , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
127 | |||||
128 | 4 | return $firstLine ?: null; |
|||
129 | } |
||||
130 | |||||
131 | 2 | private function throwItIsNotWriteable(): void |
|||
132 | { |
||||
133 | 2 | throw new IllegalStateException("Could not write to file: {$this->path}"); |
|||
134 | } |
||||
135 | |||||
136 | 1 | private function throwItNotExists(): void |
|||
137 | { |
||||
138 | 1 | throw new IllegalStateException("File $this->path not exists"); |
|||
139 | } |
||||
140 | } |
||||
141 |
This check looks for function or method calls that always return null and whose return value is assigned to a variable.
The method
getObject()
can return nothing but null, so it makes no sense to assign that value to a variable.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.