Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 469b8eb

Browse files
committed
Implement url_stats and accept context options
1 parent 9725fd1 commit 469b8eb

File tree

4 files changed

+100
-34
lines changed

4 files changed

+100
-34
lines changed

‎src/GridFS/Bucket.php‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -597,14 +597,14 @@ public function openUploadStream(string $filename, array $options = [])
597597
*
598598
* @param non-empty-string string $alias The alias to use for the bucket
599599
*/
600-
public function registerGlobalAliasForResolutionInStandaloneStreamOpen(string $alias): void
600+
public function registerGlobalStreamWrapperAlias(string $alias): void
601601
{
602602
if ($alias === '' || str_contains($alias, '/')) {
603603
throw new InvalidArgumentException(sprintf('The bucket alias must be a non-empty string without any slash, "%s" given', $alias));
604604
}
605605

606606
// Use a closure to expose the private method into another class
607-
StreamWrapper::setContextResolver($alias, fn (string $path, string $mode) => $this->resolveStreamContext($path, $mode));
607+
StreamWrapper::setContextResolver($alias, fn (string $path, string $mode, array$context) => $this->resolveStreamContext($path, $mode, $context));
608608
}
609609

610610
/**
@@ -787,13 +787,13 @@ private function registerStreamWrapper(): void
787787
*
788788
* @return array{collectionWrapper: CollectionWrapper, file: object}|array{collectionWrapper: CollectionWrapper, filename: string, options: array}|null
789789
*/
790-
private function resolveStreamContext(string $path, string $mode): ?array
790+
private function resolveStreamContext(string $path, string $mode, array$context): ?array
791791
{
792792
$parts = explode('/', $path, 4);
793793
$filename = $parts[3] ?? '';
794794

795-
if (str_contains($mode, 'r')) {
796-
$file = $this->collectionWrapper->findFileByFilenameAndRevision($filename, -1);
795+
if ($mode === 'r' || $mode === 'rb') {
796+
$file = $this->collectionWrapper->findFileByFilenameAndRevision($filename, $context['revision'] ?? -1);
797797

798798
// File not found
799799
if ($file === null) {
@@ -806,11 +806,11 @@ private function resolveStreamContext(string $path, string $mode): ?array
806806
];
807807
}
808808

809-
if (str_contains($mode, 'w')) {
809+
if ($mode === 'w' || $mode === 'wb') {
810810
return [
811811
'collectionWrapper' => $this->collectionWrapper,
812812
'filename' => $filename,
813-
'options' => [
813+
'options' => $context + [
814814
'chunkSizeBytes' => $this->chunkSizeBytes,
815815
'disableMD5' => $this->disableMD5,
816816
],

‎src/GridFS/StreamWrapper.php‎

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public static function register(string $protocol = 'gridfs'): void
9999
/**
100100
* @see Bucket::resolveStreamContext()
101101
*
102-
* @param Closure(string, string):ContextOptions|null $resolver
102+
* @param Closure(string, string, array):ContextOptions|null $resolver
103103
*/
104104
public static function setContextResolver(string $name, ?Closure $resolver): void
105105
{
@@ -147,10 +147,13 @@ public function stream_open(string $path, string $mode, int $options, ?string &$
147147
{
148148
[$protocol] = explode('://', $path, 2);
149149

150-
assert(is_resource($this->context));
151-
$contextOptions = stream_context_get_options($this->context)[$protocol] ?? null;
150+
$context = [];
151+
if (is_resource($this->context)) {
152+
$context = stream_context_get_options($this->context)[$protocol] ?? [];
153+
}
152154

153-
if ($contextOptions === null) {
155+
// Opening stream from gridfs
156+
if (! isset($context['collectionWrapper'])) {
154157
$parts = explode('/', $path, 4);
155158

156159
if (count($parts) < 4) {
@@ -169,8 +172,8 @@ public function stream_open(string $path, string $mode, int $options, ?string &$
169172
return false;
170173
}
171174

172-
$contextOptions = self::$contextResolvers[$parts[2]]($path, $mode);
173-
if ($contextOptions === null) {
175+
$context = self::$contextResolvers[$parts[2]]($path, $mode, $context);
176+
if ($context === null) {
174177
if ($options & STREAM_REPORT_ERRORS) {
175178
trigger_error(sprintf('File not found "%s".', $path), E_USER_WARNING);
176179
}
@@ -179,20 +182,20 @@ public function stream_open(string $path, string $mode, int $options, ?string &$
179182
}
180183
}
181184

182-
assert(is_array($contextOptions));
183-
assert(isset($contextOptions['collectionWrapper']) && $contextOptions['collectionWrapper'] instanceof CollectionWrapper);
185+
assert(is_array($context));
186+
assert(isset($context['collectionWrapper']) && $context['collectionWrapper'] instanceof CollectionWrapper);
184187

185-
if (str_contains($mode, 'r')) {
186-
assert(isset($contextOptions['file']) && is_object($contextOptions['file']));
188+
if ($mode === 'r' || $mode === 'rb') {
189+
assert(isset($context['file']) && is_object($context['file']));
187190

188-
return $this->initReadableStream($contextOptions);
191+
return $this->initReadableStream($context);
189192
}
190193

191-
if (str_contains($mode, 'w')) {
192-
assert(isset($contextOptions['filename']) && is_string($contextOptions['filename']));
193-
assert(isset($contextOptions['options']) && is_array($contextOptions['options']));
194+
if ($mode === 'w' || $mode === 'wb') {
195+
assert(isset($context['filename']) && is_string($context['filename']));
196+
assert(isset($context['options']) && is_array($context['options']));
194197

195-
return $this->initWritableStream($contextOptions);
198+
return $this->initWritableStream($context);
196199
}
197200

198201
return false;
@@ -312,6 +315,17 @@ public function stream_write(string $data): int
312315
return $this->stream->writeBytes($data);
313316
}
314317

318+
public function url_stat(string $path, int $flags)
319+
{
320+
$success = $this->stream_open($path, 'r', 0, $openedPath);
321+
322+
if (! $success) {
323+
return false;
324+
}
325+
326+
return $this->stream_stat();
327+
}
328+
315329
/**
316330
* Returns a stat template with default values.
317331
*/

‎tests/GridFS/BucketFunctionalTest.php‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -902,9 +902,8 @@ public function testResolveStreamContextForRead(): void
902902

903903
$method = new ReflectionMethod($this->bucket, 'resolveStreamContext');
904904
$method->setAccessible(true);
905-
$method->setAccessible(true);
906905

907-
$context = $method->invokeArgs($this->bucket, ['gridfs://bucket/filename', 'rb']);
906+
$context = $method->invokeArgs($this->bucket, ['gridfs://bucket/filename', 'rb', []]);
908907

909908
$this->assertIsArray($context);
910909
$this->assertArrayHasKey('collectionWrapper', $context);
@@ -919,9 +918,8 @@ public function testResolveStreamContextForWrite(): void
919918
{
920919
$method = new ReflectionMethod($this->bucket, 'resolveStreamContext');
921920
$method->setAccessible(true);
922-
$method->setAccessible(true);
923921

924-
$context = $method->invokeArgs($this->bucket, ['gridfs://bucket/filename', 'wb']);
922+
$context = $method->invokeArgs($this->bucket, ['gridfs://bucket/filename', 'wb', []]);
925923

926924
$this->assertIsArray($context);
927925
$this->assertArrayHasKey('collectionWrapper', $context);

‎tests/GridFS/StreamWrapperFunctionalTest.php‎

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,21 @@
77

88
use function fclose;
99
use function feof;
10+
use function file_exists;
11+
use function file_get_contents;
12+
use function file_put_contents;
13+
use function filemtime;
14+
use function filesize;
15+
use function filetype;
1016
use function fopen;
1117
use function fread;
1218
use function fseek;
1319
use function fstat;
1420
use function fwrite;
21+
use function is_dir;
22+
use function is_file;
23+
use function is_link;
24+
use function time;
1525

1626
use const SEEK_CUR;
1727
use const SEEK_END;
@@ -206,37 +216,81 @@ public function testWritableStreamWrite(): void
206216
$this->assertSame(6, fwrite($stream, 'foobar'));
207217
}
208218

209-
public function testStreamWithContextResolver(): void
219+
/** @dataProvider provideUrl */
220+
public function testStreamWithContextResolver(string $url, string $expectedFilename): void
210221
{
211-
$filename = 'gridfs://bucket/path/to/filename';
212-
$this->bucket->registerGlobalAliasForResolutionInStandaloneStreamOpen('bucket');
222+
$this->bucket->registerGlobalStreamWrapperAlias('bucket');
213223

214-
$stream = fopen($filename, 'wb');
224+
$stream = fopen($url, 'wb');
215225

216226
$this->assertSame(6, fwrite($stream, 'foobar'));
217227
$this->assertTrue(fclose($stream));
218228

219-
$stream = fopen($filename, 'rb');
229+
$file = $this->filesCollection->findOne(['filename' => $expectedFilename]);
230+
$this->assertNotNull($file);
231+
232+
$stream = fopen($url, 'rb');
220233

221234
$this->assertSame('foobar', fread($stream, 10));
222235
$this->assertTrue(fclose($stream));
223236
}
224237

238+
public static function provideUrl()
239+
{
240+
yield 'simple file' => ['gridfs://bucket/filename', 'filename'];
241+
yield 'subdirectory file' => ['gridfs://bucket/path/to/filename.txt', 'path/to/filename.txt'];
242+
yield 'question mark can be used in file name' => ['gridfs://bucket/file%20name?foo=bar', 'file%20name?foo=bar'];
243+
}
244+
245+
public function testFilePutAndGetContents(): void
246+
{
247+
$this->bucket->registerGlobalStreamWrapperAlias('bucket');
248+
249+
$filename = 'gridfs://bucket/path/to/filename';
250+
251+
$this->assertSame(6, file_put_contents($filename, 'foobar'));
252+
253+
$file = $this->filesCollection->findOne(['filename' => 'path/to/filename']);
254+
$this->assertNotNull($file);
255+
256+
$this->assertSame('foobar', file_get_contents($filename));
257+
}
258+
225259
public function testFileNoFoundWithContextResolver(): void
226260
{
227-
$this->bucket->registerGlobalAliasForResolutionInStandaloneStreamOpen('default');
261+
$this->bucket->registerGlobalStreamWrapperAlias('bucket');
228262

229263
$this->expectWarning();
230-
$stream = fopen('gridfs://bucket/path/to/filename', 'r');
264+
$stream = fopen('gridfs://bucket/filename', 'r');
231265

232266
$this->assertFalse($stream);
233267
}
234268

235269
public function testFileNoFoundWithoutDefaultResolver(): void
236270
{
237271
$this->expectWarning();
238-
$stream = fopen('gridfs://bucket/path/to/filename', 'r');
272+
$stream = fopen('gridfs://bucket/filename', 'r');
239273

240274
$this->assertFalse($stream);
241275
}
276+
277+
public function testFileStats(): void
278+
{
279+
$this->bucket->registerGlobalStreamWrapperAlias('bucket');
280+
$path = 'gridfs://bucket/filename';
281+
282+
$this->assertFalse(file_exists($path));
283+
284+
$time = time();
285+
$this->assertSame(6, file_put_contents($path, 'foobar'));
286+
287+
$this->assertTrue(file_exists($path));
288+
$this->assertSame('file', filetype($path));
289+
$this->assertTrue(is_file($path));
290+
$this->assertFalse(is_dir($path));
291+
$this->assertFalse(is_link($path));
292+
$this->assertSame(6, filesize($path));
293+
$this->assertGreaterThanOrEqual($time, filemtime($path));
294+
$this->assertLessThanOrEqual(time(), filemtime($path));
295+
}
242296
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /