19
19
20
20
use Closure ;
21
21
use MongoDB \BSON \UTCDateTime ;
22
+ use MongoDB \GridFS \Exception \FileNotFoundException ;
23
+ use MongoDB \GridFS \Exception \LogicException ;
22
24
23
25
use function assert ;
24
- use function count ;
25
26
use function explode ;
26
27
use function in_array ;
27
28
use function is_array ;
28
29
use function is_integer ;
29
- use function is_object ;
30
30
use function is_resource ;
31
- use function is_string ;
32
- use function sprintf ;
33
31
use function stream_context_get_options ;
34
32
use function stream_get_wrappers ;
35
33
use function stream_wrapper_register ;
36
34
use function stream_wrapper_unregister ;
37
- use function trigger_error ;
38
35
39
- use const E_USER_ERROR ;
40
36
use const SEEK_CUR ;
41
37
use const SEEK_END ;
42
38
use const SEEK_SET ;
43
39
use const STREAM_IS_URL ;
44
- use const STREAM_REPORT_ERRORS ;
45
40
46
41
/**
47
42
* Stream wrapper for reading and writing a GridFS file.
48
43
*
49
44
* @internal
50
45
* @see Bucket::openUploadStream()
51
46
* @see Bucket::openDownloadStream()
52
- * @psalm-type ContextOptions = array{collectionWrapper: CollectionWrapper, file: object}|array{collectionWrapper: CollectionWrapper, filename: string, options: array}|null
47
+ * @psalm-type ContextOptions = array{collectionWrapper: CollectionWrapper, file: object}|array{collectionWrapper: CollectionWrapper, filename: string, options: array}
53
48
*/
54
49
class StreamWrapper
55
50
{
@@ -81,6 +76,18 @@ public function getFile(): object
81
76
return $ this ->stream ->getFile ();
82
77
}
83
78
79
+ /** @return false|array */
80
+ public function url_stat (string $ path , int $ flags )
81
+ {
82
+ try {
83
+ $ this ->stream_open ($ path , 'r ' , 0 , $ openedPath );
84
+ } catch (FileNotFoundException $ e ) {
85
+ return false ;
86
+ }
87
+
88
+ return $ this ->stream_stat ();
89
+ }
90
+
84
91
/**
85
92
* Register the GridFS stream wrapper.
86
93
*
@@ -148,74 +155,44 @@ public function stream_eof(): bool
148
155
*/
149
156
public function stream_open (string $ path , string $ mode , int $ options , ?string &$ openedPath ): bool
150
157
{
151
- [$ protocol ] = explode (':// ' , $ path , 2 );
152
-
153
158
$ context = [];
159
+
160
+ /**
161
+ * The Bucket methods { @see Bucket::openUploadStream() } and { @see Bucket::openDownloadStreamByFile() }
162
+ * always set an internal context. But the context can also be set by the user.
163
+ */
154
164
if (is_resource ($ this ->context )) {
155
- $ context = stream_context_get_options ($ this ->context )[$ protocol ] ?? [];
165
+ $ context = stream_context_get_options ($ this ->context )[' gridfs ' ] ?? [];
156
166
157
167
if (! is_array ($ context )) {
158
- if ($ options & STREAM_REPORT_ERRORS ) {
159
- trigger_error (sprintf ('Invalid context for "%s" protocol. ' , $ protocol ), E_USER_ERROR );
160
- }
161
-
162
- return false ;
168
+ throw LogicException::invalidContext ($ context );
163
169
}
164
170
}
165
171
166
- // Opening stream from gridfs
172
+ // When the stream is opened using fopen(), the context is not required, it can contain only options.
167
173
if (! isset ($ context ['collectionWrapper ' ])) {
168
- $ parts = explode ('/ ' , $ path , 4 );
169
-
170
- if (count ($ parts ) < 4 ) {
171
- if ($ options & STREAM_REPORT_ERRORS ) {
172
- trigger_error (sprintf ('Invalid GridFS file name: "%s" ' , $ path ), E_USER_ERROR );
173
- }
174
+ $ bucketAlias = explode ('/ ' , $ path , 4 )[2 ] ?? '' ;
174
175
175
- return false ;
176
+ if (! isset (self ::$ contextResolvers [$ bucketAlias ])) {
177
+ throw LogicException::bucketAliasNotRegistered ($ bucketAlias );
176
178
}
177
179
178
- $ resolver = self ::$ contextResolvers [$ parts [2 ]] ?? null ;
179
- if (null === $ resolver ) {
180
- if ($ options & STREAM_REPORT_ERRORS ) {
181
- trigger_error (sprintf ('Unknown GridFS Bucket "%1$s". Call $bucket->asStreamWrap( \'%1$s \') on the Bucket you want to access. ' , $ parts [2 ]), E_USER_ERROR );
182
- }
183
-
184
- return false ;
185
- }
186
-
187
- $ context = $ resolver ($ path , $ mode , $ context );
188
- if ($ context === null ) {
189
- if ($ options & STREAM_REPORT_ERRORS ) {
190
- trigger_error (sprintf ('File not found "%s". ' , $ path ), E_USER_ERROR );
191
- }
192
-
193
- return false ;
194
- }
180
+ $ context = self ::$ contextResolvers [$ bucketAlias ]($ path , $ mode , $ context );
195
181
}
196
182
197
183
if (! $ context ['collectionWrapper ' ] instanceof CollectionWrapper) {
198
- if ($ options & STREAM_REPORT_ERRORS ) {
199
- trigger_error ('Invalid context: "gridfs[collectionWrapper]" must be a CollectionWrapper. ' , E_USER_ERROR );
200
- }
201
-
202
- return false ;
184
+ throw LogicException::invalidContextCollectionWrapper ($ context ['collectionWrapper ' ]);
203
185
}
204
186
205
187
if ($ mode === 'r ' || $ mode === 'rb ' ) {
206
- assert (isset ($ context ['file ' ]) && is_object ($ context ['file ' ]));
207
-
208
188
return $ this ->initReadableStream ($ context );
209
189
}
210
190
211
191
if ($ mode === 'w ' || $ mode === 'wb ' ) {
212
- assert (isset ($ context ['filename ' ]) && is_string ($ context ['filename ' ]));
213
- assert (isset ($ context ['options ' ]) && is_array ($ context ['options ' ]));
214
-
215
192
return $ this ->initWritableStream ($ context );
216
193
}
217
194
218
- return false ;
195
+ throw LogicException:: openModeNotSupported ( $ mode ) ;
219
196
}
220
197
221
198
/**
@@ -332,18 +309,6 @@ public function stream_write(string $data): int
332
309
return $ this ->stream ->writeBytes ($ data );
333
310
}
334
311
335
- /** @return false|array */
336
- public function url_stat (string $ path , int $ flags )
337
- {
338
- $ success = $ this ->stream_open ($ path , 'r ' , 0 , $ openedPath );
339
-
340
- if (! $ success ) {
341
- return false ;
342
- }
343
-
344
- return $ this ->stream_stat ();
345
- }
346
-
347
312
/**
348
313
* Returns a stat template with default values.
349
314
*/
@@ -371,8 +336,7 @@ private function getStatTemplate(): array
371
336
/**
372
337
* Initialize the internal stream for reading.
373
338
*
374
- * @psalm-param array{collectionWrapper: CollectionWrapper, file: object, ...} $contextOptions
375
- * @see StreamWrapper::stream_open()
339
+ * @param array{collectionWrapper: CollectionWrapper, file: object} $contextOptions
376
340
*/
377
341
private function initReadableStream (array $ contextOptions ): bool
378
342
{
@@ -387,8 +351,7 @@ private function initReadableStream(array $contextOptions): bool
387
351
/**
388
352
* Initialize the internal stream for writing.
389
353
*
390
- * @psalm-param array{collectionWrapper: CollectionWrapper, filename: string, options: array, ...} $contextOptions
391
- * @see StreamWrapper::stream_open()
354
+ * @param array{collectionWrapper: CollectionWrapper, filename: string, options: array} $contextOptions
392
355
*/
393
356
private function initWritableStream (array $ contextOptions ): bool
394
357
{
0 commit comments