4
4
5
5
use Carbon \Carbon ;
6
6
use Illuminate \Contracts \Filesystem \Factory ;
7
- use Illuminate \Filesystem \FilesystemAdapter as Disk ;
7
+ use Illuminate \Filesystem \FilesystemAdapter ;
8
8
use Illuminate \Support \Facades \DB ;
9
- use Illuminate \Support \LazyCollection ;
10
9
use Spatie \DbSnapshots \Events \DeletedSnapshot ;
11
10
use Spatie \DbSnapshots \Events \DeletingSnapshot ;
12
11
use Spatie \DbSnapshots \Events \LoadedSnapshot ;
15
14
16
15
class Snapshot
17
16
{
18
- public Disk $ disk ;
17
+ public FilesystemAdapter $ disk ;
19
18
20
19
public string $ fileName ;
21
20
@@ -29,10 +28,9 @@ class Snapshot
29
28
30
29
protected Factory $ filesystemFactory ;
31
30
32
- public function __construct (Disk $ disk , string $ fileName )
31
+ public function __construct (FilesystemAdapter $ disk , string $ fileName )
33
32
{
34
33
$ this ->disk = $ disk ;
35
-
36
34
$ this ->fileName = $ fileName ;
37
35
38
36
$ pathinfo = pathinfo ($ fileName );
@@ -43,14 +41,12 @@ public function __construct(Disk $disk, string $fileName)
43
41
}
44
42
45
43
$ this ->name = pathinfo ($ fileName , PATHINFO_FILENAME );
46
-
47
44
$ this ->filesystemFactory = app (Factory::class);
48
45
}
49
46
50
47
public function useStream (): self
51
48
{
52
49
$ this ->useStream = true ;
53
-
54
50
return $ this ;
55
51
}
56
52
@@ -79,6 +75,10 @@ protected function loadAsync(?string $connectionName = null): void
79
75
$ dbDumpContents = gzdecode ($ dbDumpContents );
80
76
}
81
77
78
+ if (empty (trim ($ dbDumpContents ))) {
79
+ return ;
80
+ }
81
+
82
82
DB ::connection ($ connectionName )->unprepared ($ dbDumpContents );
83
83
}
84
84
@@ -90,83 +90,116 @@ protected function isASqlComment(string $line): bool
90
90
protected function shouldIgnoreLine (string $ line ): bool
91
91
{
92
92
$ line = trim ($ line );
93
-
94
93
return empty ($ line ) || $ this ->isASqlComment ($ line );
95
94
}
96
95
97
96
protected function loadStream (?string $ connectionName = null ): void
98
97
{
99
- $ directory = (new TemporaryDirectory (config ('db-snapshots.temporary_directory_path ' )))->create ();
98
+ $ temporaryDirectory = (new TemporaryDirectory (config ('db-snapshots.temporary_directory_path ' )))->create ();
99
+
100
+ $ this ->configureFilesystemDisk ($ temporaryDirectory ->path ());
101
+
102
+ $ localDisk = $ this ->filesystemFactory ->disk (self ::class);
103
+
104
+ try {
105
+ $ this ->processStream ($ localDisk , $ connectionName );
106
+ } finally {
107
+ $ temporaryDirectory ->delete ();
108
+ }
109
+ }
100
110
111
+ private function configureFilesystemDisk (string $ path ): void
112
+ {
101
113
config ([
102
114
'filesystems.disks. ' . self ::class => [
103
115
'driver ' => 'local ' ,
104
- 'root ' => $ directory -> path () ,
116
+ 'root ' => $ path ,
105
117
'throw ' => false ,
106
- ]
118
+ ],
107
119
]);
120
+ }
108
121
109
- $ localDisk = $ this ->filesystemFactory ->disk (self ::class);
122
+ private function processStream (FilesystemAdapter $ localDisk , ?string $ connectionName ): void
123
+ {
124
+ $ this ->copyStreamToLocalDisk ($ localDisk );
125
+
126
+ $ stream = $ this ->openStream ($ localDisk );
110
127
111
128
try {
112
- LazyCollection:: make ( function () use ( $ localDisk ) {
113
- $ localDisk -> writeStream ( $ this -> fileName , $ this -> disk -> readStream ( $ this -> fileName ));
114
-
115
- $ stream = $ this -> compressionExtension === ' gz '
116
- ? gzopen ( $ localDisk -> path ( $ this -> fileName ), ' r ' )
117
- : $ localDisk -> readStream ( $ this -> fileName );
118
-
119
- $ statement = '' ;
120
- while (! feof ( $ stream )) {
121
- $ chunk = $ this -> compressionExtension === ' gz '
122
- ? gzread ( $ stream , self :: STREAM_BUFFER_SIZE )
123
- : fread ( $ stream , self :: STREAM_BUFFER_SIZE );
124
-
125
- $ lines = explode ( "\n" , $ chunk );
126
- foreach ( $ lines as $ idx => $ line ) {
127
- if ( $ this -> shouldIgnoreLine ( $ line )) {
128
- continue ;
129
- }
130
-
131
- $ statement .= $ line ;
132
-
133
- // Carry-over the last line to the next chunk since it
134
- // is possible that this chunk finished mid-line right on
135
- // a semi-colon.
136
- if ( count ( $ lines ) == $ idx + 1 ) {
137
- break ;
138
- }
139
-
140
- if ( str_ends_with ( trim ( $ statement ), ' ; ' )) {
141
- yield $ statement ;
142
- $ statement = '' ;
143
- }
144
- }
129
+ $ this -> processStatements ( $ stream , $ connectionName );
130
+ } finally {
131
+ $ this -> closeStream ( $ stream );
132
+ }
133
+ }
134
+
135
+ private function copyStreamToLocalDisk ( FilesystemAdapter $ localDisk ): void
136
+ {
137
+ $ localDisk -> writeStream ( $ this -> fileName , $ this -> disk -> readStream ( $ this -> fileName ));
138
+ }
139
+
140
+ private function openStream ( FilesystemAdapter $ localDisk ): mixed
141
+ {
142
+ return $ this -> compressionExtension === ' gz '
143
+ ? gzopen ( $ localDisk -> path ( $ this -> fileName ), ' r ' )
144
+ : $ localDisk -> readStream ( $ this -> fileName );
145
+ }
146
+
147
+ private function closeStream ( mixed $ stream ): void
148
+ {
149
+ $ this -> compressionExtension === ' gz ' ? gzclose ( $ stream ) : fclose ( $ stream );
150
+ }
151
+
152
+ private function processStatements ( mixed $ stream , ? string $ connectionName ): void
153
+ {
154
+ $ statement = '' ;
155
+ while (! feof ( $ stream )) {
156
+ $ chunk = $ this -> readChunk ( $ stream );
157
+ $ lines = explode ( "\n" , $ chunk );
158
+
159
+ foreach ( $ lines as $ idx => $ line ) {
160
+ if ( $ this -> shouldIgnoreLine ( $ line )) {
161
+ continue ;
145
162
}
146
163
147
- if (str_ends_with (trim ($ statement ), '; ' )) {
148
- yield $ statement ;
164
+ $ statement .= $ line ;
165
+
166
+ if ($ this ->isLastLineOfChunk ($ lines , $ idx )) {
167
+ break ;
149
168
}
150
169
151
- if ($ this ->compressionExtension === 'gz ' ) {
152
- gzclose ($ stream );
153
- } else {
154
- fclose ($ stream );
170
+ if ($ this ->isCompleteStatement ($ statement )) {
171
+ DB ::connection ($ connectionName )->unprepared ($ statement );
172
+ $ statement = '' ;
155
173
}
156
- })-> each ( function ( string $ statement ) use ( $ connectionName ) {
157
- DB :: connection ( $ connectionName )-> unprepared ( $ statement );
158
- });
159
- } finally {
160
- $ directory -> delete ( );
174
+ }
175
+ }
176
+
177
+ if ( $ this -> isCompleteStatement ( $ statement )) {
178
+ DB :: connection ( $ connectionName )-> unprepared ( $ statement );
161
179
}
162
180
}
163
181
182
+ private function readChunk (mixed $ stream ): string
183
+ {
184
+ return $ this ->compressionExtension === 'gz '
185
+ ? gzread ($ stream , self ::STREAM_BUFFER_SIZE )
186
+ : fread ($ stream , self ::STREAM_BUFFER_SIZE );
187
+ }
188
+
189
+ private function isLastLineOfChunk (array $ lines , int $ idx ): bool
190
+ {
191
+ return count ($ lines ) === $ idx + 1 ;
192
+ }
193
+
194
+ private function isCompleteStatement (string $ statement ): bool
195
+ {
196
+ return str_ends_with (trim ($ statement ), '; ' );
197
+ }
198
+
164
199
public function delete (): void
165
200
{
166
201
event (new DeletingSnapshot ($ this ));
167
-
168
202
$ this ->disk ->delete ($ this ->fileName );
169
-
170
203
event (new DeletedSnapshot ($ this ->fileName , $ this ->disk ));
171
204
}
172
205
0 commit comments