diff --git a/model/Db.php b/model/Db.php index 0eec589..933b011 100644 --- a/model/Db.php +++ b/model/Db.php @@ -31,6 +31,7 @@ class Db * @param array $config Configuration array. * * @return DbDriver + * @throws InitializationException */ static public function connect($name = 'default', $config = null) { diff --git a/model/DbStatement.php b/model/DbStatement.php index 26caba2..9ee5feb 100644 --- a/model/DbStatement.php +++ b/model/DbStatement.php @@ -66,6 +66,7 @@ abstract class DbStatement /** * @param string $field + * @return array Value of queried field for all matching rows */ public function fetchColumn($field) { @@ -78,6 +79,7 @@ abstract class DbStatement /** * @param string $field + * @return mixed Value of queried filed for first matching row */ public function fetchField($field) { @@ -108,6 +110,7 @@ abstract class DbStatement abstract public function numRows(); /** + * @param mixed $request * @return bool */ abstract protected function driverExecute($request); diff --git a/model/Model.php b/model/Model.php index fd4fd01..7af41aa 100644 --- a/model/Model.php +++ b/model/Model.php @@ -63,7 +63,6 @@ abstract class Model /** * @param array $data - * @param array $on_duplicate * @return int Id of inserted row */ public function insert($data) @@ -152,22 +151,22 @@ abstract class Model abstract public function delete($id); /** - * @param string $sql - * @param array $params - * @param string $field - * @param CacheKey $cache_key + * @param string $data Request + * @param array $params Request parameters + * @param string $field Requested field name + * @param CacheKey $cache_key Key for caching in */ abstract protected function fetchField($data, $params = array(), $field, $cache_key = null); /** - * @param string $sql - * @param array $params - * @param CacheKey $cache_key + * @param string $data Request + * @param array $params Request parameters + * @param CacheKey $cache_key Key for caching in */ abstract protected function fetch($data, $params = array(), $cache_key = null); /** - * @param string $sql + * @param string $data * @param array $params * @param CacheKey $cache_key */ diff --git a/model/MongoDbCommand.php b/model/MongoDbCommand.php index 319ac84..18bc7ee 100644 --- a/model/MongoDbCommand.php +++ b/model/MongoDbCommand.php @@ -22,6 +22,12 @@ class MongoCommandBuilder const COMMAND = 'Command'; + + /** + * @param string $type + * @param MongoCollection $collection + * @return MongoDbCommand + */ static public function factory($type, $collection = null) { $class = ucfirst($type) . 'MongoCommand'; @@ -33,8 +39,18 @@ class MongoCommandBuilder abstract class MongoDbCommand { + + /** + * @var MongoCollection + */ protected $collection; + /** + * Execute Mongo command/query + * + * @return mixed + * @throws GeneralException + */ public function execute() { if ($this->checkParams()) { @@ -44,6 +60,12 @@ abstract class MongoDbCommand } } + + /** + * @param string $name Parameter name + * @param mixed $value Parameter value + * @return MongoDbCommand + */ public function bindParam($name, $value) { if (property_exists($this, $name)) { @@ -52,12 +74,22 @@ abstract class MongoDbCommand return $this; } + /** + * @param MongoCollection $collection Mongo collection + * @return MongoDbCommand + */ public function setCollection($collection) { $this->collection = $collection; return $this; } + /** + * Convert query parameters array to string + * + * @param array $array + * @return string + */ protected function arrayToString($array) { $string = '['; diff --git a/model/MongoDriver.php b/model/MongoDriver.php index 455b0a4..5af2a51 100644 --- a/model/MongoDriver.php +++ b/model/MongoDriver.php @@ -38,6 +38,12 @@ class MongoDriver extends NoSqlDbDriver return $this->query($command, $params)->affectedRows(); } + /** + * @param string $collection Mongo collection name to search in + * @param array $condition Search conditions + * @param array $fields Fields to return in result set + * @return MongoStatement + */ public function find($collection, $condition = array(), $fields = array()) { $command = MongoCommandBuilder::factory(MongoCommandBuilder::FIND, $this->getCollection($collection)); @@ -49,17 +55,6 @@ class MongoDriver extends NoSqlDbDriver return $this->query($command, $params); } - public function get($collection, $condition, $fields = array()) - { - $command = MongoCommandBuilder::factory(MongoCommandBuilder::FIND, $this->getCollection($collection)); - $params = array( - 'condition' => $condition, - 'fields' => $fields, - 'multiple' => false - ); - return $this->query($command, $params); - } - public function findAndModify($collection, $query, $update, $sort = array(), $field = array(), $upsert = false, $new = false, $remove = false) { $command = MongoCommandBuilder::factory(MongoCommandBuilder::COMMAND, $this->getCollection($collection)); @@ -123,10 +118,9 @@ class MongoDriver extends NoSqlDbDriver } - /** * @param mixed $request - * @return DbStatement + * @return MongoStatement */ public function prepare($request) { diff --git a/model/MongoModel.php b/model/MongoModel.php index 6bf7093..9a5c672 100644 --- a/model/MongoModel.php +++ b/model/MongoModel.php @@ -10,9 +10,20 @@ * @since 2011-11-15 */ +/** + * @property MongoDriver $db + */ abstract class MongoModel extends Model { + /** + * @var string Mongo id field to use as key + */ + protected $key = '_id'; + + /** + * @var bool Is Mongo key field uses original MongoId + */ protected $useMongoId = true; public function __construct($connection = 'default') @@ -20,16 +31,11 @@ abstract class MongoModel extends Model parent::__construct($connection); } - public function count($query = array(), $limit = 0, $skip = 0) + protected function count($query = array(), $limit = 0, $skip = 0) { return $this->db->count($this->table(), $query, $limit, $skip); } - public function find($condition = array(), $fields = array()) - { - return $this->db->find($this->table(), $condition, $fields); - } - public function get($id) { if ($this->useMongoId) { @@ -37,7 +43,7 @@ abstract class MongoModel extends Model $id = new MongoId($id); } } - return $this->db->get($this->table(), array('_id' => $id))->fetch(); + return $this->fetch(array($this->key => $id)); } public function batchInsert($data) @@ -45,25 +51,42 @@ abstract class MongoModel extends Model return $this->db->insert($this->table(), $data, true); } - public function delete($id) + public function update($data, $where) { if ($this->useMongoId) { - if (!$id instanceof MongoId) { - $id = new MongoId($id); + if (!$where instanceof MongoId) { + $where = new MongoId($where); } } - return $this->db->delete($this->table(), array('_id' => $id)); + return $this->db->update($this->table(), $data, array($this->key => $where)); } - public function deleteAll($query = array()) + public function delete($id) { - $this->db->delete($this->table(), $query); + if ($this->useMongoId) { + if (!$id instanceof MongoId) { + $id = new MongoId($id); + } + } + return $this->db->delete($this->table(), array($this->key => $id)); } + /** + * @param array $data Request + * @param array $params Request parameters + * @param string $field Requested field name + * @param CacheKey $cache_key Key for caching in + * @return mixed + */ protected function fetchField($data, $params = array(), $field, $cache_key = null) { if (!$cache_key || !$result = $cache_key->get()) { - $result = $this->db->find($this->table(), $data, array($field => 1))->fetchField($field); + $result = $this->db + ->find($this->table(), $data, array($field => 1)) + ->limit($this->getLimit($params)) + ->skip($this->getSkip($params)) + ->order($this->getOrder($params)) + ->fetchField($field); if ($cache_key) { $cache_key->set($result); } @@ -71,10 +94,21 @@ abstract class MongoModel extends Model return $result; } + /** + * @param array $data Request + * @param array $params Request parameters + * @param CacheKey $cache_key Key for caching in + * @return mixed + */ protected function fetch($data, $params = array(), $cache_key = null) { if (!$cache_key || !$result = $cache_key->get()) { - $result = $this->db->find($this->table(), $data)->fetch(); + $result = $this->db + ->find($this->table(), $data, $this->getFields($params)) + ->limit(1) + ->skip($this->getSkip($params)) + ->order($this->getOrder($params)) + ->fetch(); if ($cache_key) { $cache_key->set($result); } @@ -82,14 +116,105 @@ abstract class MongoModel extends Model return $result; } + /** + * @param array $data + * @param array $params + * @param CacheKey $cache_key + * @return array + */ protected function fetchAll($data, $params = array(), $cache_key = null) { if (!$cache_key || !$result = $cache_key->get()) { - $result = $this->db->find($this->table(), $data)->fetchAll(); + $result = $this->db + ->find($this->table(), $data, $this->getFields($params)) + ->limit($this->getLimit($params)) + ->skip($this->getSkip($params)) + ->order($this->getOrder($params)) + ->fetchAll(); if ($cache_key) { $cache_key->set($result); } } return $result; } + + /** + * @param array $params Parameters for find query + * @return int Query result limits rule + * */ + private function getLimit($params = array()) + { + return isset($params['limit']) ? (int) $params['limit'] : 0; + } + + /** + * @param array $params Parameters for find query + * @return int Query result skip rule + * */ + private function getSkip($params = array()) + { + return isset($params['skip']) ? (int) $params['skip'] : 0; + } + + /** + * @param array $params Parameters for find query + * @return array Query result sort rules + * @throws GeneralException + * */ + private function getOrder($params = array()) + { + $order = array(); + if (isset($params['order'])) { + if (is_string($params['order'])) { + $order = array($params['order'] => 1); + } elseif (is_array($params['order'])) { + $order = $params['order']; + } else { + throw new GeneralException('Wrong order parameter given to query.'); + } + } + return $order; + } + + /** + * @param array $params Parameters for find query + * @return array Query result sort rules + * @throws GeneralException + * */ + private function getFields($params) + { + $fields = array(); + if (isset($params['fields'])) { + if (is_string($params['fields'])) { + $fields = array($params['fields'] => 1); + } elseif (is_array($params['fields'])) { + if (array_keys($params['fields']) === range(0, count($params['fields']) - 1)) { + foreach ($params['fields'] as $filed) { + $fields[$filed] = 1; + } + } else { + $fields = $params['fields']; + } + } else { + throw new GeneralException('Wrong fields parameter given to query.'); + } + } + return $fields; + } + + /** + * Sets the additional condition if it is set + * + * @param array $query Initial query + * @param string $filed Field name to set + * @param mixed $value Field value to set + * @return MongoModel Current model object + */ + protected function addCondition(&$query, $filed, $value) + { + if(!is_null($value) && $value !== false) { + $query[$filed] = $value; + } + return $this; + } } \ No newline at end of file diff --git a/model/MongoStatement.php b/model/MongoStatement.php index 49f4c53..221e49c 100644 --- a/model/MongoStatement.php +++ b/model/MongoStatement.php @@ -114,7 +114,7 @@ class MongoStatement extends DbStatement } else { return false; } - } elseif (is_int($this->result)) { + } elseif (is_int($this->result) || $this->result instanceof MongoId) { return $this->result; } return false; @@ -156,6 +156,9 @@ class MongoStatement extends DbStatement if (is_array($result) && isset($result['values'])) { $this->result = $result['values']; } + if (is_array($result) && isset($result['upserted'])) { + $this->result = $result['n'] > 1 ? $result['n'] : $result['upserted']; + } } elseif (is_int($result)) { $this->result = $result; } diff --git a/model/MySQLiDriver.php b/model/MySQLiDriver.php index 76b060a..179815e 100644 --- a/model/MySQLiDriver.php +++ b/model/MySQLiDriver.php @@ -14,7 +14,7 @@ */ class MySQLiDriver extends SqlDbDriver { - + public function insert($table, $bind, $on_duplicate = array()) { $columns = array(); @@ -22,7 +22,7 @@ class MySQLiDriver extends SqlDbDriver $columns[] = $this->quoteIdentifier($col); } $values = array_values($bind); - + if ($on_duplicate) { $update = array(); foreach ($on_duplicate as $col => $val) { @@ -30,16 +30,16 @@ class MySQLiDriver extends SqlDbDriver } $on_duplicate = ' ON DUPLICATE KEY UPDATE ' . implode(', ', $update); } - + $sql = 'INSERT INTO ' . $this->quoteIdentifier($table) - . ' (' . implode(', ', $columns) . ') VALUES (' . $this->quote($values) . ')' - . (($on_duplicate) ? $on_duplicate : ''); + . ' (' . implode(', ', $columns) . ') VALUES (' . $this->quote($values) . ')' + . (($on_duplicate) ? $on_duplicate : ''); return $this->query($sql)->affectedRows(); } - + /** * @param mixed $sql - * @return DbStatement + * @return MySQLiStatement */ public function prepare($sql) { @@ -50,73 +50,73 @@ class MySQLiDriver extends SqlDbDriver { return $this->connection->insert_id; } - + public function isConnected() { return ($this->connection instanceof MySQLi); } - + public function disconnect() { if ($this->isConnected()) { $this->connection->close(); } - $this->connection = null; + $this->connection = null; } - + protected function connect() { if ($this->connection) { return; } - + $port = isset($this->config['port']) ? (int) $this->config['port'] : null; $this->connection = mysqli_init(); - $connected = @mysqli_real_connect($this->connection, - $this->config['hostname'], - $this->config['username'], - $this->config['password'], - $this->config['database'], - $port); + @mysqli_real_connect($this->connection, + $this->config['hostname'], + $this->config['username'], + $this->config['password'], + $this->config['database'], + $port); // Connection errors check if (mysqli_connect_error()) { throw new GeneralException(mysqli_connect_error(), mysqli_connect_errno()); } - + $charset = (!empty($this->config['charset'])) ? $this->config['charset'] : 'utf8'; $this->connection->set_charset($charset); } - + protected function driverQuote($value) { if (is_int($value) || is_float($value)) { return $value; } - + if (is_bool($value)) { return (int) $value; } - + if ($value === null) { return 'NULL'; } - + $this->connect(); return '\'' . $this->connection->real_escape_string($value) . '\''; } - + protected function driverBeginTransaction() { $this->connect(); $this->connection->autocommit(false); } - + protected function driverCommitTransaction() { $this->connection->commit(); $this->connection->autocommit(true); } - + protected function driverRollbackTransaction() { $this->connection->rollback(); diff --git a/model/MySQLiStatement.php b/model/MySQLiStatement.php index a89adb4..5700d80 100644 --- a/model/MySQLiStatement.php +++ b/model/MySQLiStatement.php @@ -83,6 +83,7 @@ class MySQLiStatement extends DbStatement * * @param mixed $style * @return mixed + * @throws GeneralException */ public function fetch($style = Db::FETCH_OBJ) { @@ -90,7 +91,6 @@ class MySQLiStatement extends DbStatement return false; } - $row = false; switch ($style) { case Db::FETCH_OBJ: $row = $this->result->fetch_object(); @@ -112,6 +112,7 @@ class MySQLiStatement extends DbStatement /** * @param string $class + * @return object */ public function fetchObject($class = 'stdClass') { diff --git a/model/SqlDbDriver.php b/model/SqlDbDriver.php index fa86668..ec62c49 100644 --- a/model/SqlDbDriver.php +++ b/model/SqlDbDriver.php @@ -37,7 +37,7 @@ abstract class SqlDbDriver extends DbDriver /** * @param string $table - * @param mixed $bind + * @param mixed $data * @param mixed $on_duplicate * @return int Affected rows count */ @@ -56,9 +56,9 @@ abstract class SqlDbDriver extends DbDriver /** * @param string $table - * @param array $bind - * @param mixed $where - * @return int + * @param array $data + * @param mixed $condition + * @return int Number of updated rows */ public function update($table, $data, $condition = '') { @@ -74,7 +74,7 @@ abstract class SqlDbDriver extends DbDriver /** * @param string $table - * @param mixed $where + * @param mixed $condition * @return int */ public function delete($table, $condition = '') @@ -152,10 +152,6 @@ abstract class SqlDbDriver extends DbDriver return implode(' AND ', $where); } - /** - * @return DbStatement - */ - abstract protected function driverQuote($value); abstract protected function driverBeginTransaction(); diff --git a/model/SqlModel.php b/model/SqlModel.php index 7724232..7eb98ae 100644 --- a/model/SqlModel.php +++ b/model/SqlModel.php @@ -10,6 +10,9 @@ * @since 2011-11-11 */ +/** + * @property SqlDbDriver $db + */ abstract class SqlModel extends Model { @@ -105,8 +108,10 @@ abstract class SqlModel extends Model /** * This method appends to params table and primary key. - * So they can be accessed thru `:table` and `:pk` placeholders. + * So they can be accessed through `:table` and `:pk` placeholders. * + * @param string $sql + * @param array $params * @return DbStatement */ protected function query($sql, $params = array()) @@ -122,10 +127,11 @@ abstract class SqlModel extends Model } /** - * @param string $sql - * @param array $params - * @param string $field - * @param CacheKey $cache_key + * @param string $data Request + * @param array $params Request parameters + * @param string $field Requested field name + * @param CacheKey $cache_key Key for caching in + * @return mixed */ protected function fetchField($data, $params = array(), $field, $cache_key = null) { @@ -139,9 +145,10 @@ abstract class SqlModel extends Model } /** - * @param string $sql - * @param array $params - * @param CacheKey $cache_key + * @param string $data Request + * @param array $params Request parameters + * @param CacheKey $cache_key Key for caching in + * @return mixed */ protected function fetch($data, $params = array(), $cache_key = null) { @@ -155,9 +162,10 @@ abstract class SqlModel extends Model } /** - * @param string $sql + * @param string $data * @param array $params * @param CacheKey $cache_key + * @return array */ protected function fetchAll($data, $params = array(), $cache_key = null) { diff --git a/tests/model/MongoDbCommandTest.php b/tests/model/MongoDbCommandTest.php index a6f2339..f8e5d0c 100644 --- a/tests/model/MongoDbCommandTest.php +++ b/tests/model/MongoDbCommandTest.php @@ -16,7 +16,7 @@ require_once dirname(__FILE__) . '/../../model/MongoDriver.php'; require_once dirname(__FILE__) . '/../../model/MongoDbCommand.php'; require_once dirname(__FILE__) . '/../../exception/GeneralException.php'; -class MongoDbCommandTest extends PHPUnit_Framework_TestCase +class MongoDbCommandTest extends PHPUnit_Framework_TestCase { private $conf = array(); @@ -323,11 +323,14 @@ class MongoDbCommandTest extends PHPUnit_Framework_TestCase */ public function testToString() { - $cmd = MongoCommandBuilder::factory(MongoCommandBuilder::COUNT, new CollectionMock()); - $cmd->bindParam('condition', array()); + $cmd = MongoCommandBuilder::factory(MongoCommandBuilder::COUNT); + $this->assertSame('Command properties not set', $cmd->__toString()); + $cmd->bindParam('collection', new CollectionMock()); $this->assertStringStartsWith("\n" . 'Collection: CollectionMock', $cmd->__toString()); - $cmd = MongoCommandBuilder::factory(MongoCommandBuilder::FIND, new CollectionMock()); + $cmd = MongoCommandBuilder::factory(MongoCommandBuilder::FIND); + $this->assertSame('Command properties not set', $cmd->__toString()); + $cmd->bindParam('collection', new CollectionMock()); $cmd->bindParam('condition', array()); $this->assertStringStartsWith("\n" . 'Collection: CollectionMock', $cmd->__toString()); $this->assertContains('Condition: ' . '[]' . PHP_EOL, $cmd->__toString()); diff --git a/tests/model/MongoDriverTest.php b/tests/model/MongoDriverTest.php index 63cfd1e..5a5352e 100644 --- a/tests/model/MongoDriverTest.php +++ b/tests/model/MongoDriverTest.php @@ -204,22 +204,6 @@ class MongoDriverTest extends PHPUnit_Framework_TestCase * @runInSeparateProcess * @group Mongo */ - public function testGet() - { - Config::set('DEBUG', false); - - $mongo = new MongoDriver($this->conf); - $eggs = $mongo->get('items', array('name' => 'eggs'))->fetchObject(); - $this->assertEquals(20, $eggs->quantity); - $eggs = $mongo->get('items', array('name' => 'eggs'))->fetch(); - $this->assertEquals('eggs', $eggs->name); - $this->assertInstanceOf('MongoId', $eggs->_id); - } - - /** - * @runInSeparateProcess - * @group Mongo - */ public function testRemove() { Config::set('DEBUG', false); @@ -246,7 +230,7 @@ class MongoDriverTest extends PHPUnit_Framework_TestCase $this->assertNotEmpty($mongo->getInsertId()); $this->assertEquals(2, $mongo->find('items', array('name' => 'bread'))->numRows()); $this->assertEquals(0, $mongo->insert('items', array('name' => 'meat', 'weight' => 230))); - $this->assertEquals(230, $mongo->get('items', array('name' => 'meat'))->fetch()->weight); + $this->assertEquals(230, $mongo->find('items', array('name' => 'meat'))->fetch()->weight); } /** @@ -304,7 +288,7 @@ class MongoDriverTest extends PHPUnit_Framework_TestCase $this->assertEquals(1, $mongo->find('items', array('name' => 'bread'))->numRows()); $this->assertEquals(1, $mongo->update('items', array('$set' => array('price' => 200, 'date' => 'today')), array('name' => 'fish'))); $this->assertEquals(2, $mongo->update('items', array('$set' => array('price' => 1)), array('name' => 'eggs'))); - $fish = $mongo->get('items', array('name' => 'fish'))->fetch(); + $fish = $mongo->find('items', array('name' => 'fish'))->fetch(); $this->assertEquals(200, $fish->price); $this->assertEquals('today', $fish->date); $this->assertEquals(0, $mongo->update('items', array('$set' => array('price' => 200, 'date' => 'today')), array('name' => 'ball'))); @@ -321,8 +305,9 @@ class MongoDriverTest extends PHPUnit_Framework_TestCase $mongo = new MongoDriver($this->conf); $mongo->insert('items', array('name' => 'bread')); - $this->assertEquals(1, $mongo->update('items', array('$set' => array('price' => 200, 'date' => 'today')), array('name' => 'ball'), true, true)); - $this->assertEquals('today', $mongo->get('items', array('name' => 'ball'))->fetch()->date); + $this->assertInstanceOf('MongoId', $mongo->update('items', array('$set' => array('price' => 200, 'date' => 'today')), array('name' => 'ball'), true, true)); + $this->assertEquals('today', $mongo->find('items', array('name' => 'ball'))->fetch()->date); + $this->assertEquals(2, $mongo->update('items', array('$set' => array('price' => 200, 'date' => 'today')), array('name' => 'eggs'), true, true)); } /** @@ -335,10 +320,10 @@ class MongoDriverTest extends PHPUnit_Framework_TestCase $mongo = new MongoDriver($this->conf); - $this->assertEquals(10, $mongo->get('items', array('name' => 'bread'))->fetch()->quantity); + $this->assertEquals(10, $mongo->find('items', array('name' => 'bread'))->fetch()->quantity); $result = $mongo->findAndModify('items', array('name' => 'bread'), array('$set' => array('quantity' => 20))); $this->assertEquals(10, $result->fetch()->quantity); - $this->assertEquals(20, $mongo->get('items', array('name' => 'bread'))->fetch()->quantity); + $this->assertEquals(20, $mongo->find('items', array('name' => 'bread'))->fetch()->quantity); } /** @@ -351,10 +336,10 @@ class MongoDriverTest extends PHPUnit_Framework_TestCase $mongo = new MongoDriver($this->conf); - $this->assertEquals(10, $mongo->get('items', array('name' => 'bread'))->fetch()->quantity); + $this->assertEquals(10, $mongo->find('items', array('name' => 'bread'))->fetch()->quantity); $result = $mongo->findAndModify('items', array('name' => 'breading'), array('$set' => array('quantity' => 20)))->fetch(); $this->assertFalse($result); - $this->assertEquals(10, $mongo->get('items', array('name' => 'bread'))->fetch()->quantity); + $this->assertEquals(10, $mongo->find('items', array('name' => 'bread'))->fetch()->quantity); } /** diff --git a/tests/model/MongoModelTest.php b/tests/model/MongoModelTest.php index 848dc99..9f3abb0 100644 --- a/tests/model/MongoModelTest.php +++ b/tests/model/MongoModelTest.php @@ -13,6 +13,7 @@ require_once dirname(__FILE__) . '/../../Registry.php'; require_once dirname(__FILE__) . '/../../Config.php'; require_once dirname(__FILE__) . '/../../cache/Cacher.php'; +require_once dirname(__FILE__) . '/../../exception/GeneralException.php'; require_once dirname(__FILE__) . '/../../model/DbExpr.php'; require_once dirname(__FILE__) . '/../../model/Db.php'; require_once dirname(__FILE__) . '/../../model/MongoDbCommand.php'; @@ -27,8 +28,21 @@ require_once dirname(__FILE__) . '/../../model/MongoModel.php'; class MongoModelTest extends PHPUnit_Framework_TestCase { + /** + * @var MongoModel + */ private $model; + /** + * @var ReflectionMethod + */ + private $method_count; + + /** + * @var ReflectionMethod + */ + private $method_fetch; + public function run(PHPUnit_Framework_TestResult $result = NULL) { $this->setPreserveGlobalState(false); @@ -47,6 +61,13 @@ class MongoModelTest extends PHPUnit_Framework_TestCase } else { $this->model = new MongoMockModel(); } + + $model = new ReflectionClass('MongoModel'); + $this->method_count = $model->getMethod('count'); + $this->method_count->setAccessible(true); + $this->method_fetch = $model->getMethod('fetch'); + $this->method_fetch->setAccessible(true); + set_new_overload(array($this, 'newCallback')); } @@ -62,126 +83,204 @@ class MongoModelTest extends PHPUnit_Framework_TestCase * @runInSeparateProcess * @group Mongo */ - public function testFind() + public function testFetch() { Config::set('DEBUG', false); - $result = $this->model->find(); - $this->assertInstanceOf('MongoStatement', $result); - $this->assertEquals('milk', $result->limit(2)->order(array('name' => -1))->fetch()->name); - $this->assertEquals('fish', $result->fetch()->name); - $result = $this->model->find(array(), array('name'))->fetch(); + + $mock = $this->getMock('CacheKey', array('set', 'get')); + $mock->expects($this->once()) + ->method('set') + ->will($this->returnValue(true)); + $mock->expects($this->once()) + ->method('get') + ->will($this->returnValue(false)); + + $result = $this->method_fetch->invoke($this->model, array(), array('order' => array('name' => -1), 'limit' => 2), $mock); + $this->assertInstanceOf('ArrayObject', $result); + $this->assertEquals('milk', $result->name); + $result = $this->method_fetch->invoke($this->model, array(), array('fields' => array('name'))); $this->assertSame('bread', $result->name); + $result = $this->method_fetch->invoke($this->model, array()); $this->setExpectedException('PHPUnit_Framework_Error'); - $this->assertNull($result->price); + $this->assertNull($result->pounds); } /** * @runInSeparateProcess * @group Mongo */ - public function testGet() + public function testFetchField() { Config::set('DEBUG', false); - $result = $this->model->find()->limit(1)->order(array('name' => 1)); - $result = $result->fetch(); - $this->assertEquals('bread', $result->name); - $id = $result->_id; - $this->assertEquals(10, $this->model->get($id)->quantity); + + $mock = $this->getMock('CacheKey', array('set', 'get')); + $mock->expects($this->exactly(2)) + ->method('set') + ->will($this->returnValue(true)); + $mock->expects($this->exactly(2)) + ->method('get') + ->will($this->returnValue(false)); + + $model = new ReflectionClass('MongoModel'); + $method = $model->getMethod('fetchField'); + $method->setAccessible(true); + + $result = $method->invoke($this->model, array('name' => 'milk'), array(), 'quantity', $mock); + $this->assertEquals(1, $result); + $result = $method->invoke($this->model, array(), array('skip' => 2), 'quantity', $mock); + $this->assertEquals($result, $this->method_fetch->invoke($this->model, array(), array('skip' => 2))->quantity); } /** * @runInSeparateProcess * @group Mongo */ - public function testDelete() + public function testFetchAll() { Config::set('DEBUG', false); - $result = $this->model->find()->limit(1)->order(array('name' => 1)); - $id = $result->fetch()->_id; - $this->assertEquals(1, $this->model->delete($id)); - $this->assertFalse($this->model->find(array('name' => 'bread'))->fetch()); + + $mock = $this->getMock('CacheKey', array('set', 'get')); + $mock->expects($this->once()) + ->method('set') + ->will($this->returnValue(true)); + $mock->expects($this->once()) + ->method('get') + ->will($this->returnValue(false)); + + $model = new ReflectionClass('MongoModel'); + $method = $model->getMethod('fetchAll'); + $method->setAccessible(true); + + $result = $method->invoke($this->model, array('name' => 'eggs'), array(), $mock); + $this->assertEquals(2, count($result)); + $result = $method->invoke($this->model, array(), array('skip' => 2)); + $this->assertEquals(3, count($result)); + $this->assertEquals('fish', $result[0]->name); + $this->assertEquals('milk', $result[1]->name); + $this->assertEquals('eggs', $result[2]->name); } /** * @runInSeparateProcess * @group Mongo */ - public function testBatchInsert() + public function testFetchOrderParam() { Config::set('DEBUG', false); - $data = array( - array('name' => 'first object'), - array('name' => 'second object'), - array('name' => 'equal object'), - array('name' => 'equal object') - ); - $this->model->batchInsert($data); - $this->assertEquals(1, $this->model->count(array('name' => 'first object'))); - $this->assertEquals(2, $this->model->count(array('name' => 'equal object'))); - $this->model->batchInsert(array()); + $result = $this->method_fetch->invoke($this->model, array(), array('order' => 'name')); + $this->assertSame('bread', $result->name); + $result = $this->method_fetch->invoke($this->model, array(), array('order' => array('name' => 1, 'quantity' => -1), 'skip' => 1)); + $this->assertSame(2.1, $result->price); + $this->setExpectedException('GeneralException', 'Wrong order parameter given to query.'); + $this->method_fetch->invoke($this->model, array(), array('order' => 1)); } /** * @runInSeparateProcess * @group Mongo */ - public function testDeleteAll() + public function testFetchSkipLimitParam() { Config::set('DEBUG', false); + $result = $this->method_fetch->invoke($this->model, array(), array('order' => 'name')); + $this->assertSame('bread', $result->name); + $result = $this->method_fetch->invoke($this->model, array(), array('order' => array('name' => 1, 'quantity' => -1), 'skip' => 1, 'limit' => 1)); + $this->assertSame(2.1, $result->price); - $this->assertEquals(2, $this->model->count(array('name' => 'eggs'))); - $this->assertEquals(0, $this->model->deleteAll(array('name' => 'eggs'))); - $this->assertFalse($this->model->find(array('name' => 'eggs'))->fetch()); + $model = new ReflectionClass('MongoModel'); + $method = $model->getMethod('fetchAll'); + $method->setAccessible(true); + $this->assertCount(3, $method->invoke($this->model, array(), array('limit' => 3))); + $this->assertCount(2, $method->invoke($this->model, array(), array('skip' => 3))); + $this->assertCount(5, $method->invoke($this->model, array(), array())); } /** * @runInSeparateProcess * @group Mongo */ - public function testCount() + public function testFetchFieldsParam() { Config::set('DEBUG', false); - $this->assertEquals(5, $this->model->count()); - $this->assertEquals(2, $this->model->count(array('name' => 'eggs'))); + $result = $this->method_fetch->invoke($this->model, array(), array('fields' => 'name')); + $this->assertTrue(!isset($result->quantity)); + $result = $this->method_fetch->invoke($this->model, array(), array('fields' => array('name', 'price'))); + $this->assertTrue(!isset($result->quantity)); + $result = $this->method_fetch->invoke($this->model, array(), array('fields' => array('name' => 1, 'price' => 1))); + $this->assertTrue(!isset($result->quantity)); + $this->setExpectedException('GeneralException', 'Wrong fields parameter given to query.'); + $this->method_fetch->invoke($this->model, array(), array('fields' => 1)); } /** * @runInSeparateProcess * @group Mongo */ - public function testFetch() + public function testGet() { Config::set('DEBUG', false); + $result = $this->method_fetch->invoke($this->model, array(), array('order' => array('name' => 1))); + $this->assertEquals('bread', $result->name); + $id = $result->_id; + $this->assertEquals(10, $this->model->get($id)->quantity); + } - $mock = $this->getMock('CacheKey', array('set', 'get')); - $mock->expects($this->exactly(3)) - ->method('set') - ->will($this->returnValue(true)); - $mock->expects($this->exactly(3)) - ->method('get') - ->will($this->returnValue(false)); - - $model = new ReflectionClass('MongoModel'); - $method = $model->getMethod('fetchField'); - $method->setAccessible(true); - - $result = $method->invoke($this->model, array('name' => 'milk'), array(), 'quantity', $mock); - $this->assertEquals(1, $result); - - $model = new ReflectionClass('MongoModel'); - $method = $model->getMethod('fetch'); - $method->setAccessible(true); + /** + * @runInSeparateProcess + * @group Mongo + */ + public function testDelete() + { + Config::set('DEBUG', false); + $result = $this->method_fetch->invoke($this->model, array(), array('order' => array('name' => 1))); + $id = $result->_id; + $this->assertEquals(1, $this->model->delete($id)); + $this->assertFalse($this->method_fetch->invoke($this->model, array('name' => 'bread'))); + } - $result = $method->invoke($this->model, array('name' => 'bread'), array(), $mock); - $this->assertEquals('bread', $result->name); + /** + * @runInSeparateProcess + * @group Mongo + */ + public function testUpdate() + { + Config::set('DEBUG', false); + $this->model->insert(array('name' => 'testbread', 'price' => 3.2, 'quantity' => 10)); + $result = $this->method_fetch->invoke($this->model, array('name' => 'testbread')); + $this->assertEquals(10, $result->quantity); + $this->model->update(array('$set' => array('quantity' => 3)), $result->_id); + $this->assertEquals(3, $this->model->get($result->_id)->quantity); + $this->model->update(array('$set' => array('quantity' => 13)), (string)$result->_id); + $this->assertEquals(13, $this->model->get($result->_id)->quantity); + } - $model = new ReflectionClass('MongoModel'); - $method = $model->getMethod('fetchAll'); - $method->setAccessible(true); + /** + * @runInSeparateProcess + * @group Mongo + */ + public function testBatchInsert() + { + Config::set('DEBUG', false); + $data = array( + array('name' => 'first object'), + array('name' => 'second object'), + array('name' => 'equal object'), + array('name' => 'equal object') + ); + $this->model->batchInsert($data); + $this->assertEquals(1, $this->method_count->invoke($this->model, array('name' => 'first object'))); + $this->assertEquals(2, $this->method_count->invoke($this->model, array('name' => 'equal object'))); + } - $result = $method->invoke($this->model, array('name' => 'eggs'), array(), $mock); - $this->assertEquals(2, count($result)); - $this->assertEquals('eggs', $result[0]->name); + /** + * @runInSeparateProcess + * @group Mongo + */ + public function testCount() + { + Config::set('DEBUG', false); + $this->assertEquals(5, $this->method_count->invoke($this->model)); + $this->assertEquals(2, $this->method_count->invoke($this->model, array('name' => 'eggs'))); } /** @@ -208,11 +307,11 @@ class MongoModelTest extends PHPUnit_Framework_TestCase $this->model->insert(array('_id' => 1, 'name' => 'testbread', 'price' => 3.2, 'quantity' => 10)); $this->model->insert(array('_id' => 2, 'name' => 'testbread', 'price' => 12, 'quantity' => 2)); - $this->assertSame(2, $this->model->count(array('name' => 'testbread'))); + $this->assertSame(2, $this->method_count->invoke($this->model, array('name' => 'testbread'))); $prop->setValue($this->model, false); $this->model->delete(1); - $this->assertSame(1, $this->model->count(array('name' => 'testbread'))); + $this->assertSame(1, $this->method_count->invoke($this->model, array('name' => 'testbread'))); } /** @@ -225,13 +324,13 @@ class MongoModelTest extends PHPUnit_Framework_TestCase $this->model->insert(array('name' => 'testbread', 'price' => 3.2, 'quantity' => 10)); $this->model->insert(array('name' => 'testbread', 'price' => 12, 'quantity' => 2)); - $this->assertSame(2, $this->model->count(array('name' => 'testbread'))); - $id = $this->model->find(array('name' => 'testbread'))->limit(1)->fetch()->_id->__toString(); + $this->assertSame(2, $this->method_count->invoke($this->model, array('name' => 'testbread'))); + $id = $this->method_fetch->invoke($this->model, array('name' => 'testbread'))->_id->__toString(); $this->assertInternalType('string', $id); $item = $this->model->get($id); $this->assertSame('testbread', $item->name); $this->model->delete($id); - $this->assertSame(1, $this->model->count(array('name' => 'testbread'))); + $this->assertSame(1, $this->method_count->invoke($this->model, array('name' => 'testbread'))); } public function tearDown() @@ -242,7 +341,7 @@ class MongoModelTest extends PHPUnit_Framework_TestCase $db = $connection->selectDB($conf['database']); $db->authenticate($conf['username'], $conf['password']); $collection = 'mongomock'; - $db->dropCollection($collection); + $db->selectCollection($collection)->remove(array()); } protected function newCallback($className)