diff --git a/.travis.yml b/.travis.yml index 808653d..a135d54 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: php dist: precise php: - - 5.3 - 5.4 - 5.5 diff --git a/composer.json b/composer.json index f64f377..9e4ec04 100644 --- a/composer.json +++ b/composer.json @@ -19,13 +19,18 @@ "chunks" ], "require": { - "php": ">=5.3" + "php": ">=5.4" }, "require-dev": { "mikey179/vfsstream": "v1.2.0", "league/phpunit-coverage-listener": "~1.1", "fabpot/php-cs-fixer": "~2.2", - "phpunit/phpunit": "4.*" + "phpunit/phpunit": "4.*", + "mongodb/mongodb": "^1.4.0", + "ext-mongodb": "*" + }, + "suggest": { + "mongodb/mongodb":"Required to use this package with Mongo DB" }, "autoload": { "psr-0": { diff --git a/src/Flow/Mongo/MongoConfig.php b/src/Flow/Mongo/MongoConfig.php index fa90f2e..1d11f45 100644 --- a/src/Flow/Mongo/MongoConfig.php +++ b/src/Flow/Mongo/MongoConfig.php @@ -3,6 +3,7 @@ namespace Flow\Mongo; use Flow\Config; +use MongoDB\GridFS\Bucket; /** * @codeCoverageIgnore @@ -12,9 +13,9 @@ class MongoConfig extends Config implements MongoConfigInterface private $gridFs; /** - * @param \MongoGridFS $gridFS storage of the upload (and chunks) + * @param Bucket $gridFS storage of the upload (and chunks) */ - function __construct(\MongoGridFS $gridFS) + function __construct(Bucket $gridFS) { parent::__construct(); $this->gridFs = $gridFS; @@ -22,7 +23,7 @@ function __construct(\MongoGridFS $gridFS) /** - * @return \MongoGridFS + * @return Bucket */ public function getGridFs() { diff --git a/src/Flow/Mongo/MongoConfigInterface.php b/src/Flow/Mongo/MongoConfigInterface.php index c9aa7b3..0d3308f 100644 --- a/src/Flow/Mongo/MongoConfigInterface.php +++ b/src/Flow/Mongo/MongoConfigInterface.php @@ -3,6 +3,7 @@ namespace Flow\Mongo; use Flow\ConfigInterface; +use MongoDB\GridFS\Bucket; /** * @codeCoverageIgnore @@ -11,7 +12,7 @@ interface MongoConfigInterface extends ConfigInterface { /** - * @return \MongoGridFS + * @return Bucket */ public function getGridFs(); diff --git a/src/Flow/Mongo/MongoFile.php b/src/Flow/Mongo/MongoFile.php index d4d3660..7996b10 100644 --- a/src/Flow/Mongo/MongoFile.php +++ b/src/Flow/Mongo/MongoFile.php @@ -2,9 +2,14 @@ namespace Flow\Mongo; +use Exception; use Flow\File; use Flow\Request; use Flow\RequestInterface; +use MongoDB\BSON\Binary; +use MongoDB\BSON\ObjectId; +use MongoDB\BSON\UTCDateTime; +use MongoDB\Operation\FindOneAndReplace; /** @@ -42,9 +47,9 @@ protected function getGridFsFile() if (!$this->uploadGridFsFile) { $gridFsFileQuery = $this->getGridFsFileQuery(); $changed = $gridFsFileQuery; - $changed['flowUpdated'] = new \MongoDate(); - $this->uploadGridFsFile = $this->config->getGridFs()->findAndModify($gridFsFileQuery, $changed, null, - ['upsert' => true, 'new' => true]); + $changed['flowUpdated'] = new UTCDateTime(); + $this->uploadGridFsFile = $this->config->getGridFs()->getFilesCollection()->findOneAndReplace($gridFsFileQuery, $changed, + ['upsert' => true, 'returnDocument' => FindOneAndReplace::RETURN_DOCUMENT_AFTER]); } return $this->uploadGridFsFile; @@ -56,10 +61,10 @@ protected function getGridFsFile() */ public function chunkExists($index) { - return $this->config->getGridFs()->chunks->find([ + return $this->config->getGridFs()->getChunksCollection()->findOne([ 'files_id' => $this->getGridFsFile()['_id'], 'n' => (intval($index) - 1) - ])->limit(1)->hasNext(); + ]) !== null; } public function checkChunk() @@ -71,7 +76,7 @@ public function checkChunk() * Save chunk * @param $additionalUpdateOptions array additional options for the mongo update/upsert operation. * @return bool - * @throws \Exception if upload size is invalid or some other unexpected error occurred. + * @throws Exception if upload size is invalid or some other unexpected error occurred. */ public function saveChunk($additionalUpdateOptions = []) { @@ -89,19 +94,19 @@ public function saveChunk($additionalUpdateOptions = []) ($actualChunkSize < $this->request->getDefaultChunkSize() && $this->request->getCurrentChunkNumber() != $this->request->getTotalChunks()) ) { - throw new \Exception("Invalid upload! (size: {$actualChunkSize})"); + throw new Exception("Invalid upload! (size: $actualChunkSize)"); } - $chunk['data'] = new \MongoBinData($data, 0); // \MongoBinData::GENERIC is not defined for older mongo drivers - $this->config->getGridFs()->chunks->update($chunkQuery, $chunk, array_merge(['upsert' => true], $additionalUpdateOptions)); + $chunk['data'] = new Binary($data, Binary::TYPE_GENERIC); + $this->config->getGridFs()->getChunksCollection()->replaceOne($chunkQuery, $chunk, array_merge(['upsert' => true], $additionalUpdateOptions)); unlink($file['tmp_name']); $this->ensureIndices(); return true; - } catch (\Exception $e) { + } catch (Exception $e) { // try to remove a possibly (partly) stored chunk: if (isset($chunkQuery)) { - $this->config->getGridFs()->chunks->remove($chunkQuery); + $this->config->getGridFs()->getChunksCollection()->deleteMany($chunkQuery); } throw $e; } @@ -113,9 +118,8 @@ public function saveChunk($additionalUpdateOptions = []) public function validateFile() { $totalChunks = intval($this->request->getTotalChunks()); - $storedChunks = $this->config->getGridFs()->chunks - ->find(['files_id' => $this->getGridFsFile()['_id']]) - ->count(); + $storedChunks = $this->config->getGridFs()->getChunksCollection() + ->countDocuments(['files_id' => $this->getGridFsFile()['_id']]); return $totalChunks === $storedChunks; } @@ -123,15 +127,15 @@ public function validateFile() /** * Merge all chunks to single file * @param $metadata array additional metadata for final file - * @return \MongoId|bool of saved file or false if file was already saved - * @throws \Exception + * @return ObjectId|bool of saved file or false if file was already saved + * @throws Exception */ public function saveToGridFs($metadata = null) { $file = $this->getGridFsFile(); $file['flowStatus'] = 'finished'; $file['metadata'] = $metadata; - $result = $this->config->getGridFs()->findAndModify($this->getGridFsFileQuery(), $file); + $result = $this->config->getGridFs()->getFilesCollection()->findOneAndReplace($this->getGridFsFileQuery(), $file); // on second invocation no more file can be found, as the flowStatus changed: if (is_null($result)) { return false; @@ -142,7 +146,7 @@ public function saveToGridFs($metadata = null) public function save($destination) { - throw new \Exception("Must not use 'save' on MongoFile - use 'saveToGridFs'!"); + throw new Exception("Must not use 'save' on MongoFile - use 'saveToGridFs'!"); } public function deleteChunks() @@ -152,14 +156,10 @@ public function deleteChunks() public function ensureIndices() { - $chunksCollection = $this->config->getGridFs()->chunks; + $chunksCollection = $this->config->getGridFs()->getChunksCollection(); $indexKeys = ['files_id' => 1, 'n' => 1]; $indexOptions = ['unique' => true, 'background' => true]; - if(method_exists($chunksCollection, 'createIndex')) { // only available for PECL mongo >= 1.5.0 - $chunksCollection->createIndex($indexKeys, $indexOptions); - } else { - $chunksCollection->ensureIndex($indexKeys, $indexOptions); - } + $chunksCollection->createIndex($indexKeys, $indexOptions); } /** diff --git a/src/Flow/Mongo/MongoUploader.php b/src/Flow/Mongo/MongoUploader.php index 8a8d534..d0ca7f8 100644 --- a/src/Flow/Mongo/MongoUploader.php +++ b/src/Flow/Mongo/MongoUploader.php @@ -2,7 +2,7 @@ namespace Flow\Mongo; -use Flow\FileOpenException; +use MongoDB\GridFS\Bucket; /** * @codeCoverageIgnore @@ -12,20 +12,17 @@ class MongoUploader /** * Delete chunks older than expiration time. * - * @param \MongoGridFS $gridFs + * @param Bucket $gridFs * @param int $expirationTime seconds - * - * @throws FileOpenException */ public static function pruneChunks($gridFs, $expirationTime = 172800) { - $result = $gridFs->remove([ - 'flowUpdated' => ['$lt' => new \MongoDate(time() - $expirationTime)], + $result = $gridFs->find([ + 'flowUpdated' => ['$lt' => new \MongoDB\BSON\UTCDateTime(time() - $expirationTime)], 'flowStatus' => 'uploading' ]); - - if (!$result) { - throw new FileOpenException("Could not remove chunks!"); + foreach ($result as $file) { + $gridFs->delete($file['_id']); } } } diff --git a/src/Flow/Mongo/README.md b/src/Flow/Mongo/README.md index c74738d..35e2e9a 100644 --- a/src/Flow/Mongo/README.md +++ b/src/Flow/Mongo/README.md @@ -3,7 +3,7 @@ Usage * Must use 'forceChunkSize=true' on client side. * Chunk preprocessor not supported. - * One should ensure indices on the gridfs collection on the property 'flowIdentifier'. + * One should ensure indices on the gridfs files collection on the property 'flowIdentifier'. Besides the points above, the usage is analogous to the 'normal' flow-php: @@ -41,7 +41,7 @@ if ($file->validateFile()) { Delete unfinished files ----------------------- -For this you should setup cron, which would check each chunk upload time. +For this you should set up cron, which would check each chunk upload time. If chunk is uploaded long time ago, then chunk should be deleted. Helper method for checking this: