diff --git a/extensions/mongo/file/ActiveQuery.php b/extensions/mongo/file/ActiveQuery.php new file mode 100644 index 0000000..005e4ce --- /dev/null +++ b/extensions/mongo/file/ActiveQuery.php @@ -0,0 +1,91 @@ + + * @since 2.0 + */ +class ActiveQuery extends Query implements ActiveQueryInterface +{ + use ActiveQueryTrait; + + /** + * Executes query and returns all results as an array. + * @param \yii\mongo\Connection $db the Mongo connection used to execute the query. + * If null, the Mongo connection returned by [[modelClass]] will be used. + * @return array the query results. If the query results in nothing, an empty array will be returned. + */ + public function all($db = null) + { + $cursor = $this->buildCursor($db); + $rows = $this->fetchRows($cursor); + if (!empty($rows)) { + $models = $this->createModels($rows); + if (!empty($this->with)) { + $this->findWith($this->with, $models); + } + return $models; + } else { + return []; + } + } + + /** + * Executes query and returns a single row of result. + * @param \yii\mongo\Connection $db the Mongo connection used to execute the query. + * If null, the Mongo connection returned by [[modelClass]] will be used. + * @return ActiveRecord|array|null a single row of query result. Depending on the setting of [[asArray]], + * the query result may be either an array or an ActiveRecord object. Null will be returned + * if the query results in nothing. + */ + public function one($db = null) + { + $row = parent::one($db); + if ($row !== false) { + if ($this->asArray) { + $model = $row; + } else { + /** @var ActiveRecord $class */ + $class = $this->modelClass; + $model = $class::create($row); + } + if (!empty($this->with)) { + $models = [$model]; + $this->findWith($this->with, $models); + $model = $models[0]; + } + return $model; + } else { + return null; + } + } + + /** + * Returns the Mongo collection for this query. + * @param \yii\mongo\Connection $db Mongo connection. + * @return Collection collection instance. + */ + public function getCollection($db = null) + { + /** @var ActiveRecord $modelClass */ + $modelClass = $this->modelClass; + if ($db === null) { + $db = $modelClass::getDb(); + } + if ($this->from === null) { + $this->from = $modelClass::collectionName(); + } + return $db->getFileCollection($this->from); + } +} \ No newline at end of file diff --git a/extensions/mongo/file/ActiveRecord.php b/extensions/mongo/file/ActiveRecord.php new file mode 100644 index 0000000..b7f6f51 --- /dev/null +++ b/extensions/mongo/file/ActiveRecord.php @@ -0,0 +1,146 @@ + + * @since 2.0 + */ +class ActiveRecord extends \yii\mongo\ActiveRecord +{ + /** + * Creates an [[ActiveQuery]] instance. + * This method is called by [[find()]] to start a "find" command. + * You may override this method to return a customized query (e.g. `CustomerQuery` specified + * written for querying `Customer` purpose.) + * @return ActiveQuery the newly created [[ActiveQuery]] instance. + */ + public static function createQuery() + { + return new ActiveQuery(['modelClass' => get_called_class()]); + } + + /** + * Return the Mongo GridFS collection instance for this AR class. + * @return Collection collection instance. + */ + public static function getCollection() + { + return static::getDb()->getFileCollection(static::collectionName()); + } + + /** + * Creates an [[ActiveRelation]] instance. + * This method is called by [[hasOne()]] and [[hasMany()]] to create a relation instance. + * You may override this method to return a customized relation. + * @param array $config the configuration passed to the ActiveRelation class. + * @return ActiveRelation the newly created [[ActiveRelation]] instance. + */ + public static function createActiveRelation($config = []) + { + return new ActiveRelation($config); + } + + /** + * Returns the list of all attribute names of the model. + * This method could be overridden by child classes to define available attributes. + * Note: primary key attribute "_id" should be always present in returned array. + * @return array list of attribute names. + */ + public function attributes() + { + return ['id', 'file']; + } + + /** + * @see ActiveRecord::insert() + */ + protected function insertInternal($attributes = null) + { + if (!$this->beforeSave(true)) { + return false; + } + $values = $this->getDirtyAttributes($attributes); + if (empty($values)) { + $currentAttributes = $this->getAttributes(); + foreach ($this->primaryKey() as $key) { + $values[$key] = isset($currentAttributes[$key]) ? $currentAttributes[$key] : null; + } + } + $collection = static::getCollection(); + $newId = $collection->insert($values); + $this->setAttribute('_id', $newId); + foreach ($values as $name => $value) { + $this->setOldAttribute($name, $value); + } + $this->afterSave(true); + return true; + } + + /** + * @see CActiveRecord::update() + * @throws StaleObjectException + */ + protected function updateInternal($attributes = null) + { + if (!$this->beforeSave(false)) { + return false; + } + $values = $this->getDirtyAttributes($attributes); + if (empty($values)) { + $this->afterSave(false); + return 0; + } + $condition = $this->getOldPrimaryKey(true); + $lock = $this->optimisticLock(); + if ($lock !== null) { + if (!isset($values[$lock])) { + $values[$lock] = $this->$lock + 1; + } + $condition[$lock] = $this->$lock; + } + // We do not check the return value of update() because it's possible + // that it doesn't change anything and thus returns 0. + $rows = static::getCollection()->update($condition, $values); + + if ($lock !== null && !$rows) { + throw new StaleObjectException('The object being updated is outdated.'); + } + + foreach ($values as $name => $value) { + $this->setOldAttribute($name, $this->getAttribute($name)); + } + $this->afterSave(false); + return $rows; + } + + public function getContent() + { + $file = $this->getAttribute('file'); + if (empty($file)) { + return null; + } + if ($file instanceof \MongoGridFSFile) { + return $file->getBytes(); + } + } + + public function getFileName() + { + $file = $this->getAttribute('file'); + if (empty($file)) { + return null; + } + if ($file instanceof \MongoGridFSFile) { + return $file->getFilename(); + } + } + +} \ No newline at end of file diff --git a/extensions/mongo/file/ActiveRelation.php b/extensions/mongo/file/ActiveRelation.php new file mode 100644 index 0000000..6ea0831 --- /dev/null +++ b/extensions/mongo/file/ActiveRelation.php @@ -0,0 +1,22 @@ + + * @since 2.0 + */ +class ActiveRelation extends ActiveQuery implements ActiveRelationInterface +{ + use ActiveRelationTrait; +} \ No newline at end of file diff --git a/extensions/mongo/file/Query.php b/extensions/mongo/file/Query.php new file mode 100644 index 0000000..6cf2215 --- /dev/null +++ b/extensions/mongo/file/Query.php @@ -0,0 +1,32 @@ + + * @since 2.0 + */ +class Query extends \yii\mongo\Query +{ + /** + * Returns the Mongo collection for this query. + * @param \yii\mongo\Connection $db Mongo connection. + * @return Collection collection instance. + */ + public function getCollection($db = null) + { + if ($db === null) { + $db = Yii::$app->getComponent('mongo'); + } + return $db->getFileCollection($this->from); + } +} \ No newline at end of file diff --git a/tests/unit/extensions/mongo/MongoTestCase.php b/tests/unit/extensions/mongo/MongoTestCase.php index a14e27b..eefb972 100644 --- a/tests/unit/extensions/mongo/MongoTestCase.php +++ b/tests/unit/extensions/mongo/MongoTestCase.php @@ -108,7 +108,7 @@ class MongoTestCase extends TestCase * Drops the specified file collection. * @param string $name file collection name. */ - protected function dropFileCollection($name) + protected function dropFileCollection($name = 'fs') { if ($this->mongo) { try { diff --git a/tests/unit/extensions/mongo/file/CollectionTest.php b/tests/unit/extensions/mongo/file/CollectionTest.php index bed7ab9..a0aaa3e 100644 --- a/tests/unit/extensions/mongo/file/CollectionTest.php +++ b/tests/unit/extensions/mongo/file/CollectionTest.php @@ -4,6 +4,9 @@ namespace yiiunit\extensions\mongo\file; use yiiunit\extensions\mongo\MongoTestCase; +/** + * @group mongo + */ class CollectionTest extends MongoTestCase { protected function tearDown() diff --git a/tests/unit/extensions/mongo/file/QueryTest.php b/tests/unit/extensions/mongo/file/QueryTest.php new file mode 100644 index 0000000..cbba53c --- /dev/null +++ b/tests/unit/extensions/mongo/file/QueryTest.php @@ -0,0 +1,53 @@ +setUpTestRows(); + } + + protected function tearDown() + { + $this->dropFileCollection(); + parent::tearDown(); + } + + /** + * Sets up test rows. + */ + protected function setUpTestRows() + { + $collection = $this->getConnection()->getFileCollection(); + for ($i = 1; $i <= 10; $i++) { + $collection->storeBytes('content' . $i, ['filename' => 'name' . $i]); + } + } + + // Tests : + + public function testAll() + { + $connection = $this->getConnection(); + $query = new Query; + $rows = $query->from('fs')->all($connection); + $this->assertEquals(10, count($rows)); + } + + public function testOne() + { + $connection = $this->getConnection(); + $query = new Query; + $row = $query->from('fs')->one($connection); + $this->assertTrue($row instanceof \MongoGridFSFile); + } +} \ No newline at end of file