Skip to content

Commit 5f79bc4

Browse files
committed
PHPLIB-202: Use stream_copy_to_stream() in Bucket upload/download methods
This also improves test coverage for downloadToStreamByName().
1 parent cd9394c commit 5f79bc4

File tree

5 files changed

+105
-83
lines changed

5 files changed

+105
-83
lines changed

src/GridFS/Bucket.php

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -104,17 +104,15 @@ public function delete($id)
104104
* @param mixed $id File ID
105105
* @param resource $destination Writable Stream
106106
* @throws FileNotFoundException
107+
* @throws InvalidArgumentException if $destination is not a stream
107108
*/
108109
public function downloadToStream($id, $destination)
109110
{
110-
$file = $this->collectionWrapper->findFileById($id);
111-
112-
if ($file === null) {
113-
throw FileNotFoundException::byId($id, $this->getFilesNamespace());
111+
if ( ! is_resource($destination) || get_resource_type($destination) != "stream") {
112+
throw InvalidArgumentException::invalidType('$destination', $destination, 'resource');
114113
}
115114

116-
$stream = new ReadableStream($this->collectionWrapper, $file);
117-
$stream ->downloadToStream($destination);
115+
stream_copy_to_stream($this->openDownloadStream($id), $destination);
118116
}
119117

120118
/**
@@ -140,19 +138,15 @@ public function downloadToStream($id, $destination)
140138
* @param resource $destination Writable Stream
141139
* @param array $options Download options
142140
* @throws FileNotFoundException
141+
* @throws InvalidArgumentException if $destination is not a stream
143142
*/
144143
public function downloadToStreamByName($filename, $destination, array $options = [])
145144
{
146-
$options += ['revision' => -1];
147-
148-
$file = $this->collectionWrapper->findFileByFilenameAndRevision($filename, $options['revision']);
149-
150-
if ($file === null) {
151-
throw FileNotFoundException::byFilenameAndRevision($filename, $options['revision'], $this->getFilesNamespace());
145+
if ( ! is_resource($destination) || get_resource_type($destination) != "stream") {
146+
throw InvalidArgumentException::invalidType('$destination', $destination, 'resource');
152147
}
153148

154-
$stream = new ReadableStream($this->collectionWrapper, $file);
155-
$stream->downloadToStream($destination);
149+
stream_copy_to_stream($this->openDownloadStreamByName($filename, $options), $destination);
156150
}
157151

158152
/**
@@ -339,15 +333,18 @@ public function rename($id, $newFilename)
339333
* @param resource $source Readable stream
340334
* @param array $options Stream options
341335
* @return ObjectId ID of the newly created GridFS file
342-
* @throws InvalidArgumentException
336+
* @throws InvalidArgumentException if $source is not a stream
343337
*/
344338
public function uploadFromStream($filename, $source, array $options = [])
345339
{
346-
$options += ['chunkSizeBytes' => $this->options['chunkSizeBytes']];
340+
if ( ! is_resource($source) || get_resource_type($source) != "stream") {
341+
throw InvalidArgumentException::invalidType('$source', $source, 'resource');
342+
}
347343

348-
$stream = new WritableStream($this->collectionWrapper, $filename, $options);
344+
$destination = $this->openUploadStream($filename, $options);
345+
stream_copy_to_stream($source, $destination);
349346

350-
return $stream->uploadFromStream($source);
347+
return $this->getIdFromStream($destination);
351348
}
352349

353350
/**

src/GridFS/ReadableStream.php

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -129,24 +129,6 @@ public function downloadNumBytes($numBytes)
129129
return $output;
130130
}
131131

132-
/**
133-
* Writes the contents of this GridFS file to a writable stream.
134-
*
135-
* @param resource $destination Writable stream
136-
* @throws InvalidArgumentException
137-
*/
138-
public function downloadToStream($destination)
139-
{
140-
if ( ! is_resource($destination) || get_resource_type($destination) != "stream") {
141-
throw InvalidArgumentException::invalidType('$destination', $destination, 'resource');
142-
}
143-
144-
while ($this->advanceChunks()) {
145-
// TODO: Should we be checking for fwrite errors here?
146-
fwrite($destination, $this->chunksIterator->current()->data->getData());
147-
}
148-
}
149-
150132
/**
151133
* Return the stream's ID (i.e. file document identifier).
152134
*

src/GridFS/WritableStream.php

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -189,26 +189,6 @@ public function isEOF()
189189
return $this->isClosed;
190190
}
191191

192-
/**
193-
* Writes the contents of a readable stream to a GridFS file.
194-
*
195-
* @param resource $source Readable stream
196-
* @return ObjectId
197-
* @throws InvalidArgumentException
198-
*/
199-
public function uploadFromStream($source)
200-
{
201-
if ( ! is_resource($source) || get_resource_type($source) != "stream") {
202-
throw InvalidArgumentException::invalidType('$source', $source, 'resource');
203-
}
204-
205-
while ($data = $this->readChunk($source)) {
206-
$this->insertChunk($data);
207-
}
208-
209-
return $this->fileCollectionInsert();
210-
}
211-
212192
private function abort()
213193
{
214194
$this->collectionWrapper->deleteChunksByFilesId($this->file['_id']);

tests/GridFS/BucketFunctionalTest.php

Lines changed: 90 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,20 @@ public function testDownloadToStream($input)
172172
$this->assertStreamContents($input, $destination);
173173
}
174174

175+
/**
176+
* @expectedException MongoDB\Exception\InvalidArgumentException
177+
* @dataProvider provideInvalidStreamValues
178+
*/
179+
public function testDownloadToStreamShouldRequireDestinationStream($destination)
180+
{
181+
$this->bucket->downloadToStream('id', $destination);
182+
}
183+
184+
public function provideInvalidStreamValues()
185+
{
186+
return $this->wrapValuesForDataProvider([null, 123, 'foo', [], hash_init('md5')]);
187+
}
188+
175189
/**
176190
* @expectedException MongoDB\GridFS\Exception\FileNotFoundException
177191
*/
@@ -180,6 +194,73 @@ public function testDownloadToStreamShouldRequireFileToExist()
180194
$this->bucket->downloadToStream('nonexistent-id', $this->createStream());
181195
}
182196

197+
public function testDownloadToStreamByName()
198+
{
199+
$this->bucket->uploadFromStream('filename', $this->createStream('foo'));
200+
$this->bucket->uploadFromStream('filename', $this->createStream('bar'));
201+
$this->bucket->uploadFromStream('filename', $this->createStream('baz'));
202+
203+
$destination = $this->createStream();
204+
$this->bucket->downloadToStreamByName('filename', $destination);
205+
$this->assertStreamContents('baz', $destination);
206+
207+
$destination = $this->createStream();
208+
$this->bucket->downloadToStreamByName('filename', $destination, ['revision' => -3]);
209+
$this->assertStreamContents('foo', $destination);
210+
211+
$destination = $this->createStream();
212+
$this->bucket->downloadToStreamByName('filename', $destination, ['revision' => -2]);
213+
$this->assertStreamContents('bar', $destination);
214+
215+
$destination = $this->createStream();
216+
$this->bucket->downloadToStreamByName('filename', $destination, ['revision' => -1]);
217+
$this->assertStreamContents('baz', $destination);
218+
219+
$destination = $this->createStream();
220+
$this->bucket->downloadToStreamByName('filename', $destination, ['revision' => 0]);
221+
$this->assertStreamContents('foo', $destination);
222+
223+
$destination = $this->createStream();
224+
$this->bucket->downloadToStreamByName('filename', $destination, ['revision' => 1]);
225+
$this->assertStreamContents('bar', $destination);
226+
227+
$destination = $this->createStream();
228+
$this->bucket->downloadToStreamByName('filename', $destination, ['revision' => 2]);
229+
$this->assertStreamContents('baz', $destination);
230+
}
231+
232+
/**
233+
* @expectedException MongoDB\Exception\InvalidArgumentException
234+
* @dataProvider provideInvalidStreamValues
235+
*/
236+
public function testDownloadToStreamByNameShouldRequireDestinationStream($destination)
237+
{
238+
$this->bucket->downloadToStreamByName('filename', $destination);
239+
}
240+
241+
/**
242+
* @expectedException MongoDB\GridFS\Exception\FileNotFoundException
243+
* @dataProvider provideNonexistentFilenameAndRevision
244+
*/
245+
public function testDownloadToStreamByNameShouldRequireFilenameAndRevisionToExist($filename, $revision)
246+
{
247+
$this->bucket->uploadFromStream('filename', $this->createStream('foo'));
248+
$this->bucket->uploadFromStream('filename', $this->createStream('bar'));
249+
250+
$destination = $this->createStream();
251+
$this->bucket->downloadToStreamByName($filename, $destination, ['revision' => $revision]);
252+
}
253+
254+
public function provideNonexistentFilenameAndRevision()
255+
{
256+
return [
257+
['filename', 2],
258+
['filename', -3],
259+
['nonexistent-filename', 0],
260+
['nonexistent-filename', -1],
261+
];
262+
}
263+
183264
public function testDrop()
184265
{
185266
$this->bucket->uploadFromStream('filename', $this->createStream('foobar'));
@@ -306,16 +387,6 @@ public function testOpenDownloadStreamByNameShouldRequireFilenameAndRevisionToEx
306387
$this->bucket->openDownloadStream($filename, ['revision' => $revision]);
307388
}
308389

309-
public function provideNonexistentFilenameAndRevision()
310-
{
311-
return [
312-
['filename', 2],
313-
['filename', -3],
314-
['nonexistent-filename', 0],
315-
['nonexistent-filename', -1],
316-
];
317-
}
318-
319390
public function testOpenUploadStream()
320391
{
321392
$stream = $this->bucket->openUploadStream('filename');
@@ -401,6 +472,15 @@ public function testUploadFromStream()
401472
$this->assertSameDocument(['foo' => 'bar'], $fileDocument['metadata']);
402473
}
403474

475+
/**
476+
* @expectedException MongoDB\Exception\InvalidArgumentException
477+
* @dataProvider provideInvalidStreamValues
478+
*/
479+
public function testUploadFromStreamShouldRequireSourceStream($source)
480+
{
481+
$this->bucket->uploadFromStream('filename', $source);
482+
}
483+
404484
public function testUploadingAnEmptyFile()
405485
{
406486
$id = $this->bucket->uploadFromStream('filename', $this->createStream(''));

tests/GridFS/WritableStreamFunctionalTest.php

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -80,21 +80,4 @@ public function provideInputDataAndExpectedMD5()
8080
[str_repeat('foobar', 87041), '95e78f624f8e745bcfd2d11691fa601e'],
8181
];
8282
}
83-
84-
/**
85-
* @dataProvider provideInputDataAndExpectedMD5
86-
*/
87-
public function testUploadFromStreamCalculatesMD5($input, $expectedMD5)
88-
{
89-
$stream = new WritableStream($this->collectionWrapper, 'filename');
90-
$stream->uploadFromStream($this->createStream($input));
91-
//$stream->close();
92-
93-
$fileDocument = $this->filesCollection->findOne(
94-
['_id' => $stream->getId()],
95-
['projection' => ['md5' => 1, '_id' => 0]]
96-
);
97-
98-
$this->assertSameDocument(['md5' => $expectedMD5], $fileDocument);
99-
}
10083
}

0 commit comments

Comments
 (0)