Skip to content

Commit 16f9cc2

Browse files
committed
PHPLIB-1206 Add default bucket for GridFS StreamWrapper
1 parent 9e1971c commit 16f9cc2

File tree

4 files changed

+69
-7
lines changed

4 files changed

+69
-7
lines changed

src/GridFS/Bucket.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,12 @@ public function uploadFromStream(string $filename, $source, array $options = [])
631631
return $this->getFileIdForStream($destination);
632632
}
633633

634+
/** @internal */
635+
public function getCollectionWrapper(): CollectionWrapper
636+
{
637+
return $this->collectionWrapper;
638+
}
639+
634640
/**
635641
* Creates a path for an existing GridFS file.
636642
*

src/GridFS/StreamWrapper.php

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
namespace MongoDB\GridFS;
1919

2020
use MongoDB\BSON\UTCDateTime;
21+
use RuntimeException;
2122

2223
use function assert;
2324
use function explode;
2425
use function in_array;
2526
use function is_integer;
2627
use function is_resource;
28+
use function parse_url;
2729
use function stream_context_get_options;
2830
use function stream_get_wrappers;
2931
use function stream_wrapper_register;
@@ -43,14 +45,24 @@
4345
*/
4446
class StreamWrapper
4547
{
48+
private static ?Bucket $defaultBucket = null;
49+
4650
/** @var resource|null Stream context (set by PHP) */
4751
public $context;
4852

4953
private ?string $protocol = null;
5054

55+
/** @var array{collectionWrapper: CollectionWrapper, file: ?object, filename: string, options: array} */
56+
private array $contextOptions;
57+
5158
/** @var ReadableStream|WritableStream|null */
5259
private $stream;
5360

61+
public static function setDefaultBucket(?Bucket $defaultBucket = null): void
62+
{
63+
self::$defaultBucket = $defaultBucket;
64+
}
65+
5466
public function __destruct()
5567
{
5668
/* This destructor is a workaround for PHP trying to use the stream well
@@ -280,8 +292,24 @@ private function getStatTemplate(): array
280292
*/
281293
private function initProtocol(string $path): void
282294
{
283-
$parts = explode('://', $path, 2);
284-
$this->protocol = $parts[0] ?: 'gridfs';
295+
$parts = parse_url($path);
296+
$this->protocol = $parts['scheme'] ?: 'gridfs';
297+
298+
$context = stream_context_get_options($this->context);
299+
300+
if (isset($context[$this->protocol]['collectionWrapper'])) {
301+
$this->contextOptions = $context[$this->protocol];
302+
} elseif (! isset(self::$defaultBucket)) {
303+
throw new RuntimeException('No default GridFS bucket available for stream wrapper.');
304+
} else {
305+
$file = explode('/', $parts['path'], 3)[2] ?? '';
306+
$this->contextOptions = [
307+
'collectionWrapper' => self::$defaultBucket->getCollectionWrapper(),
308+
'file' => self::$defaultBucket->findOne(['_id' => $file]),
309+
'filename' => $file,
310+
'options' => [],
311+
];
312+
}
285313
}
286314

287315
/**
@@ -296,8 +324,8 @@ private function initReadableStream(): bool
296324

297325
assert($this->protocol !== null);
298326
$this->stream = new ReadableStream(
299-
$context[$this->protocol]['collectionWrapper'],
300-
$context[$this->protocol]['file'],
327+
$this->contextOptions['collectionWrapper'],
328+
$this->contextOptions['file'],
301329
);
302330

303331
return true;
@@ -315,9 +343,9 @@ private function initWritableStream(): bool
315343

316344
assert($this->protocol !== null);
317345
$this->stream = new WritableStream(
318-
$context[$this->protocol]['collectionWrapper'],
319-
$context[$this->protocol]['filename'],
320-
$context[$this->protocol]['options'],
346+
$this->contextOptions['collectionWrapper'],
347+
$this->contextOptions['filename'],
348+
$this->contextOptions['options'],
321349
);
322350

323351
return true;

tests/GridFS/FunctionalTestCase.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use MongoDB\Collection;
66
use MongoDB\GridFS\Bucket;
7+
use MongoDB\GridFS\StreamWrapper;
78
use MongoDB\Tests\FunctionalTestCase as BaseFunctionalTestCase;
89

910
use function fopen;
@@ -34,6 +35,13 @@ public function setUp(): void
3435
$this->filesCollection = $this->createCollection($this->getDatabaseName(), 'fs.files');
3536
}
3637

38+
public function tearDown(): void
39+
{
40+
StreamWrapper::setDefaultBucket(null);
41+
42+
parent::tearDown();
43+
}
44+
3745
/**
3846
* Asserts that a variable is a stream containing the expected data.
3947
*

tests/GridFS/StreamWrapperFunctionalTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44

55
use MongoDB\BSON\Binary;
66
use MongoDB\BSON\UTCDateTime;
7+
use MongoDB\GridFS\StreamWrapper;
78

89
use function fclose;
910
use function feof;
11+
use function fopen;
1012
use function fread;
1113
use function fseek;
1214
use function fstat;
@@ -36,6 +38,15 @@ public function setUp(): void
3638
]);
3739
}
3840

41+
public function testReadableStreamCloseWithDefaultBucket(): void
42+
{
43+
StreamWrapper::setDefaultBucket($this->bucket);
44+
45+
$stream = fopen('gridfs://default/default/length-10', 'r');
46+
47+
$this->assertTrue(fclose($stream));
48+
}
49+
3950
public function testReadableStreamClose(): void
4051
{
4152
$stream = $this->bucket->openDownloadStream('length-10');
@@ -104,6 +115,15 @@ public function testReadableStreamStat(): void
104115
$this->assertSame(4, $stat['blksize']);
105116
}
106117

118+
public function testReadableStreamWriteWithDefaultBucket(): void
119+
{
120+
StreamWrapper::setDefaultBucket($this->bucket);
121+
122+
$stream = fopen('gridfs://default/default/length-10', 'w');
123+
124+
$this->assertSame(0, fwrite($stream, 'foobar'));
125+
}
126+
107127
public function testReadableStreamWrite(): void
108128
{
109129
$stream = $this->bucket->openDownloadStream('length-10');

0 commit comments

Comments
 (0)