Commit 5ffd0503 authored by Jeremy Mikola's avatar Jeremy Mikola

Merge pull request #189

parents c3e4774e c560e14e
<?php
namespace MongoDB\Exception;
class GridFSCorruptFileException extends \MongoDB\Driver\Exception\RuntimeException implements Exception
{
}
<?php
namespace MongoDB\Exception;
class GridFSFileNotFoundException extends \MongoDB\Driver\Exception\RuntimeException implements Exception
{
public function __construct($filename, $namespace)
{
parent::__construct(sprintf('Unable to find file "%s" in namespace "%s"', $filename, $namespace));
}
}
This diff is collapsed.
......@@ -3,19 +3,22 @@
namespace MongoDB\GridFS;
use MongoDB\Collection;
use MongoDB\UpdateResult;
use MongoDB\Driver\Cursor;
use MongoDB\Driver\Manager;
use MongoDB\Driver\ReadPreference;
use MongoDB\Driver\WriteConcern;
use IteratorIterator;
use stdClass;
/**
* GridFSCollectionsWrapper abstracts the GridFS files and chunks collections.
* CollectionWrapper abstracts the GridFS files and chunks collections.
*
* @internal
*/
class GridFSCollectionsWrapper
class CollectionWrapper
{
private $chunksCollection;
private $ensuredIndexes = false;
private $checkedIndexes = false;
private $filesCollection;
/**
......@@ -34,33 +37,183 @@ class GridFSCollectionsWrapper
$this->chunksCollection = new Collection($manager, $databaseName, sprintf('%s.chunks', $bucketName), $collectionOptions);
}
public function dropCollections(){
$this->filesCollection-> drop();
/**
* Deletes all GridFS chunks for a given file ID.
*
* @param mixed $id
*/
public function deleteChunksByFilesId($id)
{
$this->chunksCollection->deleteMany(['files_id' => $id]);
}
/**
* Deletes a GridFS file and related chunks by ID.
*
* @param mixed $id
*/
public function deleteFileAndChunksById($id)
{
$this->filesCollection->deleteOne(['_id' => $id]);
$this->chunksCollection->deleteMany(['files_id' => $id]);
}
/**
* Drops the GridFS files and chunks collections.
*/
public function dropCollections()
{
$this->filesCollection->drop();
$this->chunksCollection->drop();
}
/**
* Finds a GridFS file document for a given filename and revision.
*
* Revision numbers are defined as follows:
*
* * 0 = the original stored file
* * 1 = the first revision
* * 2 = the second revision
* * etc…
* * -2 = the second most recent revision
* * -1 = the most recent revision
*
* @see Bucket::downloadToStreamByName()
* @see Bucket::openDownloadStreamByName()
* @param string $filename
* @param integer $revision
* @return stdClass|null
*/
public function findFileByFilenameAndRevision($filename, $revision)
{
$filename = (string) $filename;
$revision = (integer) $revision;
if ($revision < 0) {
$skip = abs($revision) - 1;
$sortOrder = -1;
} else {
$skip = $revision;
$sortOrder = 1;
}
return $this->filesCollection->findOne(
['filename' => $filename],
[
'skip' => $skip,
'sort' => ['uploadDate' => $sortOrder],
'typeMap' => ['root' => 'stdClass'],
]
);
}
/**
* Finds a GridFS file document for a given ID.
*
* @param mixed $id
* @return stdClass|null
*/
public function findFileById($id)
{
return $this->filesCollection->findOne(
['_id' => $id],
['typeMap' => ['root' => 'stdClass']]
);
}
/**
* Finds documents from the GridFS bucket's files collection.
*
* @see Find::__construct() for supported options
* @param array|object $filter Query by which to filter documents
* @param array $options Additional options
* @return Cursor
*/
public function findFiles($filter, array $options = [])
{
return $this->filesCollection->find($filter, $options);
}
// TODO: Remove this
public function getChunksCollection()
{
return $this->chunksCollection;
}
/**
* Returns a chunks iterator for a given file ID.
*
* @param mixed $id
* @return IteratorIterator
*/
public function getChunksIteratorByFilesId($id)
{
$cursor = $this->chunksCollection->find(
['files_id' => $id],
[
'sort' => ['n' => 1],
'typeMap' => ['root' => 'stdClass'],
]
);
return new IteratorIterator($cursor);
}
// TODO: Remove this
public function getFilesCollection()
{
return $this->filesCollection;
}
/**
* Inserts a document into the chunks collection.
*
* @param array|object $chunk Chunk document
*/
public function insertChunk($chunk)
{
if ( ! $this->checkedIndexes) {
$this->ensureIndexes();
}
$this->chunksCollection->insertOne($chunk);
}
/**
* Inserts a document into the files collection.
*
* The file document should be inserted after all chunks have been inserted.
*
* @param array|object $file File document
*/
public function insertFile($file)
{
if ( ! $this->checkedIndexes) {
$this->ensureIndexes();
}
$this->filesCollection->insertOne($file);
}
/**
* Updates the filename field in the file document for a given ID.
*
* @param mixed $id
* @param string $filename
* @return UpdateResult
*/
public function updateFilenameForId($id, $filename)
{
return $this->filesCollection->updateOne(
['_id' => $id],
['$set' => ['filename' => (string) $filename]]
);
}
/**
* Create an index on the chunks collection if it does not already exist.
*/
private function ensureChunksIndex()
{
foreach ($this->chunksCollection->listIndexes() as $index) {
......@@ -72,6 +225,9 @@ class GridFSCollectionsWrapper
$this->chunksCollection->createIndex(['files_id' => 1, 'n' => 1], ['unique' => true]);
}
/**
* Create an index on the files collection if it does not already exist.
*/
private function ensureFilesIndex()
{
foreach ($this->filesCollection->listIndexes() as $index) {
......@@ -83,21 +239,33 @@ class GridFSCollectionsWrapper
$this->filesCollection->createIndex(['filename' => 1, 'uploadDate' => 1]);
}
/**
* Ensure indexes on the files and chunks collections exist.
*
* This method is called once before the first write operation on a GridFS
* bucket. Indexes are only be created if the files collection is empty.
*/
private function ensureIndexes()
{
if ($this->ensuredIndexes) {
if ($this->checkedIndexes) {
return;
}
$this->checkedIndexes = true;
if ( ! $this->isFilesCollectionEmpty()) {
return;
}
$this->ensureFilesIndex();
$this->ensureChunksIndex();
$this->ensuredIndexes = true;
}
/**
* Returns whether the files collection is empty.
*
* @return boolean
*/
private function isFilesCollectionEmpty()
{
return null === $this->filesCollection->findOne([], [
......
<?php
namespace MongoDB\GridFS\Exception;
use MongoDB\Exception\RuntimeException;
class CorruptFileException extends RuntimeException
{
/**
* Thrown when a chunk is not found for an expected index.
*
* @param integer $expectedIndex Expected index number
* @return self
*/
public static function missingChunk($expectedIndex)
{
return new static(sprintf('Chunk not found for index "%d"', $expectedIndex));
}
/**
* Thrown when a chunk has an unexpected index number.
*
* @param integer $index Actual index number (i.e. "n" field)
* @param integer $expectedIndex Expected index number
* @return self
*/
public static function unexpectedIndex($index, $expectedIndex)
{
return new static(sprintf('Expected chunk to have index "%d" but found "%d"', $expectedIndex, $index));
}
/**
* Thrown when a chunk has an unexpected data size.
*
* @param integer $size Actual size (i.e. "data" field length)
* @param integer $expectedSize Expected size
* @return self
*/
public static function unexpectedSize($size, $expectedSize)
{
return new static(sprintf('Expected chunk to have size "%d" but found "%d"', $expectedSize, $size));
}
}
<?php
namespace MongoDB\GridFS\Exception;
use MongoDB\Exception\RuntimeException;
class FileNotFoundException extends RuntimeException
{
/**
* Thrown when a file cannot be found by its filename and revision.
*
* @param string $filename Filename
* @param integer $revision Revision
* @param string $namespace Namespace for the files collection
* @return self
*/
public static function byFilenameAndRevision($filename, $revision, $namespace)
{
return new static(sprintf('File with name "%s" and revision "%d" not found in "%s"', $filename, $revision, $namespace));
}
/**
* Thrown when a file cannot be found by its ID.
*
* @param mixed $id File ID
* @param string $namespace Namespace for the files collection
* @return self
*/
public static function byId($id, $namespace)
{
$json = \MongoDB\BSON\toJSON(\MongoDB\BSON\fromPHP(['_id' => $id]));
return new static(sprintf('File "%s" not found in "%s"', $json, $namespace));
}
}
......@@ -3,53 +3,41 @@
namespace MongoDB\GridFS;
use MongoDB\Driver\Exception\Exception;
use MongoDB\Exception\GridFSCorruptFileException;
use MongoDB\GridFS\Exception\CorruptFileException;
use stdClass;
/**
* GridFSDownload abstracts the process of reading a GridFS file.
* ReadableStream abstracts the process of reading a GridFS file.
*
* @internal
*/
class GridFSDownload
class ReadableStream
{
private $buffer;
private $bufferEmpty = true;
private $bufferFresh = true;
private $bufferEmpty;
private $bufferFresh;
private $bytesSeen = 0;
private $chunkOffset = 0;
private $chunksIterator;
private $collectionsWrapper;
private $file;
private $firstCheck = true;
private $iteratorEmpty = false;
private $numChunks;
/**
* Constructs a GridFS download stream.
* Constructs a readable GridFS stream.
*
* @param GridFSCollectionsWrapper $collectionsWrapper GridFS collections wrapper
* @param CollectionWrapper $collectionWrapper GridFS collection wrapper
* @param stdClass $file GridFS file document
* @throws GridFSCorruptFileException
* @throws CorruptFileException
*/
public function __construct(GridFSCollectionsWrapper $collectionsWrapper, stdClass $file)
public function __construct(CollectionWrapper $collectionWrapper, stdClass $file)
{
$this->collectionsWrapper = $collectionsWrapper;
$this->file = $file;
try {
$cursor = $this->collectionsWrapper->getChunksCollection()->find(
['files_id' => $this->file->_id],
['sort' => ['n' => 1]]
);
} catch (Exception $e) {
// TODO: Why do we replace a driver exception with GridFSCorruptFileException here?
throw new GridFSCorruptFileException();
}
$this->chunksIterator = new \IteratorIterator($cursor);
$this->chunksIterator = $collectionWrapper->getChunksIteratorByFilesId($this->file->_id);
$this->numChunks = ($file->length >= 0) ? ceil($file->length / $file->chunkSize) : 0;
$this->buffer = fopen('php://temp', 'w+');
$this->initEmptyBuffer();
}
public function close()
......@@ -57,32 +45,35 @@ class GridFSDownload
fclose($this->buffer);
}
public function downloadNumBytes($numToRead)
/**
* Read bytes from the stream.
*
* Note: this method may return a string smaller than the requested length
* if data is not available to be read.
*
* @param integer $numBytes Number of bytes to read
* @return string
*/
public function downloadNumBytes($numBytes)
{
$output = "";
if ($this->bufferFresh) {
rewind($this->buffer);
$this->bufferFresh = false;
}
// TODO: Should we be checking for fread errors here?
$output = fread($this->buffer, $numToRead);
$output = fread($this->buffer, $numBytes);
if (strlen($output) == $numToRead) {
if (strlen($output) == $numBytes) {
return $output;
}
fclose($this->buffer);
$this->buffer = fopen("php://temp", "w+");
$this->bufferFresh = true;
$this->bufferEmpty = true;
$this->initEmptyBuffer();
$bytesLeft = $numToRead - strlen($output);
$bytesLeft = $numBytes - strlen($output);
while (strlen($output) < $numToRead && $this->advanceChunks()) {
$bytesLeft = $numToRead - strlen($output);
while (strlen($output) < $numBytes && $this->advanceChunks()) {
$bytesLeft = $numBytes - strlen($output);
$output .= substr($this->chunksIterator->current()->data->getData(), 0, $bytesLeft);
}
......@@ -94,8 +85,18 @@ class GridFSDownload
return $output;
}
/**
* Writes the contents of this GridFS file to a writable stream.
*
* @param resource $destination Writable stream
* @throws InvalidArgumentException
*/
public function downloadToStream($destination)
{
if ( ! is_resource($destination) || get_resource_type($destination) != "stream") {
throw InvalidArgumentException::invalidType('$destination', $destination, 'resource');
}
while ($this->advanceChunks()) {
// TODO: Should we be checking for fwrite errors here?
fwrite($destination, $this->chunksIterator->current()->data->getData());
......@@ -138,11 +139,11 @@ class GridFSDownload
}
if ( ! $this->chunksIterator->valid()) {
throw new GridFSCorruptFileException();
throw CorruptFileException::missingChunk($this->chunkOffset);
}
if ($this->chunksIterator->current()->n != $this->chunkOffset) {
throw new GridFSCorruptFileException();
throw CorruptFileException::unexpectedIndex($this->chunksIterator->current()->n, $this->chunkOffset);
}
$actualChunkSize = strlen($this->chunksIterator->current()->data->getData());
......@@ -152,7 +153,7 @@ class GridFSDownload
: $this->file->chunkSize;
if ($actualChunkSize != $expectedChunkSize) {
throw new GridFSCorruptFileException();
throw CorruptFileException::unexpectedSize($actualChunkSize, $expectedChunkSize);
}
$this->bytesSeen += $actualChunkSize;
......@@ -160,4 +161,15 @@ class GridFSDownload
return true;
}
private function initEmptyBuffer()
{
if (isset($this->buffer)) {
fclose($this->buffer);
}
$this->buffer = fopen("php://temp", "w+");
$this->bufferEmpty = true;
$this->bufferFresh = true;
}
}
......@@ -11,96 +11,130 @@ namespace MongoDB\GridFS;
*/
class StreamWrapper
{
/**
* @var resource|null Stream context (set by PHP)
*/
public $context;
private $collectionsWrapper;
private $gridFSStream;
private $id;
private $mode;
private $protocol;
private $stream;
public function getId()
{
return $this->id;
}
public function openReadStream()
{
$context = stream_context_get_options($this->context);
$this->gridFSStream = new GridFSDownload($this->collectionsWrapper, $context['gridfs']['file']);
$this->id = $this->gridFSStream->getId();
return true;
}
public function openWriteStream()
{
$context = stream_context_get_options($this->context);
$options = $context['gridfs']['uploadOptions'];
$this->gridFSStream = new GridFSUpload($this->collectionsWrapper, $this->identifier, $options);
$this->id = $this->gridFSStream->getId();
return true;
return $this->stream->getId();
}
/**
* Register the GridFS stream wrapper.
*
* @param string $protocol Protocol to use for stream_wrapper_register()
*/
public static function register()
public static function register($protocol = 'gridfs')
{
if (in_array('gridfs', stream_get_wrappers())) {
stream_wrapper_unregister('gridfs');
if (in_array($protocol, stream_get_wrappers())) {
stream_wrapper_unregister($protocol);
}
stream_wrapper_register('gridfs', get_called_class(), \STREAM_IS_URL);
stream_wrapper_register($protocol, get_called_class(), \STREAM_IS_URL);
}
/**
* Closes the stream.
*
* @see http://php.net/manual/en/streamwrapper.stream-close.php
*/
public function stream_close()
{
$this->gridFSStream->close();
$this->stream->close();
}
/**
* Returns whether the file pointer is at the end of the stream.
*
* @see http://php.net/manual/en/streamwrapper.stream-eof.php
* @return boolean
*/
public function stream_eof()
{
return $this->gridFSStream->isEOF();
return $this->stream->isEOF();
}
/**
* Opens the stream.
*
* @see http://php.net/manual/en/streamwrapper.stream-open.php
* @param string $path Path to the file resource
* @param string $mode Mode used to open the file (only "r" and "w" are supported)
* @param integer $options Additional flags set by the streams API
* @param string $openedPath Not used
*/
public function stream_open($path, $mode, $options, &$openedPath)
{
$this->initProtocol($path);
$context = stream_context_get_options($this->context);
$this->collectionsWrapper = $context['gridfs']['collectionsWrapper'];
$this->mode = $mode;
switch ($this->mode) {
case 'r': return $this->openReadStream();
case 'w': return $this->openWriteStream();
default: return false;
if ($mode === 'r') {
return $this->initReadableStream();
}
if ($mode === 'w') {
return $this->initWritableStream();
}
return false;
}
/**
* Read bytes from the stream.
*
* Note: this method may return a string smaller than the requested length
* if data is not available to be read.
*
* @see http://php.net/manual/en/streamwrapper.stream-read.php
* @param integer $count Number of bytes to read
* @return string
*/
public function stream_read($count)
{
return $this->gridFSStream->downloadNumBytes($count);
// TODO: Ensure that $this->stream is a ReadableStream
return $this->stream->downloadNumBytes($count);
}
/**
* Return information about the stream.
*
* @see http://php.net/manual/en/streamwrapper.stream-stat.php
* @return array
*/
public function stream_stat()
{
$stat = $this->getStatTemplate();
$stat[7] = $stat['size'] = $this->gridFSStream->getSize();
$stat[2] = $stat['mode'] = $this->mode;
$stat[7] = $stat['size'] = $this->stream->getSize();
return $stat;
}
/**
* Write bytes to the stream.
*
* @see http://php.net/manual/en/streamwrapper.stream-write.php
* @param string $data Data to write
* @return integer The number of bytes successfully stored
*/
public function stream_write($data)
{
$this->gridFSStream->insertChunks($data);
// TODO: Ensure that $this->stream is a WritableStream
$this->stream->insertChunks($data);
return strlen($data);
}
/**
* Gets a URL stat template with default values
* from https://github.com/aws/aws-sdk-php/blob/master/src/S3/StreamWrapper.php
* Returns a stat template with default values.
*
* @return array
*/
private function getStatTemplate()
......@@ -122,9 +156,52 @@ class StreamWrapper
];
}
/**
* Initialize the protocol from the given path.
*
* @see StreamWrapper::stream_open()
* @param string $path
*/
private function initProtocol($path)
{
$parsed_path = parse_url($path);
$this->identifier = substr($parsed_path['path'], 1);
$parts = explode('://', $path, 2);
$this->protocol = $parts[0] ?: 'gridfs';
}
/**
* Initialize the internal stream for reading.
*
* @see StreamWrapper::stream_open()
* @return boolean
*/
private function initReadableStream()
{
$context = stream_context_get_options($this->context);
$this->stream = new ReadableStream(
$context[$this->protocol]['collectionWrapper'],
$context[$this->protocol]['file']
);
return true;
}
/**
* Initialize the internal stream for writing.
*
* @see StreamWrapper::stream_open()
* @return boolean
*/
private function initWritableStream()
{
$context = stream_context_get_options($this->context);
$this->stream = new WritableStream(
$context[$this->protocol]['collectionWrapper'],
$context[$this->protocol]['filename'],
$context[$this->protocol]['options']
);
return true;
}
}
......@@ -5,32 +5,35 @@ namespace MongoDB\GridFS;
use MongoDB\BSON\Binary;
use MongoDB\BSON\ObjectId;
use MongoDB\BSON\UTCDateTime;
use MongoDB\Driver\Exception\Exception;
use MongoDB\Driver\Exception\Exception as DriverException;
use MongoDB\Exception\InvalidArgumentException;
/**
* GridFSUpload abstracts the process of writing a GridFS file.
* WritableStream abstracts the process of writing a GridFS file.
*
* @internal
*/
class GridFSUpload
class WritableStream
{
private static $defaultChunkSizeBytes = 261120;
private $buffer;
private $bufferLength = 0;
private $chunkOffset = 0;
private $chunkSize;
private $collectionsWrapper;
private $collectionWrapper;
private $ctx;
private $file;
private $indexChecker;
private $isClosed = false;
private $length = 0;
/**
* Constructs a GridFS upload stream.
* Constructs a writable GridFS stream.
*
* Supported options:
*
* * _id (mixed): File document identifier. Defaults to a new ObjectId.
*
* * aliases (array of strings): DEPRECATED An array of aliases.
* Applications wishing to store aliases should add an aliases field to
* the metadata document instead.
......@@ -44,19 +47,26 @@ class GridFSUpload
* * metadata (document): User data for the "metadata" field of the files
* collection document.
*
* @param GridFSCollectionsWrapper $collectionsWrapper GridFS collections wrapper
* @param CollectionWrapper $collectionWrapper GridFS collection wrapper
* @param string $filename File name
* @param array $options Upload options
* @throws InvalidArgumentException
*/
public function __construct(GridFSCollectionsWrapper $collectionsWrapper, $filename, array $options = [])
public function __construct(CollectionWrapper $collectionWrapper, $filename, array $options = [])
{
$options += ['chunkSizeBytes' => 261120];
$options += [
'_id' => new ObjectId,
'chunkSizeBytes' => self::$defaultChunkSizeBytes,
];
if (isset($options['aliases']) && ! \MongoDB\is_string_array($options['aliases'])) {
throw InvalidArgumentException::invalidType('"aliases" option', $options['aliases'], 'array of strings');
}
if (isset($options['chunkSizeBytes']) && ! is_integer($options['chunkSizeBytes'])) {
throw InvalidArgumentException::invalidType('"chunkSizeBytes" option', $options['chunkSizeBytes'], 'integer');
}
if (isset($options['contentType']) && ! is_string($options['contentType'])) {
throw InvalidArgumentException::invalidType('"contentType" option', $options['contentType'], 'string');
}
......@@ -66,15 +76,16 @@ class GridFSUpload
}
$this->chunkSize = $options['chunkSizeBytes'];
$this->collectionsWrapper = $collectionsWrapper;
$this->collectionWrapper = $collectionWrapper;
$this->buffer = fopen('php://temp', 'w+');
$this->ctx = hash_init('md5');
$this->file = [
'_id' => new ObjectId(),
'_id' => $options['_id'],
'chunkSize' => $this->chunkSize,
'filename' => (string) $filename,
'uploadDate' => $this->createUploadDate(),
// TODO: This is necessary until PHPC-536 is implemented
'uploadDate' => new UTCDateTime(floor(microtime(true) * 1000)),
] + array_intersect_key($options, ['aliases' => 1, 'contentType' => 1, 'metadata' => 1]);
}
......@@ -133,7 +144,7 @@ class GridFSUpload
* reset.
*
* @param string $toWrite Binary data to write
* @return int
* @return integer
*/
public function insertChunks($toWrite)
{
......@@ -171,6 +182,7 @@ class GridFSUpload
*
* @param resource $source Readable stream
* @return ObjectId
* @throws InvalidArgumentException
*/
public function uploadFromStream($source)
{
......@@ -178,8 +190,6 @@ class GridFSUpload
throw InvalidArgumentException::invalidType('$source', $source, 'resource');
}
$streamMetadata = stream_get_meta_data($source);
while ($data = $this->readChunk($source)) {
$this->insertChunk($data);
}
......@@ -189,20 +199,10 @@ class GridFSUpload
private function abort()
{
$this->collectionsWrapper->getChunksCollection()->deleteMany(['files_id' => $this->file['_id']]);
$this->collectionsWrapper->getFilesCollection()->deleteOne(['_id' => $this->file['_id']]);
$this->collectionWrapper->deleteChunksByFilesId($this->file['_id']);
$this->isClosed = true;
}
// From: http://stackoverflow.com/questions/3656713/how-to-get-current-time-in-milliseconds-in-php
private function createUploadDate()
{
$parts = explode(' ', microtime());
$milliseconds = sprintf('%d%03d', $parts[1], $parts[0] * 1000);
return new UTCDateTime($milliseconds);
}
private function fileCollectionInsert()
{
if ($this->isClosed) {
......@@ -215,7 +215,7 @@ class GridFSUpload
$this->file['length'] = $this->length;
$this->file['md5'] = $md5;
$this->collectionsWrapper->insertFile($this->file);
$this->collectionWrapper->insertFile($this->file);
return $this->file['_id'];
}
......@@ -235,7 +235,7 @@ class GridFSUpload
hash_update($this->ctx, $data);
$this->collectionsWrapper->insertChunk($toUpload);
$this->collectionWrapper->insertChunk($toUpload);
$this->length += strlen($data);
$this->chunkOffset++;
}
......@@ -244,7 +244,7 @@ class GridFSUpload
{
try {
$data = fread($source, $this->chunkSize);
} catch (Exception $e) {
} catch (DriverException $e) {
$this->abort();
throw $e;
}
......
......@@ -63,8 +63,8 @@ class BucketFunctionalTest extends FunctionalTestCase
$id = $this->bucket->uploadFromStream("test_filename", $this->generateStream("hello world"));
$contents = stream_get_contents($this->bucket->openDownloadStream($id));
$this->assertEquals("hello world", $contents);
$this->assertEquals(1, $this->bucket->getCollectionsWrapper()->getFilesCollection()->count());
$this->assertEquals(1, $this->bucket->getCollectionsWrapper()->getChunksCollection()->count());
$this->assertEquals(1, $this->bucket->getCollectionWrapper()->getFilesCollection()->count());
$this->assertEquals(1, $this->bucket->getCollectionWrapper()->getChunksCollection()->count());
$this->bucket->delete($id);
$error=null;
......@@ -73,19 +73,19 @@ class BucketFunctionalTest extends FunctionalTestCase
} catch(\MongoDB\Exception\Exception $e) {
$error = $e;
}
$fileNotFound = '\MongoDB\Exception\GridFSFileNotFoundException';
$fileNotFound = '\MongoDB\GridFS\Exception\FileNotFoundException';
$this->assertTrue($error instanceof $fileNotFound);
$this->assertEquals(0, $this->bucket->getCollectionsWrapper()->getFilesCollection()->count());
$this->assertEquals(0, $this->bucket->getCollectionsWrapper()->getChunksCollection()->count());
$this->assertEquals(0, $this->bucket->getCollectionWrapper()->getFilesCollection()->count());
$this->assertEquals(0, $this->bucket->getCollectionWrapper()->getChunksCollection()->count());
}
public function testMultiChunkDelete()
{
$id = $this->bucket->uploadFromStream("test_filename", $this->generateStream("hello"), ['chunkSizeBytes'=>1]);
$this->assertEquals(1, $this->bucket->getCollectionsWrapper()->getFilesCollection()->count());
$this->assertEquals(5, $this->bucket->getCollectionsWrapper()->getChunksCollection()->count());
$this->assertEquals(1, $this->bucket->getCollectionWrapper()->getFilesCollection()->count());
$this->assertEquals(5, $this->bucket->getCollectionWrapper()->getChunksCollection()->count());
$this->bucket->delete($id);
$this->assertEquals(0, $this->bucket->getCollectionsWrapper()->getFilesCollection()->count());
$this->assertEquals(0, $this->bucket->getCollectionsWrapper()->getChunksCollection()->count());
$this->assertEquals(0, $this->bucket->getCollectionWrapper()->getFilesCollection()->count());
$this->assertEquals(0, $this->bucket->getCollectionWrapper()->getChunksCollection()->count());
}
public function testEmptyFile()
......@@ -93,10 +93,10 @@ class BucketFunctionalTest extends FunctionalTestCase
$id = $this->bucket->uploadFromStream("test_filename",$this->generateStream(""));
$contents = stream_get_contents($this->bucket->openDownloadStream($id));
$this->assertEquals("", $contents);
$this->assertEquals(1, $this->bucket->getCollectionsWrapper()->getFilesCollection()->count());
$this->assertEquals(0, $this->bucket->getCollectionsWrapper()->getChunksCollection()->count());
$this->assertEquals(1, $this->bucket->getCollectionWrapper()->getFilesCollection()->count());
$this->assertEquals(0, $this->bucket->getCollectionWrapper()->getChunksCollection()->count());
$raw = $this->bucket->getCollectionsWrapper()->getFilesCollection()->findOne();
$raw = $this->bucket->getCollectionWrapper()->getFilesCollection()->findOne();
$this->assertEquals(0, $raw->length);
$this->assertEquals($id, $raw->_id);
$this->assertTrue($raw->uploadDate instanceof \MongoDB\BSON\UTCDateTime);
......@@ -107,7 +107,7 @@ class BucketFunctionalTest extends FunctionalTestCase
{
$id = $this->bucket->uploadFromStream("test_filename", $this->generateStream("foobar"));
$this->collectionsWrapper->getChunksCollection()->updateOne(['files_id' => $id],
$this->collectionWrapper->getChunksCollection()->updateOne(['files_id' => $id],
['$set' => ['data' => new \MongoDB\BSON\Binary('foo', \MongoDB\BSON\Binary::TYPE_GENERIC)]]);
$error = null;
try{
......@@ -116,14 +116,14 @@ class BucketFunctionalTest extends FunctionalTestCase
} catch(\MongoDB\Exception\Exception $e) {
$error = $e;
}
$corruptFileError = '\MongoDB\Exception\GridFSCOrruptFileException';
$corruptFileError = '\MongoDB\GridFS\Exception\CorruptFileException';
$this->assertTrue($error instanceof $corruptFileError);
}
public function testErrorsOnMissingChunk()
{
$id = $this->bucket->uploadFromStream("test_filename", $this->generateStream("hello world,abcdefghijklmnopqrstuv123456789"), ["chunkSizeBytes" => 1]);
$this->collectionsWrapper->getChunksCollection()->deleteOne(['files_id' => $id, 'n' => 7]);
$this->collectionWrapper->getChunksCollection()->deleteOne(['files_id' => $id, 'n' => 7]);
$error = null;
try{
$download = $this->bucket->openDownloadStream($id);
......@@ -131,13 +131,13 @@ class BucketFunctionalTest extends FunctionalTestCase
} catch(\MongoDB\Exception\Exception $e) {
$error = $e;
}
$corruptFileError = '\MongoDB\Exception\GridFSCOrruptFileException';
$corruptFileError = '\MongoDB\GridFS\Exception\CorruptFileException';
$this->assertTrue($error instanceof $corruptFileError);
}
public function testUploadEnsureIndexes()
{
$chunks = $this->bucket->getCollectionsWrapper()->getChunksCollection();
$files = $this->bucket->getCollectionsWrapper()->getFilesCollection();
$chunks = $this->bucket->getCollectionWrapper()->getChunksCollection();
$files = $this->bucket->getCollectionWrapper()->getFilesCollection();
$this->bucket->uploadFromStream("filename", $this->generateStream("junk"));
$chunksIndexed = false;
......@@ -177,7 +177,7 @@ class BucketFunctionalTest extends FunctionalTestCase
} catch(\MongoDB\Exception\Exception $e) {
$error = $e;
}
$fileNotFound = '\MongoDB\Exception\GridFSFileNotFoundException';
$fileNotFound = '\MongoDB\GridFS\Exception\FileNotFoundException';
$this->assertTrue($error instanceof $fileNotFound);
}
public function testGetVersion()
......@@ -194,7 +194,7 @@ class BucketFunctionalTest extends FunctionalTestCase
$this->assertEquals("bar", stream_get_contents($this->bucket->openDownloadStreamByName("test", ['revision' => -2])));
$this->assertEquals("foo", stream_get_contents($this->bucket->openDownloadStreamByName("test", ['revision' => -3])));
$fileNotFound = '\MongoDB\Exception\GridFSFileNotFoundException';
$fileNotFound = '\MongoDB\GridFS\Exception\FileNotFoundException';
$error = null;
try{
$this->bucket->openDownloadStreamByName("test", ['revision' => 3]);
......@@ -238,7 +238,7 @@ class BucketFunctionalTest extends FunctionalTestCase
public function testGridInNonIntChunksize()
{
$id = $this->bucket->uploadFromStream("f",$this->generateStream("data"));
$this->bucket->getCollectionsWrapper()->getFilesCollection()->updateOne(["filename"=>"f"],
$this->bucket->getCollectionWrapper()->getFilesCollection()->updateOne(["filename"=>"f"],
['$set'=> ['chunkSize' => 100.00]]);
$this->assertEquals("data", stream_get_contents($this->bucket->openDownloadStream($id)));
}
......@@ -278,7 +278,7 @@ class BucketFunctionalTest extends FunctionalTestCase
} catch(\MongoDB\Exception\Exception $e) {
$error = $e;
}
$fileNotFound = '\MongoDB\Exception\GridFSFileNotFoundException';
$fileNotFound = '\MongoDB\GridFS\Exception\FileNotFoundException';
$this->assertTrue($error instanceof $fileNotFound);
$this->assertEquals("testing", stream_get_contents($this->bucket->openDownloadStreamByName("second_name")));
......@@ -288,7 +288,7 @@ class BucketFunctionalTest extends FunctionalTestCase
$id = $this->bucket->uploadFromStream("test_filename", $this->generateStream("hello world"));
$this->bucket->drop();
$id = $this->bucket->uploadFromStream("test_filename", $this->generateStream("hello world"));
$this->assertEquals(1, $this->collectionsWrapper->getFilesCollection()->count());
$this->assertEquals(1, $this->collectionWrapper->getFilesCollection()->count());
}
/**
*@dataProvider provideInsertChunks
......
......@@ -12,7 +12,7 @@ use MongoDB\Tests\FunctionalTestCase as BaseFunctionalTestCase;
abstract class FunctionalTestCase extends BaseFunctionalTestCase
{
protected $bucket;
protected $collectionsWrapper;
protected $collectionWrapper;
public function setUp()
{
......@@ -22,7 +22,7 @@ abstract class FunctionalTestCase extends BaseFunctionalTestCase
$col->drop();
}
$this->bucket = new \MongoDB\GridFS\Bucket($this->manager, $this->getDatabaseName());
$this->collectionsWrapper = $this->bucket->getCollectionsWrapper();
$this->collectionWrapper = $this->bucket->getCollectionWrapper();
}
public function tearDown()
......
This diff is collapsed.
......@@ -52,11 +52,11 @@ class SpecificationTests extends FunctionalTestCase
} catch(\MongoDB\Exception\Exception $e) {
$error = $e;
}
$errors = ['FileNotFound' => '\MongoDB\Exception\GridFSFileNotFoundException',
'ChunkIsMissing' => '\MongoDB\Exception\GridFSCorruptFileException',
'ExtraChunk' => '\MongoDB\Exception\GridFSCorruptFileException',
'ChunkIsWrongSize' => '\MongoDB\Exception\GridFSCorruptFileException',
'RevisionNotFound' => '\MongoDB\Exception\GridFSFileNotFoundException'
$errors = ['FileNotFound' => '\MongoDB\GridFS\Exception\FileNotFoundException',
'ChunkIsMissing' => '\MongoDB\GridFS\Exception\CorruptFileException',
'ExtraChunk' => '\MongoDB\GridFS\Exception\CorruptFileException',
'ChunkIsWrongSize' => '\MongoDB\GridFS\Exception\CorruptFileException',
'RevisionNotFound' => '\MongoDB\GridFS\Exception\FileNotFoundException'
];
if (!isset($test['assert']['error'])) {
$this->assertNull($error);
......@@ -78,9 +78,9 @@ class SpecificationTests extends FunctionalTestCase
$fixedAssertTrue = $this->fixTypes($test['assert'], true);
if (isset($test['assert']['data'])) {
$this->runCommands($fixedAssertTrue['data'], $result);
$this->collectionsEqual($this->collections['expected.files'],$this->bucket->getCollectionsWrapper()->getFilesCollection());
$this->collectionsEqual($this->collections['expected.files'],$this->bucket->getCollectionWrapper()->getFilesCollection());
if(isset($this->collections['expected.chunks'])) {
$this->collectionsEqual($this->collections['expected.chunks'],$this->bucket->getCollectionsWrapper()->getChunksCollection());
$this->collectionsEqual($this->collections['expected.chunks'],$this->bucket->getCollectionWrapper()->getChunksCollection());
}
}
}
......@@ -161,7 +161,7 @@ class SpecificationTests extends FunctionalTestCase
$cmd['documents'][$docIndex] = $doc;
}
}
$collection = new Collection($this->manager, sprintf("%s.%s", $this->getDatabaseName(), $collectionName));
$collection = new Collection($this->manager, $this->getDatabaseName(), $collectionName);
$this->commands[$key]($collection, $this->fixTypes($cmd, true));
$this->collections[$collectionName] = $collection;
}
......@@ -175,20 +175,20 @@ class SpecificationTests extends FunctionalTestCase
$collectionsToDrop = ['fs.files','fs.chunks','expected.files','expected.chunks'];
$data = $this->fixTypes($data, true);
foreach ($collectionsToDrop as $collectionName) {
$collection = new Collection($this->manager, sprintf("%s.%s", $this->getDatabaseName(), $collectionName));
$collection = new Collection($this->manager, $this->getDatabaseName(), $collectionName);
$collection->drop();
}
if (isset($data['files']) && count($data['files']) > 0) {
$filesCollection = new Collection($this->manager, sprintf("%s.%s", $this->getDatabaseName(), "fs.files"));
$filesCollection = new Collection($this->manager, $this->getDatabaseName(), "fs.files");
$filesCollection->insertMany($data['files']);
$expectedFilesCollection = new Collection($this->manager, sprintf("%s.%s", $this->getDatabaseName(), "expected.files"));
$expectedFilesCollection = new Collection($this->manager, $this->getDatabaseName(), "expected.files");
$expectedFilesCollection->insertMany($data['files']);
$this->collections['expected.files'] = $expectedFilesCollection;
}
if (isset($data['chunks']) && count($data['chunks']) > 0) {
$chunksCollection = new Collection($this->manager, sprintf("%s.%s", $this->getDatabaseName(), "fs.chunks"));
$chunksCollection = new Collection($this->manager, $this->getDatabaseName(), "fs.chunks");
$chunksCollection->insertMany($data['chunks']);
$expectedChunksCollection = new Collection($this->manager, sprintf("%s.%s", $this->getDatabaseName(), "expected.chunks"));
$expectedChunksCollection = new Collection($this->manager, $this->getDatabaseName(), "expected.chunks");
$expectedChunksCollection->insertMany($data['chunks']);
$this->collections['expected.chunks'] = $expectedChunksCollection;
......@@ -197,7 +197,7 @@ class SpecificationTests extends FunctionalTestCase
foreach($test['arrange']['data'] as $cmd) {
foreach($cmd as $key => $value) {
if(isset($this->commands[$key])) {
$collection = new Collection($this->manager, sprintf("%s.%s", $this->getDatabaseName(), $cmd[$key]));
$collection = new Collection($this->manager, $this->getDatabaseName(), $cmd[$key]);
$this->commands[$key]($collection,$this->fixTypes($cmd, true));
}
}
......@@ -217,8 +217,6 @@ class SpecificationTests extends FunctionalTestCase
function downloadCommand($args)
{
$args = $this->fixTypes($args, false);
$streamWrapper = new \MongoDB\GridFS\StreamWrapper();
$streamWrapper->register($this->manager);
$stream = fopen('php://temp', 'w+');
$this->bucket->downloadToStream($args['id'], $stream);
rewind($stream);
......@@ -234,11 +232,9 @@ class SpecificationTests extends FunctionalTestCase
function download_by_nameCommand($args)
{
$args = $this->fixTypes($args, false);
$streamWrapper = new \MongoDB\GridFS\StreamWrapper();
$streamWrapper->register($this->manager);
$stream = fopen('php://temp', 'w+');
if(isset($args['options']['revision'])) {
$this->bucket->downloadToStreamByName($args['filename'], $stream, $args['options']['revision']);
if(isset($args['options'])) {
$this->bucket->downloadToStreamByName($args['filename'], $stream, $args['options']);
} else {
$this->bucket->downloadToStreamByName($args['filename'], $stream);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment