diff --git a/extensions/mongo/Command.php b/extensions/mongo/Command.php index fcaf591..7a21177 100644 --- a/extensions/mongo/Command.php +++ b/extensions/mongo/Command.php @@ -8,6 +8,7 @@ namespace yii\mongo; use \yii\base\Component; +use Yii; /** * Class Command @@ -23,10 +24,136 @@ class Command extends Component public $db; /** - * Drop the current database + * Drops the current database */ public function dropDb() { $this->db->db->drop(); } + + /** + * Drops the specified collection. + * @param string $name collection name. + */ + public function dropCollection($name) + { + $collection = $this->db->getCollection($name); + $collection->drop(); + } + + /** + * @param $collection + * @param array $query + * @param array $fields + * @return \MongoCursor + */ + public function find($collection, $query = [], $fields = []) + { + $collection = $this->db->getCollection($collection); + return $collection->find($query, $fields); + } + + /** + * @param $collection + * @param array $query + * @param array $fields + * @return array + */ + public function findAll($collection, $query = [], $fields = []) + { + $cursor = $this->find($collection, $query, $fields); + $result = []; + foreach ($cursor as $data) { + $result[] = $data; + } + return $result; + } + + /** + * Inserts new data into collection. + * @param string $collection name of the collection. + * @param array|object $data data to be inserted. + * @param array $options list of options in format: optionName => optionValue. + * @return \MongoId new record id instance. + * @throws Exception on failure. + */ + public function insert($collection, $data, $options = []) + { + $token = 'Inserting data into ' . $collection; + Yii::info($token, __METHOD__); + try { + Yii::beginProfile($token, __METHOD__); + $collection = $this->db->getCollection($collection); + $this->tryResultError($collection->insert($data, $options)); + Yii::endProfile($token, __METHOD__); + return is_array($data) ? $data['_id'] : $data->_id; + } catch (\Exception $e) { + Yii::endProfile($token, __METHOD__); + throw new Exception($e->getMessage(), (int)$e->getCode(), $e); + } + } + + /** + * Update the existing database data, otherwise insert this data + * @param string $collection name of the collection. + * @param array|object $data data to be updated/inserted. + * @param array $options list of options in format: optionName => optionValue. + * @return \MongoId updated/new record id instance. + * @throws Exception on failure. + */ + public function save($collection, $data, $options = []) + { + $token = 'Saving data into ' . $collection; + Yii::info($token, __METHOD__); + try { + Yii::beginProfile($token, __METHOD__); + $collection = $this->db->getCollection($collection); + $this->tryResultError($collection->save($data, $options)); + Yii::endProfile($token, __METHOD__); + return is_array($data) ? $data['_id'] : $data->_id; + } catch (\Exception $e) { + Yii::endProfile($token, __METHOD__); + throw new Exception($e->getMessage(), (int)$e->getCode(), $e); + } + } + + /** + * Removes data from the collection. + * @param string $collection name of the collection. + * @param array $criteria description of records to remove. + * @param array $options list of options in format: optionName => optionValue. + * @return boolean whether operation was successful. + * @throws Exception on failure. + */ + public function remove($collection, $criteria = [], $options = []) + { + $token = 'Removing data from ' . $collection; + Yii::info($token, __METHOD__); + try { + Yii::beginProfile($token, __METHOD__); + $collection = $this->db->getCollection($collection); + $this->tryResultError($collection->remove($criteria, $options)); + Yii::endProfile($token, __METHOD__); + return true; + } catch (\Exception $e) { + Yii::endProfile($token, __METHOD__); + throw new Exception($e->getMessage(), (int)$e->getCode(), $e); + } + } + + /** + * Checks if command execution result ended with an error. + * @param mixed $result raw command execution result. + * @throws Exception if an error occurred. + */ + protected function tryResultError($result) + { + if (is_array($result)) { + if (!empty($result['err'])) { + throw new Exception($result['errmsg'], (int)$result['code']); + } + } elseif (!$result) { + throw new Exception('Unknown error, use "w=1" option to enable error tracking'); + } + } } \ No newline at end of file diff --git a/extensions/mongo/Connection.php b/extensions/mongo/Connection.php index 2566f07..8158b15 100644 --- a/extensions/mongo/Connection.php +++ b/extensions/mongo/Connection.php @@ -9,7 +9,6 @@ namespace yii\mongo; use yii\base\Component; use yii\base\InvalidConfigException; -use yii\db\Exception; use Yii; /** @@ -102,12 +101,13 @@ class Connection extends Component Yii::beginProfile($token, __METHOD__); $options = $this->options; $options['connect'] = true; + $options['db'] = $this->dbName; $this->client = new \MongoClient($this->dsn, $options); $this->db = $this->client->selectDB($this->dbName); Yii::endProfile($token, __METHOD__); } catch (\Exception $e) { Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), [], (int)$e->getCode(), $e); + throw new Exception($e->getMessage(), (int)$e->getCode(), $e); } } } diff --git a/extensions/mongo/Exception.php b/extensions/mongo/Exception.php new file mode 100644 index 0000000..0687e48 --- /dev/null +++ b/extensions/mongo/Exception.php @@ -0,0 +1,25 @@ + + * @since 2.0 + */ +class Exception extends \yii\base\Exception +{ + /** + * @return string the user-friendly name of this exception + */ + public function getName() + { + return \Yii::t('yii', 'Mongo Exception'); + } +} \ No newline at end of file diff --git a/tests/unit/extensions/mongo/CommandTest.php b/tests/unit/extensions/mongo/CommandTest.php new file mode 100644 index 0000000..c9621d1 --- /dev/null +++ b/tests/unit/extensions/mongo/CommandTest.php @@ -0,0 +1,96 @@ +dropCollection('customer'); + parent::tearDown(); + } + + // Tests : + + public function testInsert() + { + $command = $this->getConnection()->createCommand(); + $data = [ + 'name' => 'customer 1', + 'address' => 'customer 1 address', + ]; + $id = $command->insert('customer', $data); + $this->assertTrue($id instanceof \MongoId); + $this->assertNotEmpty($id->__toString()); + } + + /** + * @depends testInsert + */ + public function testFindAll() + { + $command = $this->getConnection()->createCommand(); + $data = [ + 'name' => 'customer 1', + 'address' => 'customer 1 address', + ]; + $id = $command->insert('customer', $data); + + $rows = $command->findAll('customer'); + $this->assertEquals(1, count($rows)); + $this->assertEquals($id, $rows[0]['_id']); + } + + public function testSave() + { + $command = $this->getConnection()->createCommand(); + $data = [ + 'name' => 'customer 1', + 'address' => 'customer 1 address', + ]; + $id = $command->save('customer', $data); + $this->assertTrue($id instanceof \MongoId); + $this->assertNotEmpty($id->__toString()); + } + + /** + * @depends testSave + */ + public function testUpdate() + { + $command = $this->getConnection()->createCommand(); + $data = [ + 'name' => 'customer 1', + 'address' => 'customer 1 address', + ]; + $newId = $command->save('customer', $data); + + $updatedId = $command->save('customer', $data); + $this->assertEquals($newId, $updatedId, 'Unable to update data!'); + + $data['_id'] = $newId->__toString(); + $updatedId = $command->save('customer', $data); + $this->assertEquals($newId, $updatedId, 'Unable to updated data by string id!'); + } + + /** + * @depends testFindAll + */ + public function testRemove() + { + $command = $this->getConnection()->createCommand(); + $data = [ + 'name' => 'customer 1', + 'address' => 'customer 1 address', + ]; + $id = $command->insert('customer', $data); + + $command->remove('customer', ['_id' => $id]); + + $rows = $command->findAll('customer'); + $this->assertEquals(0, count($rows)); + } +} \ No newline at end of file diff --git a/tests/unit/extensions/mongo/ConnectionTest.php b/tests/unit/extensions/mongo/ConnectionTest.php index 11d2d0f..175a665 100644 --- a/tests/unit/extensions/mongo/ConnectionTest.php +++ b/tests/unit/extensions/mongo/ConnectionTest.php @@ -2,9 +2,11 @@ namespace yiiunit\extensions\mongo; - use yii\mongo\Connection; +/** + * @group mongo + */ class ConnectionTest extends MongoTestCase { public function testConstruct() @@ -38,7 +40,7 @@ class ConnectionTest extends MongoTestCase $connection = new Connection; $connection->dsn = 'unknown::memory:'; - $this->setExpectedException('yii\db\Exception'); + $this->setExpectedException('yii\mongo\Exception'); $connection->open(); } diff --git a/tests/unit/extensions/mongo/MongoTestCase.php b/tests/unit/extensions/mongo/MongoTestCase.php index 1b11bd1..a4f20ac 100644 --- a/tests/unit/extensions/mongo/MongoTestCase.php +++ b/tests/unit/extensions/mongo/MongoTestCase.php @@ -88,4 +88,15 @@ class MongoTestCase extends TestCase $this->mongo = $db; return $db; } + + /** + * Drops the specified collection. + * @param string $name collection name. + */ + protected function dropCollection($name) + { + if ($this->mongo) { + $this->mongo->getCollection($name)->drop(); + } + } } \ No newline at end of file