Merge branch 'mongo'
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,4 +2,5 @@
|
||||
/.project
|
||||
/.cache
|
||||
/tests/report
|
||||
*~
|
||||
/.idea
|
||||
|
34
Load.php
34
Load.php
@ -11,10 +11,27 @@
|
||||
|
||||
class Load
|
||||
{
|
||||
|
||||
|
||||
static protected $file;
|
||||
|
||||
static protected $autoload;
|
||||
|
||||
static protected $exclude = array('/.git', '/lib/core/tests', '/lib/core/.git');
|
||||
|
||||
/**
|
||||
* Add exclude path for autoload. Should be called before setAutoloadFrom
|
||||
* @static
|
||||
* @param array $exclude list of relative path (from project root)
|
||||
* @return void
|
||||
*/
|
||||
static public function setExclude($exclude = array())
|
||||
{
|
||||
if(!is_array($exclude)) {
|
||||
$exclude = array($exclude);
|
||||
}
|
||||
self::$exclude = array_merge(self::$exclude, $exclude);
|
||||
}
|
||||
|
||||
static public function setAutoloadFrom($file)
|
||||
{
|
||||
self::$file = $file;
|
||||
@ -23,7 +40,7 @@ class Load
|
||||
}
|
||||
self::$autoload = require(self::$file);
|
||||
}
|
||||
|
||||
|
||||
static public function autoload($class)
|
||||
{
|
||||
if (isset(self::$autoload[$class])) {
|
||||
@ -35,16 +52,16 @@ class Load
|
||||
self::buildAutoload();
|
||||
}
|
||||
if (isset(self::$autoload[$class])) {
|
||||
require(PATH . self::$autoload[$class]);
|
||||
require(PATH . self::$autoload[$class]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static public function getFilePath($class)
|
||||
{
|
||||
return self::$autoload[$class];
|
||||
}
|
||||
|
||||
|
||||
static protected function buildAutoload()
|
||||
{
|
||||
ignore_user_abort(true);
|
||||
@ -52,12 +69,11 @@ class Load
|
||||
if (!file_exists($dir) && !mkdir($dir)) {
|
||||
trigger_error('Can\'t create directory: "' . $dir . '"', E_USER_ERROR);
|
||||
}
|
||||
|
||||
|
||||
$scan = array(PATH . '/' . APP . '/src', PATH . '/lib');
|
||||
|
||||
require_once(PATH . '/lib/core/util/AutoloadBuilder.php');
|
||||
|
||||
$builder = new AutoloadBuilder(self::$file, $scan);
|
||||
|
||||
$builder = new AutoloadBuilder(self::$file, $scan, self::$exclude);
|
||||
$builder->build();
|
||||
ignore_user_abort(false);
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ class CliLogger extends Logger
|
||||
protected function concreteLog($message)
|
||||
{
|
||||
// Заменяем окончания строк на их символы
|
||||
$message = str_replace(array("\r", "\n"), array('\r', '\n'), $message);
|
||||
$message = str_replace(array("\r\n"), array(PHP_EOL), $message);
|
||||
$out = microtime(true) . " \t: " . $this->pid . trim($message) . PHP_EOL;
|
||||
print($out);
|
||||
}
|
||||
|
@ -12,8 +12,6 @@
|
||||
abstract class DbDriver
|
||||
{
|
||||
|
||||
protected $identifier_quote = '`';
|
||||
|
||||
/**
|
||||
* Database connection
|
||||
*
|
||||
@ -44,173 +42,39 @@ abstract class DbDriver
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function getConnection()
|
||||
{
|
||||
$this->connect();
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
public function beginTransaction()
|
||||
{
|
||||
$this->connect();
|
||||
$this->driverBeginTransaction();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function commit()
|
||||
{
|
||||
$this->connect();
|
||||
$this->driverCommitTransaction();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function rollback()
|
||||
{
|
||||
$this->connect();
|
||||
$this->driverRollbackTransaction();
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param mixed $request
|
||||
* @param mixed $params
|
||||
* @return DbStatement
|
||||
*/
|
||||
public function query($sql, $params = array())
|
||||
public function query($request, $params = array())
|
||||
{
|
||||
$this->connect();
|
||||
if (!is_array($params)) {
|
||||
$params = array($params);
|
||||
}
|
||||
$stmt = $this->prepare($sql);
|
||||
$stmt = $this->prepare($request);
|
||||
$stmt->execute($params);
|
||||
return $stmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param mixed $bind
|
||||
* @param mixed $on_duplicate
|
||||
* @return int Affected rows count
|
||||
*/
|
||||
public function insert($table, $bind, $on_duplicate = array())
|
||||
{
|
||||
$columns = array();
|
||||
foreach ($bind as $col => $val) {
|
||||
$columns[] = $this->quoteIdentifier($col);
|
||||
}
|
||||
$values = array_values($bind);
|
||||
|
||||
$sql = 'INSERT INTO ' . $this->quoteIdentifier($table)
|
||||
. ' (' . implode(', ', $columns) . ') VALUES (' . $this->quote($values) . ')';
|
||||
return $this->query($sql)->affectedRows();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param array $bind
|
||||
* @param mixed $where
|
||||
* @return int
|
||||
*/
|
||||
public function update($table, $bind, $where = '')
|
||||
{
|
||||
$set = array();
|
||||
foreach ($bind as $col => $val) {
|
||||
$set[] = $this->quoteIdentifier($col) . '=' . $this->quote($val);
|
||||
}
|
||||
$where = $this->whereExpr($where);
|
||||
$sql = 'UPDATE ' . $this->quoteIdentifier($table) . ' SET ' . implode(', ', $set)
|
||||
. (($where) ? (' WHERE ' . $where) : '');
|
||||
return $this->query($sql)->affectedRows();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param mixed $where
|
||||
* @return int
|
||||
*/
|
||||
public function delete($table, $where = '')
|
||||
{
|
||||
$where = $this->whereExpr($where);
|
||||
$sql = 'DELETE FROM ' . $this->quoteIdentifier($table) . (($where) ? (' WHERE ' . $where) : '');
|
||||
return $this->query($sql)->affectedRows();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
public function quote($value)
|
||||
{
|
||||
if ($value instanceof DbExpr) {
|
||||
return (string) $value;
|
||||
}
|
||||
if (is_array($value)) {
|
||||
foreach ($value as &$val) {
|
||||
$val = $this->quote($val);
|
||||
}
|
||||
return implode(', ', $value);
|
||||
}
|
||||
return $this->driverQuote($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ident
|
||||
* @return string
|
||||
*/
|
||||
public function quoteIdentifier($ident)
|
||||
{
|
||||
$ident = explode('.', $ident);
|
||||
if (!is_array($ident)) {
|
||||
$ident = array($ident);
|
||||
}
|
||||
foreach ($ident as &$segment) {
|
||||
$segment = $this->identifier_quote . $segment . $this->identifier_quote;
|
||||
}
|
||||
return implode('.', $ident);
|
||||
}
|
||||
|
||||
public function quoteInto($text, $value)
|
||||
{
|
||||
$pos = mb_strpos($text, '?');
|
||||
if ($pos === false) {
|
||||
return $text;
|
||||
}
|
||||
return mb_substr($text, 0, $pos) . $this->quote($value) . mb_substr($text, $pos + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $where
|
||||
* @return string
|
||||
*/
|
||||
protected function whereExpr($where)
|
||||
{
|
||||
if (empty($where)) {
|
||||
return $where;
|
||||
}
|
||||
|
||||
if (!is_array($where)) {
|
||||
$where = array($where);
|
||||
}
|
||||
foreach ($where as $cond => &$term) {
|
||||
if (is_int($cond)) {
|
||||
if ($term instanceof DbExpr) {
|
||||
$term = (string) $term;
|
||||
}
|
||||
} else {
|
||||
$term = $this->quoteInto($cond, $term);
|
||||
}
|
||||
}
|
||||
return implode(' AND ', $where);
|
||||
}
|
||||
|
||||
|
||||
/* Abstract methods */
|
||||
|
||||
abstract public function insert($table, $data);
|
||||
|
||||
abstract public function update($table, $data, $condition);
|
||||
|
||||
/**
|
||||
* @return DbStatement
|
||||
*/
|
||||
abstract public function prepare($sql);
|
||||
abstract public function delete($table, $condition);
|
||||
|
||||
abstract public function prepare($request);
|
||||
|
||||
abstract public function getInsertId($table = null, $key = null);
|
||||
|
||||
@ -219,12 +83,4 @@ abstract class DbDriver
|
||||
abstract public function disconnect();
|
||||
|
||||
abstract protected function connect();
|
||||
|
||||
abstract protected function driverQuote($value);
|
||||
|
||||
abstract protected function driverBeginTransaction();
|
||||
|
||||
abstract protected function driverCommitTransaction();
|
||||
|
||||
abstract protected function driverRollbackTransaction();
|
||||
}
|
@ -11,49 +11,27 @@
|
||||
|
||||
abstract class DbStatement
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @var DbDriver
|
||||
*/
|
||||
protected $driver;
|
||||
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $sql;
|
||||
|
||||
protected $map = null;
|
||||
|
||||
protected $request;
|
||||
|
||||
protected $params = array();
|
||||
|
||||
|
||||
protected $result;
|
||||
|
||||
public function __construct($driver, $sql)
|
||||
|
||||
public function __construct($driver, $request)
|
||||
{
|
||||
$this->driver = $driver;
|
||||
$this->sql = $sql;
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
public function bindParam($param, &$value)
|
||||
{
|
||||
if ($this->map === null) {
|
||||
$this->mapPlaceholders();
|
||||
}
|
||||
if (count($this->map) > 0) {
|
||||
if (!is_string($param) && !is_int($param)) {
|
||||
throw new GeneralException('Placeholder must be an array or string');
|
||||
}
|
||||
if (is_object($value) && ! ($value instanceof DbExpr)) {
|
||||
throw new GeneralException('Objects excepts DbExpr not allowed.');
|
||||
}
|
||||
if (isset($this->map[$param])) {
|
||||
$this->params[$param] = &$value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
* @return bool
|
||||
@ -67,48 +45,7 @@ abstract class DbStatement
|
||||
}
|
||||
return $this->driverExecute($this->assemble());
|
||||
}
|
||||
|
||||
protected function mapPlaceholders()
|
||||
{
|
||||
$matches = array();
|
||||
if(preg_match_all('/(\?|:[A-z0-9_]+)/u', $this->sql, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
$noname = 0;
|
||||
foreach ($matches[0] as $id=>$match) {
|
||||
$match[2] = $matches[1][$id][0];
|
||||
$name = ($match[2][0] === ':') ? ltrim($match[2], ':') : $noname++;
|
||||
$this->map[$name]['placeholder'] = $match[0];
|
||||
$this->map[$name]['offset'][] = $match[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function assemble()
|
||||
{
|
||||
if (empty($this->map)) {
|
||||
return $this->sql;
|
||||
}
|
||||
|
||||
$query = $this->sql;
|
||||
$placeholders = array();
|
||||
foreach($this->map as $name => $place) {
|
||||
$value = $this->driver->quote($this->params[$name]);
|
||||
foreach ($place['offset'] as $offset) {
|
||||
$placeholders[$offset] = array('placeholder' => $place['placeholder'], 'value' => $value);
|
||||
}
|
||||
}
|
||||
|
||||
ksort($placeholders);
|
||||
|
||||
$increment = 0;
|
||||
foreach($placeholders as $current_offset => $placeholder) {
|
||||
$offset = $current_offset + $increment;
|
||||
$length = mb_strlen($placeholder['placeholder']);
|
||||
$query = mb_substr($query, 0, $offset) . $placeholder['value'] . mb_substr($query, $offset + $length);
|
||||
$increment = (($increment - $length) + mb_strlen($placeholder['value']));
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
$this->close();
|
||||
@ -138,7 +75,7 @@ abstract class DbStatement
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*/
|
||||
@ -150,36 +87,28 @@ abstract class DbStatement
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function fetchPairs()
|
||||
{
|
||||
$data = array();
|
||||
while ($row = $this->fetch(Db::FETCH_NUM)) {
|
||||
$data[$row[0]] = $row[1];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/* Abstract methods */
|
||||
|
||||
|
||||
abstract public function bindParam($param, &$value);
|
||||
|
||||
abstract protected function assemble();
|
||||
|
||||
abstract public function fetch($style = Db::FETCH_OBJ);
|
||||
|
||||
|
||||
abstract public function fetchObject($class = 'stdClass');
|
||||
|
||||
|
||||
abstract public function close();
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
abstract public function affectedRows();
|
||||
|
||||
|
||||
abstract public function numRows();
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
abstract protected function driverExecute($sql);
|
||||
abstract protected function driverExecute($request);
|
||||
}
|
||||
|
188
model/Model.php
188
model/Model.php
@ -62,41 +62,13 @@ abstract class Model
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ident
|
||||
* @return string Quoted identifier.
|
||||
*/
|
||||
public function identify($ident)
|
||||
{
|
||||
return $this->db->quoteIdentifier($ident);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @return string Quoted value.
|
||||
*/
|
||||
public function quote($value)
|
||||
{
|
||||
return $this->db->quote($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return object
|
||||
*/
|
||||
public function get($id)
|
||||
{
|
||||
$sql = 'SELECT * FROM :table WHERE :pk=?';
|
||||
return $this->fetch($sql, $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $on_duplicate
|
||||
* @return int Id of inserted row
|
||||
*/
|
||||
public function insert($data, $on_duplicate = array())
|
||||
public function insert($data)
|
||||
{
|
||||
$affected = $this->db->insert($this->table(), $data, $on_duplicate);
|
||||
$affected = $this->db->insert($this->table(), $data);
|
||||
return ($this->getInsertId()) ? $this->getInsertId() : $affected;
|
||||
}
|
||||
|
||||
@ -107,21 +79,8 @@ abstract class Model
|
||||
*/
|
||||
public function update($data, $where)
|
||||
{
|
||||
if (is_int($where) || $where === (string) (int) $where) {
|
||||
$where = $this->identify($this->key) . '=' . (int) $where;
|
||||
}
|
||||
return $this->db->update($this->table(), $data, $where);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id Int id
|
||||
* @return int Number of affected rows
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
$where = $this->identify($this->key) . '=' . (int) $id;
|
||||
return $this->db->delete($this->table(), $where);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
@ -133,112 +92,7 @@ abstract class Model
|
||||
}
|
||||
return $this->table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates order sql string
|
||||
*
|
||||
* @param array $params
|
||||
* @param array $sortable
|
||||
* @return string
|
||||
*/
|
||||
protected function order($params, $sortable = array('id'))
|
||||
{
|
||||
$sql = '';
|
||||
if (isset($params['sort'])) {
|
||||
$order = (isset($params['order']) && $params['order'] == 'desc') ? 'DESC' : 'ASC';
|
||||
if (in_array($params['sort'], $sortable)) {
|
||||
$sql = ' ORDER BY ' . $this->identify($params['sort']) . ' ' . $order;
|
||||
}
|
||||
}
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches using like
|
||||
*
|
||||
* @param array $params
|
||||
* @param array $searchable
|
||||
* @param string $table_prefix
|
||||
* @return string
|
||||
*/
|
||||
protected function search($params, $searchable = array('id'), $table_prefix = '')
|
||||
{
|
||||
$sql = '';
|
||||
if (isset($params['q']) && isset($params['qt']) && in_array($params['qt'], $searchable)) {
|
||||
if ($table_prefix) {
|
||||
$sql = $table_prefix . '.';
|
||||
}
|
||||
$sql .= $this->identify($params['qt']) . ' LIKE ' . $this->quote('%' . $params['q'] . '%');
|
||||
}
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method appends to params table and primary key.
|
||||
* So they can be accessed thru `:table` and `:pk` placeholders.
|
||||
*
|
||||
* @return DbStatement
|
||||
*/
|
||||
protected function query($sql, $params = array())
|
||||
{
|
||||
if (!is_array($params)) {
|
||||
$params = array($params);
|
||||
}
|
||||
$params = array(
|
||||
'table' => new DbExpr($this->identify($this->table())),
|
||||
'pk' => new DbExpr($this->identify($this->key)),
|
||||
) + $params;
|
||||
return $this->db->query($sql, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array $params
|
||||
* @param string $field
|
||||
* @param CacheKey $cache_key
|
||||
*/
|
||||
protected function fetchField($sql, $params = array(), $field, $cache_key = null)
|
||||
{
|
||||
if (!$cache_key || !$result = $cache_key->get()) {
|
||||
$result = $this->query($sql, $params)->fetchField($field);
|
||||
if ($cache_key) {
|
||||
$cache_key->set($result);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array $params
|
||||
* @param CacheKey $cache_key
|
||||
*/
|
||||
protected function fetch($sql, $params = array(), $cache_key = null)
|
||||
{
|
||||
if (!$cache_key || !$result = $cache_key->get()) {
|
||||
$result = $this->query($sql, $params)->fetch();
|
||||
if ($cache_key) {
|
||||
$cache_key->set($result);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array $params
|
||||
* @param CacheKey $cache_key
|
||||
*/
|
||||
protected function fetchAll($sql, $params = array(), $cache_key = null)
|
||||
{
|
||||
if (!$cache_key || !$result = $cache_key->get()) {
|
||||
$result = $this->query($sql, $params)->fetchAll();
|
||||
if ($cache_key) {
|
||||
$cache_key->set($result);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/* Cache workaround */
|
||||
|
||||
@ -280,4 +134,42 @@ abstract class Model
|
||||
}
|
||||
$this->caches_clean = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return object
|
||||
*/
|
||||
abstract public function get($id);
|
||||
|
||||
/**
|
||||
* @param int $id Int id
|
||||
* @return int Number of affected rows
|
||||
*/
|
||||
abstract public function delete($id);
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array $params
|
||||
* @param string $field
|
||||
* @param CacheKey $cache_key
|
||||
*/
|
||||
abstract protected function fetchField($data, $params = array(), $field, $cache_key = null);
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array $params
|
||||
* @param CacheKey $cache_key
|
||||
*/
|
||||
abstract protected function fetch($data, $params = array(), $cache_key = null);
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array $params
|
||||
* @param CacheKey $cache_key
|
||||
*/
|
||||
abstract protected function fetchAll($data, $params = array(), $cache_key = null);
|
||||
}
|
289
model/MongoDbCommand.php
Normal file
289
model/MongoDbCommand.php
Normal file
@ -0,0 +1,289 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright NetMonsters <team@netmonsters.ru>
|
||||
* @link http://netmonsters.ru
|
||||
* @package Majestic
|
||||
* @subpackage db
|
||||
* @since 2011-11-15
|
||||
*/
|
||||
|
||||
class MongoCommandBuilder
|
||||
{
|
||||
|
||||
const FIND = 'Find';
|
||||
|
||||
const INSERT = 'Insert';
|
||||
|
||||
const UPDATE = 'Update';
|
||||
|
||||
const REMOVE = 'Remove';
|
||||
|
||||
const COMMAND = 'Command';
|
||||
|
||||
static public function factory($type, $collection = null)
|
||||
{
|
||||
$class = ucfirst($type) . 'MongoCommand';
|
||||
$command = new $class();
|
||||
$command->setCollection($collection);
|
||||
return $command;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class MongoDbCommand
|
||||
{
|
||||
protected $collection;
|
||||
|
||||
public function execute()
|
||||
{
|
||||
if ($this->checkParams()) {
|
||||
return $this->concreteExecute();
|
||||
} else {
|
||||
throw new GeneralException(get_called_class() . ' error. Bind all required params first.');
|
||||
}
|
||||
}
|
||||
|
||||
public function bindParam($name, $value)
|
||||
{
|
||||
if (property_exists($this, $name)) {
|
||||
$this->$name = $value;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCollection($collection)
|
||||
{
|
||||
$this->collection = $collection;
|
||||
return $this;
|
||||
}
|
||||
|
||||
abstract protected function concreteExecute();
|
||||
|
||||
abstract protected function checkParams();
|
||||
|
||||
/**
|
||||
* @TODO: implement method in subclasses for Profiler
|
||||
*/
|
||||
abstract public function __toString();
|
||||
}
|
||||
|
||||
class FindMongoCommand extends MongoDbCommand
|
||||
{
|
||||
protected $condition;
|
||||
|
||||
protected $fields;
|
||||
|
||||
protected $multiple = true;
|
||||
|
||||
protected function concreteExecute()
|
||||
{
|
||||
if ($this->multiple) {
|
||||
return $this->collection->find($this->condition, $this->fields);
|
||||
} else {
|
||||
return $this->collection->findOne($this->condition, $this->fields);
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkParams()
|
||||
{
|
||||
if (isset($this->collection) && isset($this->condition) && isset($this->fields)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
if ($this->checkParams()) {
|
||||
$result = 'Collection: ' . $this->collection . PHP_EOL;
|
||||
ob_start();
|
||||
var_dump($this->condition);
|
||||
$condition = ob_get_clean();
|
||||
$result .= 'Condition: ' . $condition . PHP_EOL;
|
||||
ob_start();
|
||||
var_dump($this->fields);
|
||||
$fields = ob_get_clean();
|
||||
$result .= 'Fields: ' . $fields . PHP_EOL;
|
||||
$mult = $this->multiple ? 'TRUE' : 'FALSE';
|
||||
$result .= 'Multiple fields: ' . $mult . PHP_EOL;
|
||||
return $result;
|
||||
} else {
|
||||
return 'Command properties not set';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class InsertMongoCommand extends MongoDbCommand
|
||||
{
|
||||
protected $data;
|
||||
|
||||
protected $safe = true;
|
||||
|
||||
protected $insertId = false;
|
||||
|
||||
protected function concreteExecute()
|
||||
{
|
||||
$result = $this->collection->insert($this->data, array('safe' => $this->safe));
|
||||
$this->insertId = $this->data['_id'];
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function checkParams()
|
||||
{
|
||||
if (isset($this->collection) && isset($this->data) && isset($this->safe)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function getInsertId()
|
||||
{
|
||||
return $this->insertId;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
if ($this->checkParams()) {
|
||||
$result = 'Collection: ' . $this->collection . PHP_EOL;
|
||||
ob_start();
|
||||
var_dump($this->data);
|
||||
$data = ob_get_clean();
|
||||
$result .= 'Data: ' . $data . PHP_EOL;
|
||||
$safe = $this->safe ? 'TRUE' : 'FALSE';
|
||||
$result .= 'Safe operation: ' . $safe . PHP_EOL;
|
||||
return $result;
|
||||
} else {
|
||||
return 'Command properties not set';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UpdateMongoCommand extends MongoDbCommand
|
||||
{
|
||||
protected $condition;
|
||||
|
||||
protected $data;
|
||||
|
||||
protected $multiple = true;
|
||||
|
||||
protected $upsert = false;
|
||||
|
||||
protected $safe = true;
|
||||
|
||||
protected function concreteExecute()
|
||||
{
|
||||
return $this->collection->update($this->condition, $this->data,
|
||||
array('multiple' => $this->multiple, 'upsert' => $this->upsert, 'safe' => $this->safe));
|
||||
}
|
||||
|
||||
protected function checkParams()
|
||||
{
|
||||
if (isset($this->collection) && isset($this->condition) && isset($this->data) &&
|
||||
isset($this->upsert) && isset($this->safe)
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
if ($this->checkParams()) {
|
||||
$result = 'Collection: ' . $this->collection . PHP_EOL;
|
||||
ob_start();
|
||||
var_dump($this->condition);
|
||||
$condition = ob_get_clean();
|
||||
$result .= 'Condition: ' . $condition . PHP_EOL;
|
||||
ob_start();
|
||||
var_dump($this->data);
|
||||
$data = ob_get_clean();
|
||||
$result .= 'Data: ' . $data . PHP_EOL;
|
||||
$mult = $this->multiple ? 'TRUE' : 'FALSE';
|
||||
$result .= 'Multiple fields: ' . $mult . PHP_EOL;
|
||||
$upsert = $this->upsert ? 'TRUE' : 'FALSE';
|
||||
$result .= 'Upsert: ' . $upsert . PHP_EOL;
|
||||
$safe = $this->safe ? 'TRUE' : 'FALSE';
|
||||
$result .= 'Safe operation: ' . $safe . PHP_EOL;
|
||||
return $result;
|
||||
} else {
|
||||
return 'Command properties not set';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RemoveMongoCommand extends MongoDbCommand
|
||||
{
|
||||
protected $condition;
|
||||
|
||||
protected $safe = true;
|
||||
|
||||
protected function concreteExecute()
|
||||
{
|
||||
return $this->collection->remove($this->condition, array('safe' => $this->safe));
|
||||
}
|
||||
|
||||
protected function checkParams()
|
||||
{
|
||||
if (isset($this->collection) && isset($this->condition) && isset($this->safe)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
if ($this->checkParams()) {
|
||||
$result = 'Collection: ' . $this->collection . PHP_EOL;
|
||||
ob_start();
|
||||
var_dump($this->condition);
|
||||
$condition = ob_get_clean();
|
||||
$result .= 'Condition: ' . $condition . PHP_EOL;
|
||||
$safe = $this->safe ? 'TRUE' : 'FALSE';
|
||||
$result .= 'Safe operation: ' . $safe . PHP_EOL;
|
||||
return $result;
|
||||
} else {
|
||||
return 'Command properties not set';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CommandMongoCommand extends MongoDbCommand
|
||||
{
|
||||
protected $command;
|
||||
|
||||
protected function concreteExecute()
|
||||
{
|
||||
$db = $this->collection->db;
|
||||
if ($db instanceof MongoDB) {
|
||||
return $db->command($this->command);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkParams()
|
||||
{
|
||||
if (isset($this->collection) && isset($this->command)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
if ($this->checkParams()) {
|
||||
$result = 'Collection: ' . $this->collection . PHP_EOL;
|
||||
ob_start();
|
||||
var_dump($this->command);
|
||||
$command = ob_get_clean();
|
||||
$result .= 'Command: ' . $command . PHP_EOL;
|
||||
return $result;
|
||||
} else {
|
||||
return 'Command properties not set';
|
||||
}
|
||||
}
|
||||
}
|
168
model/MongoDriver.php
Normal file
168
model/MongoDriver.php
Normal file
@ -0,0 +1,168 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright NetMonsters <team@netmonsters.ru>
|
||||
* @link http://netmonsters.ru
|
||||
* @package Majestic
|
||||
* @subpackage db
|
||||
* @since 2011-11-10
|
||||
*/
|
||||
|
||||
/**
|
||||
* @property Mongo $connection
|
||||
*/
|
||||
class MongoDriver extends NoSqlDbDriver
|
||||
{
|
||||
protected $last_insert_id = 0;
|
||||
|
||||
protected $db_name = 'admin';
|
||||
|
||||
protected $db = null;
|
||||
|
||||
protected function getCollection($name)
|
||||
{
|
||||
if (!$this->connection) {
|
||||
$this->connect();
|
||||
}
|
||||
return $this->connection->selectCollection($this->db, $name);
|
||||
}
|
||||
|
||||
public function count($collection, $query = array(), $limit = 0, $skip = 0)
|
||||
{
|
||||
return $this->getCollection($collection)->count($query, $limit, $skip);
|
||||
}
|
||||
|
||||
public function find($collection, $condition = array(), $fields = array())
|
||||
{
|
||||
$command = MongoCommandBuilder::factory(MongoCommandBuilder::FIND, $this->getCollection($collection));
|
||||
$params = array(
|
||||
'condition' => $condition,
|
||||
'fields' => $fields
|
||||
);
|
||||
|
||||
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));
|
||||
$cmd = array(
|
||||
'findAndModify' => $collection,
|
||||
'query' => $query,
|
||||
'update' => $update,
|
||||
'sort' => $sort,
|
||||
'fields' => $field,
|
||||
'new' => $new,
|
||||
'upsert' => $upsert,
|
||||
'remove' => $remove
|
||||
);
|
||||
$params = array('command' => $cmd);
|
||||
return $this->query($command, $params);
|
||||
}
|
||||
|
||||
public function command($collection, $cmd)
|
||||
{
|
||||
$command = MongoCommandBuilder::factory(MongoCommandBuilder::COMMAND, $this->getCollection($collection));
|
||||
$params = array('command' => $cmd);
|
||||
return $this->query($command, $params);
|
||||
}
|
||||
|
||||
public function insert($collection, $data, $safe = true)
|
||||
{
|
||||
$command = MongoCommandBuilder::factory(MongoCommandBuilder::INSERT, $this->getCollection($collection));
|
||||
$params = array(
|
||||
'data' => $data,
|
||||
'safe' => $safe
|
||||
);
|
||||
$result = $this->query($command, $params);
|
||||
$this->last_insert_id = $result->getInsertId();
|
||||
return $result->affectedRows();
|
||||
}
|
||||
|
||||
public function update($collection, $data, $condition = array(), $multiple = true, $upsert = false, $safe = true)
|
||||
{
|
||||
$command = MongoCommandBuilder::factory(MongoCommandBuilder::UPDATE, $this->getCollection($collection));
|
||||
$params = array(
|
||||
'data' => $data,
|
||||
'condition' => $condition,
|
||||
'multiple' => $multiple,
|
||||
'upsert' => $upsert,
|
||||
'safe' => $safe
|
||||
);
|
||||
|
||||
return $this->query($command, $params)->affectedRows();
|
||||
}
|
||||
|
||||
public function delete($collection, $condition = array(), $safe = true)
|
||||
{
|
||||
$command = MongoCommandBuilder::factory(MongoCommandBuilder::REMOVE, $this->getCollection($collection));
|
||||
$params = array(
|
||||
'condition' => $condition,
|
||||
'safe' => $safe
|
||||
);
|
||||
|
||||
return $this->query($command, $params)->affectedRows();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $request
|
||||
* @return DbStatement
|
||||
*/
|
||||
public function prepare($request)
|
||||
{
|
||||
return new MongoStatement($this, $request);
|
||||
}
|
||||
|
||||
public function getInsertId($table = null, $key = null)
|
||||
{
|
||||
return $this->last_insert_id;
|
||||
}
|
||||
|
||||
public function isConnected()
|
||||
{
|
||||
if (!is_null($this->connection)) {
|
||||
return $this->connection->connected;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function disconnect()
|
||||
{
|
||||
if ($this->isConnected()) {
|
||||
$this->connection->close();
|
||||
}
|
||||
$this->connection = null;
|
||||
}
|
||||
|
||||
protected function connect()
|
||||
{
|
||||
if ($this->connection) {
|
||||
return;
|
||||
}
|
||||
|
||||
$host = $this->config['hostname'];
|
||||
$port = isset($this->config['port']) ? ':' . (string) $this->config['port'] : '';
|
||||
|
||||
$this->config = array(
|
||||
'username' => $this->config['username'],
|
||||
'password' => $this->config['password'],
|
||||
'db' => $this->config['database']
|
||||
);
|
||||
|
||||
$this->connection = new Mongo('mongodb://' . $host . $port, $this->config);
|
||||
$this->db = $this->connection->selectDB($this->config['db']);
|
||||
}
|
||||
}
|
73
model/MongoModel.php
Normal file
73
model/MongoModel.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Класс модели данных
|
||||
*
|
||||
* @copyright NetMonsters <team@netmonsters.ru>
|
||||
* @link http://netmonsters.ru
|
||||
* @package Majestic
|
||||
* @subpackage Model
|
||||
* @since 2011-11-15
|
||||
*/
|
||||
|
||||
abstract class MongoModel extends Model
|
||||
{
|
||||
|
||||
public function count($query = array(), $limit = 0, $skip = 0)
|
||||
{
|
||||
return $this->db->count($this->table(), $query, $limit, $skip);
|
||||
}
|
||||
|
||||
public function find($condition = array())
|
||||
{
|
||||
return $this->db->find($this->table(), $condition);
|
||||
}
|
||||
|
||||
public function get($id)
|
||||
{
|
||||
return $this->db->get($this->table(), array('_id' => $id))->fetch();
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
return $this->db->delete($this->table(), array('_id' => $id));
|
||||
}
|
||||
|
||||
public function deleteAll($query = array())
|
||||
{
|
||||
$this->db->delete($this->table(), $query);
|
||||
}
|
||||
|
||||
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);
|
||||
if ($cache_key) {
|
||||
$cache_key->set($result);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function fetch($data, $params = array(), $cache_key = null)
|
||||
{
|
||||
if (!$cache_key || !$result = $cache_key->get()) {
|
||||
$result = $this->db->find($this->table(), $data)->fetch();
|
||||
if ($cache_key) {
|
||||
$cache_key->set($result);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function fetchAll($data, $params = array(), $cache_key = null)
|
||||
{
|
||||
if (!$cache_key || !$result = $cache_key->get()) {
|
||||
$result = $this->db->find($this->table(), $data)->fetchAll();
|
||||
if ($cache_key) {
|
||||
$cache_key->set($result);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
169
model/MongoStatement.php
Normal file
169
model/MongoStatement.php
Normal file
@ -0,0 +1,169 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright NetMonsters <team@netmonsters.ru>
|
||||
* @link http://netmonsters.ru
|
||||
* @package Majestic
|
||||
* @subpackage db
|
||||
* @since 2011-11-15
|
||||
*/
|
||||
|
||||
/**
|
||||
* @property MongoDriver $driver
|
||||
* @property MongoCursor $result
|
||||
*/
|
||||
class MongoStatement extends DbStatement
|
||||
{
|
||||
|
||||
protected $insertId = false;
|
||||
|
||||
public function order($sort = array())
|
||||
{
|
||||
if ($this->result instanceof MongoCursor) {
|
||||
$this->result->sort($sort);
|
||||
return $this;
|
||||
} else {
|
||||
throw new GeneralException('MongoStatement error. Impossible order results of opened cursor.');
|
||||
}
|
||||
}
|
||||
|
||||
public function skip($skip = 0)
|
||||
{
|
||||
if ($this->result instanceof MongoCursor) {
|
||||
$this->result->skip($skip);
|
||||
return $this;
|
||||
} else {
|
||||
throw new GeneralException('MongoStatement error. Impossible skip results of opened cursor.');
|
||||
}
|
||||
}
|
||||
|
||||
public function limit($limit = 0)
|
||||
{
|
||||
if ($this->result instanceof MongoCursor) {
|
||||
$this->result->limit($limit);
|
||||
return $this;
|
||||
} else {
|
||||
throw new GeneralException('MongoStatement error. Impossible limit results of opened cursor.');
|
||||
}
|
||||
}
|
||||
|
||||
public function fetch($style = Db::FETCH_OBJ)
|
||||
{
|
||||
if (!$this->result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$row = false;
|
||||
switch ($style) {
|
||||
case Db::FETCH_OBJ:
|
||||
$row = $this->fetchObject();
|
||||
break;
|
||||
case Db::FETCH_ASSOC:
|
||||
if ($this->result instanceof MongoCursor) {
|
||||
$row = $this->result->getNext();
|
||||
} else {
|
||||
$row = $this->result;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new GeneralException('Invalid fetch mode "' . $style . '" specified');
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
public function fetchObject($class = 'stdClass')
|
||||
{
|
||||
if ($this->result instanceof MongoCursor) {
|
||||
$row = $this->result->getNext();
|
||||
} else {
|
||||
$row = $this->result;
|
||||
}
|
||||
if (is_array($row) && isset($row['_id'])) {
|
||||
$row = new ArrayObject($row, ArrayObject::ARRAY_AS_PROPS);
|
||||
} else {
|
||||
$row = false;
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
$this->result = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function affectedRows()
|
||||
{
|
||||
if (is_array($this->result)) {
|
||||
if (isset($this->result['ok']) && $this->result['ok'] == 1) {
|
||||
if (isset($this->result['n'])) {
|
||||
return $this->result['n'];
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function numRows()
|
||||
{
|
||||
if ($this->result instanceof MongoCursor) {
|
||||
return $this->result->count();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MongoDbCommand $request
|
||||
* @return bool
|
||||
*/
|
||||
protected function driverExecute($request)
|
||||
{
|
||||
$mongo = $this->driver->getConnection();
|
||||
if ($mongo instanceof Mongo) {
|
||||
if (DEBUG) {
|
||||
$profiler = Profiler::getInstance()->profilerCommand('Mongo', $request);
|
||||
$result = $request->execute();
|
||||
$profiler->end();
|
||||
} else {
|
||||
$result = $request->execute();
|
||||
}
|
||||
if ($result === false) {
|
||||
throw new GeneralException('MongoDB request error.');
|
||||
}
|
||||
if ($result instanceof MongoCursor || is_array($result)) {
|
||||
$this->result = $result;
|
||||
if (is_array($result) && isset($result['value'])) {
|
||||
$this->result = $result['value'];
|
||||
}
|
||||
if (is_array($result) && isset($result['values'])) {
|
||||
$this->result = $result['values'];
|
||||
}
|
||||
}
|
||||
if ($request instanceof InsertMongoCommand) {
|
||||
$this->insertId = $request->getInsertId();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
throw new GeneralException('No connection to MongoDB server.');
|
||||
}
|
||||
}
|
||||
|
||||
public function bindParam($param, &$value)
|
||||
{
|
||||
$this->request->bindParam($param, $value);
|
||||
}
|
||||
|
||||
protected function assemble()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
public function getInsertId()
|
||||
{
|
||||
return $this->insertId;
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@
|
||||
/**
|
||||
* @property MySQLi $connection
|
||||
*/
|
||||
class MySQLiDriver extends DbDriver
|
||||
class MySQLiDriver extends SqlDbDriver
|
||||
{
|
||||
|
||||
public function insert($table, $bind, $on_duplicate = array())
|
||||
|
@ -15,10 +15,72 @@
|
||||
*/
|
||||
class MySQLiStatement extends DbStatement
|
||||
{
|
||||
|
||||
|
||||
protected $map = null;
|
||||
|
||||
public function bindParam($param, &$value)
|
||||
{
|
||||
if ($this->map === null) {
|
||||
$this->mapPlaceholders();
|
||||
}
|
||||
if (count($this->map) > 0) {
|
||||
if (!is_string($param) && !is_int($param)) {
|
||||
throw new GeneralException('Placeholder must be an integer or string');
|
||||
}
|
||||
if (is_object($value) && ! ($value instanceof DbExpr)) {
|
||||
throw new GeneralException('Objects excepts DbExpr not allowed.');
|
||||
}
|
||||
if (isset($this->map[$param])) {
|
||||
$this->params[$param] = &$value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
protected function mapPlaceholders()
|
||||
{
|
||||
$matches = array();
|
||||
if(preg_match_all('/(\?|:[A-z0-9_]+)/u', $this->request, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
$noname = 0;
|
||||
foreach ($matches[0] as $id=>$match) {
|
||||
$match[2] = $matches[1][$id][0];
|
||||
$name = ($match[2][0] === ':') ? ltrim($match[2], ':') : $noname++;
|
||||
$this->map[$name]['placeholder'] = $match[0];
|
||||
$this->map[$name]['offset'][] = $match[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function assemble()
|
||||
{
|
||||
if (empty($this->map)) {
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
$query = $this->request;
|
||||
$placeholders = array();
|
||||
foreach($this->map as $name => $place) {
|
||||
$value = $this->driver->quote($this->params[$name]);
|
||||
foreach ($place['offset'] as $offset) {
|
||||
$placeholders[$offset] = array('placeholder' => $place['placeholder'], 'value' => $value);
|
||||
}
|
||||
}
|
||||
|
||||
ksort($placeholders);
|
||||
|
||||
$increment = 0;
|
||||
foreach($placeholders as $current_offset => $placeholder) {
|
||||
$offset = $current_offset + $increment;
|
||||
$length = mb_strlen($placeholder['placeholder']);
|
||||
$query = mb_substr($query, 0, $offset) . $placeholder['value'] . mb_substr($query, $offset + $length);
|
||||
$increment = (($increment - $length) + mb_strlen($placeholder['value']));
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches single row
|
||||
*
|
||||
*
|
||||
* @param mixed $style
|
||||
* @return mixed
|
||||
*/
|
||||
@ -27,7 +89,7 @@ class MySQLiStatement extends DbStatement
|
||||
if (!$this->result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
$row = false;
|
||||
switch ($style) {
|
||||
case Db::FETCH_OBJ:
|
||||
@ -47,7 +109,7 @@ class MySQLiStatement extends DbStatement
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
*/
|
||||
@ -55,7 +117,19 @@ class MySQLiStatement extends DbStatement
|
||||
{
|
||||
return $this->result->fetch_object($class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function fetchPairs()
|
||||
{
|
||||
$data = array();
|
||||
while ($row = $this->fetch(Db::FETCH_NUM)) {
|
||||
$data[$row[0]] = $row[1];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
if ($this->result !== null) {
|
||||
@ -63,12 +137,12 @@ class MySQLiStatement extends DbStatement
|
||||
$this->result = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function affectedRows()
|
||||
{
|
||||
return $this->driver->getConnection()->affected_rows;
|
||||
}
|
||||
|
||||
|
||||
public function numRows()
|
||||
{
|
||||
if ($this->result) {
|
||||
@ -76,22 +150,22 @@ class MySQLiStatement extends DbStatement
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function driverExecute($sql)
|
||||
|
||||
protected function driverExecute($request)
|
||||
{
|
||||
/**
|
||||
* @var MySQLi
|
||||
*/
|
||||
$mysqli = $this->driver->getConnection();
|
||||
if (DEBUG) {
|
||||
$profiler = Profiler::getInstance()->profilerCommand('MySQL', $sql);
|
||||
$result = $mysqli->query($sql);
|
||||
$profiler = Profiler::getInstance()->profilerCommand('MySQL', $request);
|
||||
$result = $mysqli->query($request);
|
||||
$profiler->end();
|
||||
} else {
|
||||
$result = $mysqli->query($sql);
|
||||
$result = $mysqli->query($request);
|
||||
}
|
||||
if ($result === false) {
|
||||
$message = $mysqli->error . "\nQuery: \"" . $sql . '"';
|
||||
$message = $mysqli->error . "\nQuery: \"" . $request . '"';
|
||||
throw new GeneralException($message, $mysqli->errno);
|
||||
}
|
||||
if ($result instanceof MySQLi_Result) {
|
||||
|
14
model/NoSqlDbDriver.php
Normal file
14
model/NoSqlDbDriver.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright NetMonsters <team@netmonsters.ru>
|
||||
* @link http://netmonsters.ru
|
||||
* @package Majestic
|
||||
* @subpackage db
|
||||
* @since 2011-11-11
|
||||
*/
|
||||
|
||||
abstract class NoSqlDbDriver extends DbDriver
|
||||
{
|
||||
|
||||
abstract function find($collection, $condition = array(), $fields = array());
|
||||
}
|
168
model/SqlDbDriver.php
Normal file
168
model/SqlDbDriver.php
Normal file
@ -0,0 +1,168 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright NetMonsters <team@netmonsters.ru>
|
||||
* @link http://netmonsters.ru
|
||||
* @package Majestic
|
||||
* @subpackage db
|
||||
* @since 2011-11-11
|
||||
*/
|
||||
|
||||
abstract class SqlDbDriver extends DbDriver
|
||||
{
|
||||
|
||||
protected $identifier_quote = '`';
|
||||
|
||||
|
||||
|
||||
public function beginTransaction()
|
||||
{
|
||||
$this->connect();
|
||||
$this->driverBeginTransaction();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function commit()
|
||||
{
|
||||
$this->connect();
|
||||
$this->driverCommitTransaction();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function rollback()
|
||||
{
|
||||
$this->connect();
|
||||
$this->driverRollbackTransaction();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param mixed $bind
|
||||
* @param mixed $on_duplicate
|
||||
* @return int Affected rows count
|
||||
*/
|
||||
public function insert($table, $data, $on_duplicate = array())
|
||||
{
|
||||
$columns = array();
|
||||
foreach ($data as $col => $val) {
|
||||
$columns[] = $this->quoteIdentifier($col);
|
||||
}
|
||||
$values = array_values($data);
|
||||
|
||||
$sql = 'INSERT INTO ' . $this->quoteIdentifier($table)
|
||||
. ' (' . implode(', ', $columns) . ') VALUES (' . $this->quote($values) . ')';
|
||||
return $this->query($sql)->affectedRows();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param array $bind
|
||||
* @param mixed $where
|
||||
* @return int
|
||||
*/
|
||||
public function update($table, $data, $condition = '')
|
||||
{
|
||||
$set = array();
|
||||
foreach ($data as $col => $val) {
|
||||
$set[] = $this->quoteIdentifier($col) . '=' . $this->quote($val);
|
||||
}
|
||||
$where = $this->whereExpr($condition);
|
||||
$sql = 'UPDATE ' . $this->quoteIdentifier($table) . ' SET ' . implode(', ', $set)
|
||||
. (($where) ? (' WHERE ' . $where) : '');
|
||||
return $this->query($sql)->affectedRows();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param mixed $where
|
||||
* @return int
|
||||
*/
|
||||
public function delete($table, $condition = '')
|
||||
{
|
||||
$where = $this->whereExpr($condition);
|
||||
$sql = 'DELETE FROM ' . $this->quoteIdentifier($table) . (($where) ? (' WHERE ' . $where) : '');
|
||||
return $this->query($sql)->affectedRows();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
public function quote($value)
|
||||
{
|
||||
if ($value instanceof DbExpr) {
|
||||
return (string) $value;
|
||||
}
|
||||
if (is_array($value)) {
|
||||
foreach ($value as &$val) {
|
||||
$val = $this->quote($val);
|
||||
}
|
||||
return implode(', ', $value);
|
||||
}
|
||||
return $this->driverQuote($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ident
|
||||
* @return string
|
||||
*/
|
||||
public function quoteIdentifier($ident)
|
||||
{
|
||||
$ident = explode('.', $ident);
|
||||
if (!is_array($ident)) {
|
||||
$ident = array($ident);
|
||||
}
|
||||
foreach ($ident as &$segment) {
|
||||
$segment = $this->identifier_quote . $segment . $this->identifier_quote;
|
||||
}
|
||||
return implode('.', $ident);
|
||||
}
|
||||
|
||||
public function quoteInto($text, $value)
|
||||
{
|
||||
$pos = mb_strpos($text, '?');
|
||||
if ($pos === false) {
|
||||
return $text;
|
||||
}
|
||||
return mb_substr($text, 0, $pos) . $this->quote($value) . mb_substr($text, $pos + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $where
|
||||
* @return string
|
||||
*/
|
||||
protected function whereExpr($where)
|
||||
{
|
||||
if (empty($where)) {
|
||||
return $where;
|
||||
}
|
||||
|
||||
if (!is_array($where)) {
|
||||
$where = array($where);
|
||||
}
|
||||
foreach ($where as $cond => &$term) {
|
||||
if (is_int($cond)) {
|
||||
if ($term instanceof DbExpr) {
|
||||
$term = (string) $term;
|
||||
}
|
||||
} else {
|
||||
$term = $this->quoteInto($cond, $term);
|
||||
}
|
||||
}
|
||||
return implode(' AND ', $where);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DbStatement
|
||||
*/
|
||||
|
||||
abstract protected function driverQuote($value);
|
||||
|
||||
abstract protected function driverBeginTransaction();
|
||||
|
||||
abstract protected function driverCommitTransaction();
|
||||
|
||||
abstract protected function driverRollbackTransaction();
|
||||
|
||||
}
|
||||
|
173
model/SqlModel.php
Normal file
173
model/SqlModel.php
Normal file
@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Класс модели данных
|
||||
*
|
||||
* @copyright NetMonsters <team@netmonsters.ru>
|
||||
* @link http://netmonsters.ru
|
||||
* @package Majestic
|
||||
* @subpackage Model
|
||||
* @since 2011-11-11
|
||||
*/
|
||||
|
||||
abstract class SqlModel extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $ident
|
||||
* @return string Quoted identifier.
|
||||
*/
|
||||
public function identify($ident)
|
||||
{
|
||||
return $this->db->quoteIdentifier($ident);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @return string Quoted value.
|
||||
*/
|
||||
public function quote($value)
|
||||
{
|
||||
return $this->db->quote($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return object
|
||||
*/
|
||||
public function get($id)
|
||||
{
|
||||
$sql = 'SELECT * FROM :table WHERE :pk=?';
|
||||
return $this->fetch($sql, $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param mixed $where
|
||||
* @return int Number of affected rows
|
||||
*/
|
||||
public function update($data, $where)
|
||||
{
|
||||
if (is_int($where) || $where === (string) (int) $where) {
|
||||
$where = $this->identify($this->key) . '=' . (int) $where;
|
||||
}
|
||||
return parent::update($data, $where);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id Int id
|
||||
* @return int Number of affected rows
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
$where = $this->identify($this->key) . '=' . (int) $id;
|
||||
return $this->db->delete($this->table(), $where);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates order sql string
|
||||
*
|
||||
* @param array $params
|
||||
* @param array $sortable
|
||||
* @return string
|
||||
*/
|
||||
protected function order($params, $sortable = array('id'))
|
||||
{
|
||||
$sql = '';
|
||||
if (isset($params['sort'])) {
|
||||
$order = (isset($params['order']) && $params['order'] == 'desc') ? 'DESC' : 'ASC';
|
||||
if (in_array($params['sort'], $sortable)) {
|
||||
$sql = ' ORDER BY ' . $this->identify($params['sort']) . ' ' . $order;
|
||||
}
|
||||
}
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches using like
|
||||
*
|
||||
* @param array $params
|
||||
* @param array $searchable
|
||||
* @param string $table_prefix
|
||||
* @return string
|
||||
*/
|
||||
protected function search($params, $searchable = array('id'), $table_prefix = '')
|
||||
{
|
||||
$sql = '';
|
||||
if (isset($params['q']) && isset($params['qt']) && in_array($params['qt'], $searchable)) {
|
||||
if ($table_prefix) {
|
||||
$sql = $table_prefix . '.';
|
||||
}
|
||||
$sql .= $this->identify($params['qt']) . ' LIKE ' . $this->quote('%' . $params['q'] . '%');
|
||||
}
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method appends to params table and primary key.
|
||||
* So they can be accessed thru `:table` and `:pk` placeholders.
|
||||
*
|
||||
* @return DbStatement
|
||||
*/
|
||||
protected function query($sql, $params = array())
|
||||
{
|
||||
if (!is_array($params)) {
|
||||
$params = array($params);
|
||||
}
|
||||
$params = array(
|
||||
'table' => new DbExpr($this->identify($this->table())),
|
||||
'pk' => new DbExpr($this->identify($this->key)),
|
||||
) + $params;
|
||||
return $this->db->query($sql, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array $params
|
||||
* @param string $field
|
||||
* @param CacheKey $cache_key
|
||||
*/
|
||||
protected function fetchField($data, $params = array(), $field, $cache_key = null)
|
||||
{
|
||||
if (!$cache_key || !$result = $cache_key->get()) {
|
||||
$result = $this->query($data, $params)->fetchField($field);
|
||||
if ($cache_key) {
|
||||
$cache_key->set($result);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array $params
|
||||
* @param CacheKey $cache_key
|
||||
*/
|
||||
protected function fetch($data, $params = array(), $cache_key = null)
|
||||
{
|
||||
if (!$cache_key || !$result = $cache_key->get()) {
|
||||
$result = $this->query($data, $params)->fetch();
|
||||
if ($cache_key) {
|
||||
$cache_key->set($result);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array $params
|
||||
* @param CacheKey $cache_key
|
||||
*/
|
||||
protected function fetchAll($data, $params = array(), $cache_key = null)
|
||||
{
|
||||
if (!$cache_key || !$result = $cache_key->get()) {
|
||||
$result = $this->query($data, $params)->fetchAll();
|
||||
if ($cache_key) {
|
||||
$cache_key->set($result);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
BIN
model_class_diadram.png
Normal file
BIN
model_class_diadram.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
@ -9,7 +9,7 @@
|
||||
* @filesource $URL$
|
||||
*/
|
||||
|
||||
class SessionModel extends Model
|
||||
class SessionModel extends SqlModel
|
||||
{
|
||||
|
||||
protected $life_time;
|
||||
|
@ -44,65 +44,7 @@ class DbStatementTest extends PHPUnit_Framework_TestCase
|
||||
public function testConstruct()
|
||||
{
|
||||
$this->assertAttributeEquals($this->driver, 'driver', $this->stmt);
|
||||
$this->assertAttributeEquals($this->sql, 'sql', $this->stmt);
|
||||
}
|
||||
|
||||
public function testBindParam()
|
||||
{
|
||||
$val = $this->getMockBuilder('DbExpr')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->assertFalse($this->stmt->bindParam('var', $val));
|
||||
$this->assertTrue($this->stmt->bindParam('place', $val));
|
||||
}
|
||||
|
||||
/**
|
||||
* @TODO: change Exception Message 'Placeholder must be an array or string' - no arrays available
|
||||
*/
|
||||
public function testBindParamExceptionParam()
|
||||
{
|
||||
$val = 1;
|
||||
$this->setExpectedException('GeneralException', 'Placeholder must be an array or string');
|
||||
$this->stmt->bindParam(array(), $val);
|
||||
}
|
||||
|
||||
|
||||
public function testBindParamExceptionWrongObject()
|
||||
{
|
||||
$val = $this->getMock('NotDbExpr');
|
||||
$this->setExpectedException('GeneralException', 'Objects excepts DbExpr not allowed.');
|
||||
$this->stmt->bindParam('paa', $val);
|
||||
}
|
||||
|
||||
public function testExecute()
|
||||
{
|
||||
$this->stmt
|
||||
->expects($this->once())
|
||||
->method('driverExecute')
|
||||
->with($this->anything())
|
||||
->will($this->returnCallback(array($this, 'dbStatementAssemble')));
|
||||
|
||||
$this->driver
|
||||
->expects($this->any())
|
||||
->method('quote')
|
||||
->with($this->anything())
|
||||
->will($this->returnCallback(array($this, 'driverQuote')));
|
||||
|
||||
$result = $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
|
||||
$this->assertSame('SELECT * place_val FROM place_val AND new_val', $result);
|
||||
}
|
||||
|
||||
public function testExecuteNoPlaceholders()
|
||||
{
|
||||
$this->sql = 'PLAIN SQL';
|
||||
$this->stmt = $this->getMockForAbstractClass('DbStatement', array($this->driver, $this->sql));
|
||||
$this->stmt
|
||||
->expects($this->once())
|
||||
->method('driverExecute')
|
||||
->with($this->anything())
|
||||
->will($this->returnCallback(array($this, 'dbStatementAssemble')));
|
||||
$result = $this->stmt->execute(array());
|
||||
$this->assertSame('PLAIN SQL', $result);
|
||||
$this->assertAttributeEquals($this->sql, 'request', $this->stmt);
|
||||
}
|
||||
|
||||
public function testFetch()
|
||||
@ -124,19 +66,9 @@ class DbStatementTest extends PHPUnit_Framework_TestCase
|
||||
$this->assertSame(11, $result[0]->one);
|
||||
$this->assertSame(32, $result[2]->two);
|
||||
|
||||
reset($this->testData);
|
||||
$result = $this->stmt->fetchPairs();
|
||||
$this->assertSame(31, $result['one']);
|
||||
}
|
||||
|
||||
public function dbStatementAssemble($val)
|
||||
{
|
||||
return $val;
|
||||
}
|
||||
|
||||
public function driverQuote($val)
|
||||
{
|
||||
return $val;
|
||||
// reset($this->testData);
|
||||
// $result = $this->stmt->fetchPairs();
|
||||
// $this->assertEquals(31, $result['one']);
|
||||
}
|
||||
|
||||
public function dbStatementFetch($style)
|
||||
|
312
tests/model/MongoDbCommandTest.php
Normal file
312
tests/model/MongoDbCommandTest.php
Normal file
@ -0,0 +1,312 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright NetMonsters <team@netmonsters.ru>
|
||||
* @link http://netmonsters.ru
|
||||
* @package Majestic
|
||||
* @subpackage UnitTests
|
||||
* @since 2011-11-10
|
||||
*
|
||||
* Unit tests for MongoDriver class
|
||||
*/
|
||||
|
||||
require_once dirname(__FILE__) . '/../../model/DbDriver.php';
|
||||
require_once dirname(__FILE__) . '/../../model/NoSqlDbDriver.php';
|
||||
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
|
||||
{
|
||||
|
||||
private $conf = array();
|
||||
|
||||
private $driver;
|
||||
|
||||
private $collection;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->conf = array(
|
||||
'hostname' => 'localhost',
|
||||
'database' => 'test',
|
||||
'username' => 'test',
|
||||
'password' => '1234',
|
||||
'port' => 27017
|
||||
);
|
||||
$this->driver = new MongoDriver($this->conf);
|
||||
$connection = $this->driver->getConnection();
|
||||
|
||||
$db = $connection->selectDB($this->conf['database']);
|
||||
$db->authenticate($this->conf['username'], $this->conf['password']);
|
||||
$collection = 'items';
|
||||
$db->dropCollection($collection);
|
||||
$this->collection = $db->selectCollection($collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testCommandFactory()
|
||||
{
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::FIND);
|
||||
$this->assertInstanceOf('MongoDbCommand', $cmd);
|
||||
$this->assertInstanceOf('FindMongoCommand', $cmd);
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::INSERT);
|
||||
$this->assertInstanceOf('MongoDbCommand', $cmd);
|
||||
$this->assertInstanceOf('InsertMongoCommand', $cmd);
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::UPDATE);
|
||||
$this->assertInstanceOf('MongoDbCommand', $cmd);
|
||||
$this->assertInstanceOf('UpdateMongoCommand', $cmd);
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::REMOVE);
|
||||
$this->assertInstanceOf('MongoDbCommand', $cmd);
|
||||
$this->assertInstanceOf('RemoveMongoCommand', $cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testFindCommand()
|
||||
{
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::FIND, $this->collection);
|
||||
$cmd->bindParam('condition', array('name' => 'bread'))->bindParam('fields', array());
|
||||
$result = $cmd->execute();
|
||||
$this->assertEquals(0, $result->count());
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::INSERT, $this->collection);
|
||||
$cmd
|
||||
->bindParam('data', array('name' => 'insert'))
|
||||
->bindParam('safe', true);
|
||||
$cmd->execute();
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::INSERT, $this->collection);
|
||||
$cmd
|
||||
->bindParam('data', array('name' => 'insert'))
|
||||
->bindParam('safe', true);
|
||||
$cmd->execute();
|
||||
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::FIND, $this->collection);
|
||||
$cmd->bindParam('condition', array('name' => 'insert'))->bindParam('fields', array());
|
||||
$this->assertEquals(2, $cmd->execute()->count());
|
||||
|
||||
$cmd
|
||||
->bindParam('condition', array('name' => 'insert'))
|
||||
->bindParam('fields', array())
|
||||
->bindParam('multiple', false);
|
||||
|
||||
$result = $cmd->execute();
|
||||
$this->assertEquals('insert', $result['name']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testFindCommandNotAllParamsBinded()
|
||||
{
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::FIND, $this->collection);
|
||||
$cmd->bindParam('condition', array('name' => 'bread'));
|
||||
$this->setExpectedException('GeneralException', 'FindMongoCommand error. Bind all required params first');
|
||||
$cmd->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testInsertCommand()
|
||||
{
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::INSERT, $this->collection);
|
||||
|
||||
$cmd
|
||||
->bindParam('data', array('name' => 'insert'))
|
||||
->bindParam('safe', true);
|
||||
|
||||
$this->assertFalse($cmd->getInsertId());
|
||||
|
||||
$this->assertArrayHasKey('n', $cmd->execute());
|
||||
$this->assertNotEmpty($cmd->getInsertId());
|
||||
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::FIND, $this->collection);
|
||||
$cmd->bindParam('condition', array('name' => 'insert'))->bindParam('fields', array());
|
||||
$result = $cmd->execute();
|
||||
$this->assertEquals(1, $result->count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testInsertCommandNotAllParamsBinded()
|
||||
{
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::INSERT, $this->collection);
|
||||
$this->setExpectedException('GeneralException', 'InsertMongoCommand error. Bind all required params first');
|
||||
$cmd->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testUpdateCommand()
|
||||
{
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::INSERT, $this->collection);
|
||||
$cmd
|
||||
->bindParam('data', array('name' => 'insert'))
|
||||
->bindParam('safe', true);
|
||||
$this->assertArrayHasKey('n', $cmd->execute());
|
||||
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::UPDATE, $this->collection);
|
||||
$cmd
|
||||
->bindParam('condition', array('name' => 'insert'))
|
||||
->bindParam('data', array('$set' => array('name' => 'update')))
|
||||
->bindParam('upsert', false)
|
||||
->bindParam('safe', true);
|
||||
$this->assertArrayHasKey('n', $cmd->execute());
|
||||
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::FIND, $this->collection);
|
||||
$cmd->bindParam('condition', array('name' => 'insert'))->bindParam('fields', array());
|
||||
$result = $cmd->execute();
|
||||
$this->assertEquals(0, $result->count());
|
||||
$cmd->bindParam('condition', array('name' => 'update'))->bindParam('fields', array());
|
||||
$result = $cmd->execute();
|
||||
$this->assertEquals(1, $result->count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testUpdateCommandNotAllParamsBinded()
|
||||
{
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::UPDATE, $this->collection);
|
||||
$cmd->bindParam('data', array('name' => 'bread'));
|
||||
$this->setExpectedException('GeneralException', 'UpdateMongoCommand error. Bind all required params first');
|
||||
$cmd->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testRemoveCommand()
|
||||
{
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::INSERT, $this->collection);
|
||||
$cmd
|
||||
->bindParam('data', array('name' => 'insert'))
|
||||
->bindParam('safe', true);
|
||||
$this->assertArrayHasKey('n', $cmd->execute());
|
||||
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::FIND, $this->collection);
|
||||
$cmd->bindParam('condition', array('name' => 'insert'))->bindParam('fields', array());
|
||||
$result = $cmd->execute();
|
||||
$this->assertEquals(1, $result->count());
|
||||
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::REMOVE, $this->collection);
|
||||
$cmd
|
||||
->bindParam('condition', array('name' => 'insert'))
|
||||
->bindParam('safe', true);
|
||||
$this->assertArrayHasKey('n', $cmd->execute());
|
||||
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::FIND, $this->collection);
|
||||
$cmd->bindParam('condition', array('name' => 'insert'))->bindParam('fields', array());
|
||||
$result = $cmd->execute();
|
||||
$this->assertEquals(0, $result->count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testRemoveCommandNotAllParamsBinded()
|
||||
{
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::REMOVE, $this->collection);
|
||||
$this->setExpectedException('GeneralException', 'RemoveMongoCommand error. Bind all required params first.');
|
||||
$cmd->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testCommandCommandNotAllParamsBinded()
|
||||
{
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::COMMAND, $this->collection);
|
||||
$this->setExpectedException('GeneralException', 'CommandMongoCommand error. Bind all required params first');
|
||||
$cmd->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testCommandCommandNotMongoDb()
|
||||
{
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::COMMAND, new CollectionMock());
|
||||
$cmd->bindParam('command', array());
|
||||
$this->assertFalse($cmd->execute());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testCommandCommand()
|
||||
{
|
||||
$col = new CollectionMock();
|
||||
$col->db = $this->getMock('MongoDb', array('command'), array(), 'SomeMongoMock', false);
|
||||
$col->db
|
||||
->expects($this->once())
|
||||
->method('command')
|
||||
->will($this->returnValue(true));
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::COMMAND, $col);
|
||||
$cmd->bindParam('command', array());
|
||||
$this->assertTrue($cmd->execute());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testToStringParamsNotSet()
|
||||
{
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::COMMAND, new CollectionMock());
|
||||
$this->assertSame('Command properties not set', $cmd->__toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testToString()
|
||||
{
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::COMMAND, new CollectionMock());
|
||||
$this->assertSame('Command properties not set', $cmd->__toString());
|
||||
$cmd->bindParam('command', array());
|
||||
$this->assertStringStartsWith('Collection: CollectionMock', $cmd->__toString());
|
||||
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::INSERT, $this->collection);
|
||||
$this->assertSame('Command properties not set', $cmd->__toString());
|
||||
$cmd
|
||||
->bindParam('data', array('name' => 'insert'))
|
||||
->bindParam('safe', true);
|
||||
$this->assertStringStartsWith('Collection: ', $cmd->__toString());
|
||||
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::FIND, $this->collection);
|
||||
$this->assertSame('Command properties not set', $cmd->__toString());
|
||||
$cmd->bindParam('condition', array('name' => 'insert'))->bindParam('fields', array());
|
||||
$this->assertStringStartsWith('Collection: ', $cmd->__toString());
|
||||
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::REMOVE, $this->collection);
|
||||
$this->assertSame('Command properties not set', $cmd->__toString());
|
||||
$cmd
|
||||
->bindParam('condition', array('name' => 'insert'))
|
||||
->bindParam('safe', true);
|
||||
$this->assertStringStartsWith('Collection: ', $cmd->__toString());
|
||||
|
||||
$cmd = MongoCommandBuilder::factory(MongoCommandBuilder::UPDATE, $this->collection);
|
||||
$this->assertSame('Command properties not set', $cmd->__toString());
|
||||
$cmd
|
||||
->bindParam('condition', array('name' => 'insert'))
|
||||
->bindParam('data', array('$set' => array('name' => 'update')))
|
||||
->bindParam('upsert', false)
|
||||
->bindParam('safe', true);
|
||||
$this->assertStringStartsWith('Collection: ', $cmd->__toString());
|
||||
}
|
||||
}
|
||||
|
||||
class CollectionMock
|
||||
{
|
||||
public $db = array();
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return 'CollectionMock';
|
||||
}
|
||||
}
|
343
tests/model/MongoDriverTest.php
Normal file
343
tests/model/MongoDriverTest.php
Normal file
@ -0,0 +1,343 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright NetMonsters <team@netmonsters.ru>
|
||||
* @link http://netmonsters.ru
|
||||
* @package Majestic
|
||||
* @subpackage UnitTests
|
||||
* @since 2011-11-10
|
||||
*
|
||||
* Unit tests for MongoDriver class
|
||||
*/
|
||||
|
||||
require_once dirname(__FILE__) . '/../../model/Db.php';
|
||||
require_once dirname(__FILE__) . '/../../model/DbDriver.php';
|
||||
require_once dirname(__FILE__) . '/../../model/NoSqlDbDriver.php';
|
||||
require_once dirname(__FILE__) . '/../../model/MongoDbCommand.php';
|
||||
require_once dirname(__FILE__) . '/../../model/DbStatement.php';
|
||||
require_once dirname(__FILE__) . '/../../model/MongoStatement.php';
|
||||
require_once dirname(__FILE__) . '/../../model/MongoDriver.php';
|
||||
require_once dirname(__FILE__) . '/../../exception/GeneralException.php';
|
||||
|
||||
class MongoDriverTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
private $conf = array();
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->conf = array(
|
||||
'hostname' => 'localhost',
|
||||
'database' => 'test',
|
||||
'username' => 'test',
|
||||
'password' => '1234',
|
||||
'port' => 27017
|
||||
);
|
||||
|
||||
$data = array(
|
||||
array(
|
||||
'name' => 'bread',
|
||||
'price' => 3.2,
|
||||
'quantity' => 10
|
||||
),
|
||||
array(
|
||||
'name' => 'eggs',
|
||||
'price' => 2.1,
|
||||
'quantity' => 20
|
||||
),
|
||||
array(
|
||||
'name' => 'fish',
|
||||
'price' => 13.2,
|
||||
'quantity' => 2
|
||||
),
|
||||
array(
|
||||
'name' => 'milk',
|
||||
'price' => 3.8,
|
||||
'quantity' => 1
|
||||
),
|
||||
array(
|
||||
'name' => 'eggs',
|
||||
'price' => 2.3,
|
||||
'quantity' => 5
|
||||
)
|
||||
);
|
||||
$connection = new Mongo('mongodb://' . $this->conf['hostname'] . ':' . $this->conf['port']);
|
||||
$db = $connection->selectDB($this->conf['database']);
|
||||
$db->authenticate($this->conf['username'], $this->conf['password']);
|
||||
$collection = 'items';
|
||||
$db->dropCollection($collection);
|
||||
$collection = $db->selectCollection($collection);
|
||||
foreach($data as $document) {
|
||||
$collection->insert($document);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testGetConnectionNoHostname()
|
||||
{
|
||||
unset($this->conf['hostname']);
|
||||
$this->setExpectedException('GeneralException', 'Configuration must have a "hostname"');
|
||||
$mongo = new MongoDriver($this->conf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testGetConnectionWrongPassword()
|
||||
{
|
||||
$this->conf['password'] = 'nopass';
|
||||
$mongo = new MongoDriver($this->conf);
|
||||
$this->setExpectedException('MongoConnectionException', 'Couldn\'t authenticate with database');
|
||||
$this->assertInstanceOf('MongoDB', $mongo->getConnection());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testGetConnection()
|
||||
{
|
||||
$mongo = new MongoDriver($this->conf);
|
||||
|
||||
$this->assertFalse($mongo->isConnected());
|
||||
$this->assertInstanceOf('Mongo', $mongo->getConnection());
|
||||
$this->assertTrue($mongo->isConnected());
|
||||
$mongo->getConnection();
|
||||
$mongo->disconnect();
|
||||
$this->assertFalse($mongo->isConnected());
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testFind()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
|
||||
$mongo = new MongoDriver($this->conf);
|
||||
$this->assertEquals(1, $mongo->find('items', array('name' => 'bread'))->numRows());
|
||||
$this->assertEquals(2, $mongo->find('items', array('name' => 'eggs'))->numRows());
|
||||
$eggs = $mongo->find('items', array('name' => 'eggs'));
|
||||
$egg = $eggs->fetch();
|
||||
$this->assertEquals(20, $egg->quantity);
|
||||
$egg = $eggs->fetchObject();
|
||||
$this->assertEquals('eggs', $egg->name);
|
||||
$this->assertFalse($eggs->fetchObject());
|
||||
|
||||
$this->assertEquals(3, $mongo->find('items', array('price' => array('$lt' => 3.5)))->numRows());
|
||||
$data = $mongo->find('items', array('price' => array('$lt' => 3.5)));
|
||||
$count = 0;
|
||||
while($row = $data->fetch(Db::FETCH_ASSOC)) {
|
||||
$count++;
|
||||
$this->assertLessThan(3.5, $row['price']);
|
||||
}
|
||||
$this->assertEquals(3, $count);
|
||||
$this->assertEquals(5, $mongo->find('items', array())->numRows());
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testOrderSkipLimit()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
|
||||
$mongo = new MongoDriver($this->conf);
|
||||
|
||||
$count = $mongo->find('items', array())->numRows();
|
||||
|
||||
$this->assertEquals(1, $mongo->find('items', array('name' => 'bread'))->numRows());
|
||||
$this->assertEquals(2, $mongo->find('items', array('name' => 'eggs'))->numRows());
|
||||
$mongo->insert('items', array('name' => 'fdsbssc'));
|
||||
$mongo->insert('items', array('name' => 'boc'));
|
||||
$mongo->insert('items', array('name' => 'abc'));
|
||||
$mongo->insert('items', array('name' => 'vcxxc'));
|
||||
$mongo->insert('items', array('name' => 'abbc'));
|
||||
$mongo->insert('items', array('name' => 'dsbssc'));
|
||||
$mongo->insert('items', array('name' => 'bssc'));
|
||||
|
||||
$data = $mongo->find('items', array());
|
||||
$this->assertEquals($count + 7, $data->numRows());
|
||||
$data->order(array('name' => 1));
|
||||
$this->assertEquals('abbc', $data->fetch()->name);
|
||||
$this->assertEquals('abc', $data->fetch()->name);
|
||||
$this->assertEquals('boc', $data->fetch()->name);
|
||||
$data = $mongo->find('items', array());
|
||||
$data->order(array('name' => -1));
|
||||
$data->skip(3);
|
||||
$data->limit(1);
|
||||
while($row = $data->fetch()) {
|
||||
$this->assertEquals('fdsbssc', $row->name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testCount()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
$mongo = new MongoDriver($this->conf);
|
||||
$this->assertEquals(5, $mongo->count('items'));
|
||||
$this->assertEquals(2, $mongo->count('items', array('name' => 'eggs')));
|
||||
$this->assertEquals(1, $mongo->count('items', array('name' => 'eggs'), 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testGet()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('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()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
|
||||
$mongo = new MongoDriver($this->conf);
|
||||
$this->assertEquals(1, $mongo->find('items', array('name' => 'bread'))->numRows());
|
||||
$this->assertEquals(0, $mongo->delete('items', array('name' => 'esggs')));
|
||||
$this->assertEquals(2, $mongo->delete('items', array('name' => 'eggs')));
|
||||
$this->assertEquals(1, $mongo->delete('items', array('name' => 'bread')));
|
||||
$this->assertEquals(0, $mongo->find('items', array('name' => 'bread'))->numRows());
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testInsert()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
|
||||
$mongo = new MongoDriver($this->conf);
|
||||
$this->assertEquals(1, $mongo->find('items', array('name' => 'bread'))->numRows());
|
||||
$this->assertEquals(0, $mongo->insert('items', array('name' => 'bread')));
|
||||
$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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testGetInsertId()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
|
||||
$mongo = new MongoDriver($this->conf);
|
||||
$this->assertEquals(0, $mongo->getInsertId());
|
||||
$this->assertEquals(1, $mongo->find('items', array('name' => 'bread'))->numRows());
|
||||
$this->assertEquals(0, $mongo->insert('items', array('name' => 'bread')));
|
||||
$this->assertEquals(2, $mongo->find('items', array('name' => 'bread'))->numRows());
|
||||
$id1 = $mongo->getInsertId();
|
||||
$this->assertNotEmpty($id1);
|
||||
$this->assertEquals(0, $mongo->insert('items', array('name' => 'bread')));
|
||||
$id2 = $mongo->getInsertId();
|
||||
$this->assertNotEmpty($id2);
|
||||
$this->assertNotEquals($id1, $id2);
|
||||
$this->assertEquals(3, $mongo->find('items', array('name' => 'bread'))->numRows());
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testUpdate()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
|
||||
$mongo = new MongoDriver($this->conf);
|
||||
$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();
|
||||
$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')));
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testUpsert()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testFindAndModify()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
|
||||
$mongo = new MongoDriver($this->conf);
|
||||
|
||||
$this->assertEquals(10, $mongo->get('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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testCommand()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
$mongo = new MongoDriver($this->conf);
|
||||
$result = $mongo->command('items', array('distinct' =>'items', 'key' => 'name'));
|
||||
$this->assertEquals(4, count($result->fetch(DB::FETCH_ASSOC)));
|
||||
}
|
||||
}
|
238
tests/model/MongoModelTest.php
Normal file
238
tests/model/MongoModelTest.php
Normal file
@ -0,0 +1,238 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright NetMonsters <team@netmonsters.ru>
|
||||
* @link http://netmonsters.ru
|
||||
* @package Majestic
|
||||
* @subpackage UnitTests
|
||||
* @since 2011-11-7
|
||||
*
|
||||
* Unit tests for MongoModel class
|
||||
*/
|
||||
|
||||
require_once dirname(__FILE__) . '/../../Registry.php';
|
||||
require_once dirname(__FILE__) . '/../../Config.php';
|
||||
require_once dirname(__FILE__) . '/../../cache/Cacher.php';
|
||||
require_once dirname(__FILE__) . '/../../model/DbExpr.php';
|
||||
require_once dirname(__FILE__) . '/../../model/Db.php';
|
||||
require_once dirname(__FILE__) . '/../../model/MongoDbCommand.php';
|
||||
require_once dirname(__FILE__) . '/../../model/DbStatement.php';
|
||||
require_once dirname(__FILE__) . '/../../model/MongoStatement.php';
|
||||
require_once dirname(__FILE__) . '/../../model/DbDriver.php';
|
||||
require_once dirname(__FILE__) . '/../../model/NoSqlDbDriver.php';
|
||||
require_once dirname(__FILE__) . '/../../model/MongoDriver.php';
|
||||
require_once dirname(__FILE__) . '/../../model/Model.php';
|
||||
require_once dirname(__FILE__) . '/../../model/MongoModel.php';
|
||||
|
||||
class MongoModelTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
private $model;
|
||||
|
||||
public function run(PHPUnit_Framework_TestResult $result = NULL)
|
||||
{
|
||||
$this->setPreserveGlobalState(false);
|
||||
return parent::run($result);
|
||||
}
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$conf = array('default' => array('driver' => 'MongoDriver', 'hostname' => 'localhost', 'database' => 'test', 'username' => 'test', 'password' => '1234', 'port' => 27017));
|
||||
|
||||
$this->dbSetUp($conf);
|
||||
|
||||
Config::set('Db', $conf);
|
||||
if (!class_exists('MockModel')) {
|
||||
$this->model = $this->getMockForAbstractClass('MongoModel', array(), 'MongoMockModel');
|
||||
} else {
|
||||
$this->model = new MongoMockModel();
|
||||
}
|
||||
set_new_overload(array($this, 'newCallback'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testModel()
|
||||
{
|
||||
$this->assertInstanceOf('MongoMockModel', $this->model);
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testFind()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testGet()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testDelete()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('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());
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testDeleteAll()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
|
||||
$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());
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testCount()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
$this->assertEquals(5, $this->model->count());
|
||||
$this->assertEquals(2, $this->model->count(array('name' => 'eggs')));
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testFetch()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
|
||||
$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);
|
||||
|
||||
$result = $method->invoke($this->model, array('name' => 'bread'), array(), $mock);
|
||||
$this->assertEquals('bread', $result->name);
|
||||
|
||||
$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));
|
||||
$this->assertEquals('eggs', $result[0]->name);
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
$conf = array('driver' => 'MongoDriver', 'hostname' => 'localhost', 'database' => 'test', 'username' => 'test', 'password' => '1234', 'port' => 27017);
|
||||
|
||||
|
||||
$connection = new Mongo('mongodb://' . $conf['hostname'] . ':' . $conf['port']);
|
||||
$db = $connection->selectDB($conf['database']);
|
||||
$db->authenticate($conf['username'], $conf['password']);
|
||||
$collection = 'mongomock';
|
||||
$db->dropCollection($collection);
|
||||
}
|
||||
|
||||
protected function newCallback($className)
|
||||
{
|
||||
switch ($className) {
|
||||
case 'CacheKey':
|
||||
return 'MockCacheKey';
|
||||
default:
|
||||
return $className;
|
||||
}
|
||||
}
|
||||
|
||||
public function dbSetUp($conf)
|
||||
{
|
||||
$data = array(
|
||||
array(
|
||||
'name' => 'bread',
|
||||
'price' => 3.2,
|
||||
'quantity' => 10
|
||||
),
|
||||
array(
|
||||
'name' => 'eggs',
|
||||
'price' => 2.1,
|
||||
'quantity' => 20
|
||||
),
|
||||
array(
|
||||
'name' => 'fish',
|
||||
'price' => 13.2,
|
||||
'quantity' => 2
|
||||
),
|
||||
array(
|
||||
'name' => 'milk',
|
||||
'price' => 3.8,
|
||||
'quantity' => 1
|
||||
),
|
||||
array(
|
||||
'name' => 'eggs',
|
||||
'price' => 2.3,
|
||||
'quantity' => 5
|
||||
)
|
||||
);
|
||||
$connection = new Mongo('mongodb://' . $conf['default']['hostname'] . ':' . $conf['default']['port']);
|
||||
$db = $connection->selectDB($conf['default']['database']);
|
||||
$db->authenticate($conf['default']['username'], $conf['default']['password']);
|
||||
$collection = 'mongomock';
|
||||
$db->dropCollection($collection);
|
||||
$collection = $db->selectCollection($collection);
|
||||
foreach($data as $document) {
|
||||
$collection->insert($document);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
464
tests/model/MongoStatementTest.php
Normal file
464
tests/model/MongoStatementTest.php
Normal file
@ -0,0 +1,464 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright NetMonsters <team@netmonsters.ru>
|
||||
* @link http://netmonsters.ru
|
||||
* @package Majestic
|
||||
* @subpackage UnitTests
|
||||
* @since 2011-11-15
|
||||
*
|
||||
* Unit tests for MySQLiStatement class
|
||||
*/
|
||||
|
||||
require_once dirname(__FILE__) . '/../../util/profiler/CommandProfiler.php';
|
||||
require_once dirname(__FILE__) . '/../../util/profiler/Profiler.php';
|
||||
require_once dirname(__FILE__) . '/../../model/Db.php';
|
||||
require_once dirname(__FILE__) . '/../../model/DbDriver.php';
|
||||
require_once dirname(__FILE__) . '/../../model/DbStatement.php';
|
||||
require_once dirname(__FILE__) . '/../../model/MongoStatement.php';
|
||||
require_once dirname(__FILE__) . '/../../exception/GeneralException.php';
|
||||
|
||||
class MongoStatementTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
|
||||
private $driver;
|
||||
|
||||
private $stmt;
|
||||
|
||||
private $request;
|
||||
|
||||
private $testData = array(
|
||||
array('one' => 11, 'two' => 12),
|
||||
array('one' => 21, 'two' => 22),
|
||||
array('one' => 31, 'two' => 32),
|
||||
);
|
||||
|
||||
public function run(PHPUnit_Framework_TestResult $result = NULL)
|
||||
{
|
||||
$this->setPreserveGlobalState(false);
|
||||
return parent::run($result);
|
||||
}
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
if (!isset($this->stmt)) {
|
||||
$this->driver = $this->getMockBuilder('DbDriverMock')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('getConnection'))
|
||||
->getMock();
|
||||
$this->request = $this->getMockBuilder('MongoDbCommandMock')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('execute', 'bindParam', 'getInsertId'))
|
||||
->getMock();
|
||||
$this->stmt = new MongoStatement($this->driver, $this->request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testAffectedNumRowsNoResult()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
$this->assertFalse($this->stmt->affectedRows());
|
||||
$this->assertFalse($this->stmt->numRows());
|
||||
|
||||
$this->setDriverGetConnectionMethod();
|
||||
$this->request
|
||||
->expects($this->any())
|
||||
->method('execute')
|
||||
->will($this->returnValue(array()));
|
||||
$this->stmt->execute();
|
||||
$this->assertFalse($this->stmt->affectedRows());
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testAffectedNumRows()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
$this->setDriverGetConnectionMethod();
|
||||
$this->request
|
||||
->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue(array('n' => 20, 'ok' => 1)));
|
||||
$this->stmt->execute();
|
||||
$this->assertEquals(20, $this->stmt->affectedRows());
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testGetInsertId()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
$this->setDriverGetConnectionMethod();
|
||||
|
||||
$this->request = $this->getMockBuilder('InsertMongoCommand')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('execute', 'bindParam', 'getInsertId'))
|
||||
->getMock();
|
||||
|
||||
$this->request
|
||||
->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue(array('n' => 20, 'ok' => 1)));
|
||||
$this->request
|
||||
->expects($this->once())
|
||||
->method('getInsertId')
|
||||
->will($this->returnValue('4b0rrs'));
|
||||
|
||||
$this->stmt = new MongoStatement($this->driver, $this->request);
|
||||
|
||||
$this->stmt->execute();
|
||||
$this->assertEquals('4b0rrs', $this->stmt->getInsertId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testExecute()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
|
||||
$this->setDriverGetConnectionMethod()->setRequestExecuteMethod();
|
||||
$this->assertTrue($this->stmt->execute());
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testExecuteNoResult()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
$this->setDriverGetConnectionMethod();
|
||||
$this->request
|
||||
->expects($this->any())
|
||||
->method('execute')
|
||||
->will($this->returnValue(false));
|
||||
$this->setExpectedException('GeneralException', 'MongoDB request error.');
|
||||
$this->stmt->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testExecuteNoConnection()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
$this->driver
|
||||
->expects($this->any())
|
||||
->method('getConnection')
|
||||
->will($this->returnValue(false));
|
||||
$this->setExpectedException('GeneralException', 'No connection to MongoDB server.');
|
||||
$this->stmt->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testExecuteWithDebug()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', true);
|
||||
}
|
||||
$this->setDriverGetConnectionMethod()->setRequestExecuteMethod();
|
||||
$this->assertTrue($this->stmt->execute());
|
||||
$this->assertEquals(10, $this->stmt->numRows());
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testBindParam()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', true);
|
||||
}
|
||||
|
||||
$this->request
|
||||
->expects($this->once())
|
||||
->method('bindParam')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$this->setDriverGetConnectionMethod()->setRequestExecuteMethod();
|
||||
$this->assertTrue($this->stmt->execute(array('one' => 'two')));
|
||||
|
||||
$this->assertAttributeNotEquals(null, 'result', $this->stmt);
|
||||
$this->stmt->close();
|
||||
$this->assertAttributeEquals(null, 'result', $this->stmt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testFetch()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', true);
|
||||
}
|
||||
$this->assertFalse($this->stmt->fetch());
|
||||
|
||||
$this->setDriverGetConnectionMethod()->setRequestForFetch();
|
||||
|
||||
$this->stmt->execute();
|
||||
$result = $this->stmt->fetch();
|
||||
$this->assertEquals('prev', $result->next);
|
||||
$this->assertFalse($this->stmt->fetch());
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testFetchWithInitialArray()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', true);
|
||||
}
|
||||
$this->assertFalse($this->stmt->fetch());
|
||||
|
||||
$this->setDriverGetConnectionMethod();
|
||||
$this->request
|
||||
->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue(array('some' => 'val')));
|
||||
|
||||
$this->stmt->execute();
|
||||
$this->assertFalse($this->stmt->fetch());
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testFetchAssocFromCursor()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', true);
|
||||
}
|
||||
$this->assertFalse($this->stmt->fetch());
|
||||
|
||||
$this->setDriverGetConnectionMethod()->setRequestForFetch();
|
||||
|
||||
$this->stmt->execute();
|
||||
$result = $this->stmt->fetch(Db::FETCH_ASSOC);
|
||||
$this->assertEquals('prev', $result['next']);
|
||||
$this->assertEquals(array(), $this->stmt->fetch(Db::FETCH_ASSOC));
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testFetchAssocFromArray()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', true);
|
||||
}
|
||||
$this->assertFalse($this->stmt->fetch());
|
||||
|
||||
$this->setDriverGetConnectionMethod();
|
||||
$this->request
|
||||
->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue(array('some' => 'val')));
|
||||
|
||||
$this->stmt->execute();
|
||||
$result = $this->stmt->fetch(Db::FETCH_ASSOC);
|
||||
$this->assertEquals('val', $result['some']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testFetchWrongMode()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', true);
|
||||
}
|
||||
$this->assertFalse($this->stmt->fetch());
|
||||
|
||||
$this->setDriverGetConnectionMethod();
|
||||
$this->request
|
||||
->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue(array('some' => 'val')));
|
||||
|
||||
$this->stmt->execute();
|
||||
$this->setExpectedException('GeneralException', 'Invalid fetch mode "222" specified');
|
||||
$this->stmt->fetch(222);
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testSkipOrderLimit()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', true);
|
||||
}
|
||||
$this->setDriverGetConnectionMethod()->setRequestForFetch();
|
||||
|
||||
$this->stmt->execute();
|
||||
$this->assertInstanceOf('MongoStatement', $this->stmt->order(array('id' => 1)));
|
||||
$this->assertInstanceOf('MongoStatement', $this->stmt->limit(10));
|
||||
$this->assertInstanceOf('MongoStatement', $this->stmt->skip(1));
|
||||
|
||||
$this->stmt->fetch();
|
||||
$this->stmt->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testOrderException()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', true);
|
||||
}
|
||||
$this->setDriverGetConnectionMethod();
|
||||
$this->request
|
||||
->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue(array('some' => 'val')));
|
||||
|
||||
$this->stmt->execute();
|
||||
$this->setExpectedException('GeneralException', 'MongoStatement error. Impossible order results of opened cursor');
|
||||
$this->stmt->order(array('id' => 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testSkipException()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', true);
|
||||
}
|
||||
$this->setDriverGetConnectionMethod();
|
||||
$this->request
|
||||
->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue(array('some' => 'val')));
|
||||
|
||||
$this->stmt->execute();
|
||||
$this->setExpectedException('GeneralException', 'MongoStatement error. Impossible skip results of opened cursor');
|
||||
$this->stmt->skip(array('id' => 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group Mongo
|
||||
*/
|
||||
public function testLimitException()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', true);
|
||||
}
|
||||
$this->setDriverGetConnectionMethod();
|
||||
$this->request
|
||||
->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue(array('some' => 'val')));
|
||||
|
||||
$this->stmt->execute();
|
||||
$this->setExpectedException('GeneralException', 'MongoStatement error. Impossible limit results of opened cursor');
|
||||
$this->stmt->limit(array('id' => 1));
|
||||
}
|
||||
|
||||
private function setDriverGetConnectionMethod()
|
||||
{
|
||||
$mongoMock = $this->getMock('Mongo');
|
||||
|
||||
$this->driver
|
||||
->expects($this->any())
|
||||
->method('getConnection')
|
||||
->will($this->returnValue($mongoMock));
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setRequestExecuteMethod()
|
||||
{
|
||||
$resultMock = $this->getMockBuilder('MongoCursor')
|
||||
->setMethods(array('count'))
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$resultMock
|
||||
->expects($this->any())
|
||||
->method('count')
|
||||
->will($this->returnValue(10));
|
||||
|
||||
$this->request
|
||||
->expects($this->any())
|
||||
->method('execute')
|
||||
->will($this->returnValue($resultMock));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setRequestForFetch()
|
||||
{
|
||||
$resultMock = $this->getMockBuilder('MongoCursor')
|
||||
->setMethods(array('count', 'getNext', 'limit', 'sort', 'skip'))
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$resultMock
|
||||
->expects($this->any())
|
||||
->method('limit');
|
||||
$resultMock
|
||||
->expects($this->any())
|
||||
->method('sort');
|
||||
$resultMock
|
||||
->expects($this->any())
|
||||
->method('skip');
|
||||
$resultMock
|
||||
->expects($this->any())
|
||||
->method('count')
|
||||
->will($this->returnValue(10));
|
||||
$resultMock
|
||||
->expects($this->at(0))
|
||||
->method('getNext')
|
||||
->will($this->returnValue(array('next' => 'prev', '_id' => 10)));
|
||||
$resultMock
|
||||
->expects($this->at(1))
|
||||
->method('getNext')
|
||||
->will($this->returnValue(array()));
|
||||
|
||||
$this->request
|
||||
->expects($this->any())
|
||||
->method('execute')
|
||||
->will($this->returnValue($resultMock));
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
60
tests/model/MyDbDriver.php
Normal file
60
tests/model/MyDbDriver.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
abstract class MyDbDriver extends DbDriver
|
||||
{
|
||||
public function getInsertId($table = null, $key = null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function quoteIdentifier($param)
|
||||
{
|
||||
return $param;
|
||||
}
|
||||
|
||||
public function quote($param)
|
||||
{
|
||||
return $param;
|
||||
}
|
||||
|
||||
public function insert($table, $bind, $on_duplicate = array())
|
||||
{
|
||||
return $table;
|
||||
}
|
||||
|
||||
public function update($table, $bind, $where = '')
|
||||
{
|
||||
return $table;
|
||||
}
|
||||
|
||||
public function delete($table, $where = '')
|
||||
{
|
||||
return $table;
|
||||
}
|
||||
|
||||
public function query($sql, $params = array())
|
||||
{
|
||||
$conf = array('driver' => 'MockDbDriver', 'hostname' => 'somehost', 'database' => 'db', 'username' => 'test', 'password' => '1234');
|
||||
return new MockDbDriver($conf);
|
||||
}
|
||||
|
||||
public function execute()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function fetch()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function fetchField($field)
|
||||
{
|
||||
return $field;
|
||||
}
|
||||
|
||||
public function fetchAll()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ require_once dirname(__FILE__) . '/../../model/Db.php';
|
||||
require_once dirname(__FILE__) . '/../../model/DbStatement.php';
|
||||
require_once dirname(__FILE__) . '/../../model/MySQLiStatement.php';
|
||||
require_once dirname(__FILE__) . '/../../model/DbDriver.php';
|
||||
require_once dirname(__FILE__) . '/../../model/SqlDbDriver.php';
|
||||
require_once dirname(__FILE__) . '/../../model/MySQLiDriver.php';
|
||||
require_once dirname(__FILE__) . '/../../exception/GeneralException.php';
|
||||
|
||||
|
@ -26,6 +26,8 @@ class MySQLiStatementTest extends PHPUnit_Framework_TestCase
|
||||
|
||||
private $stmt;
|
||||
|
||||
private $sql;
|
||||
|
||||
private $testData = array(
|
||||
array('one' => 11, 'two' => 12),
|
||||
array('one' => 21, 'two' => 22),
|
||||
@ -51,6 +53,65 @@ class MySQLiStatementTest extends PHPUnit_Framework_TestCase
|
||||
}
|
||||
}
|
||||
|
||||
public function testBindParam()
|
||||
{
|
||||
$val = $this->getMockBuilder('DbExpr')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->assertFalse($this->stmt->bindParam('var', $val));
|
||||
$this->assertTrue($this->stmt->bindParam('place', $val));
|
||||
}
|
||||
|
||||
public function testBindParamExceptionParam()
|
||||
{
|
||||
$val = 1;
|
||||
$this->setExpectedException('GeneralException', 'Placeholder must be an integer or string');
|
||||
$this->stmt->bindParam(array(), $val);
|
||||
}
|
||||
|
||||
public function testBindParamExceptionWrongObject()
|
||||
{
|
||||
$val = $this->getMock('NotDbExpr');
|
||||
$this->setExpectedException('GeneralException', 'Objects excepts DbExpr not allowed.');
|
||||
$this->stmt->bindParam('paa', $val);
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
*/
|
||||
public function testExecute()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
|
||||
$this->driver
|
||||
->expects($this->any())
|
||||
->method('quote')
|
||||
->with($this->anything())
|
||||
->will($this->returnCallback(array($this, 'driverQuote')));
|
||||
|
||||
$this->setDriverGetConnectionMethod();
|
||||
|
||||
$result = $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
*/
|
||||
public function testExecuteNoPlaceholders()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
$this->setDriverGetConnectionMethod();
|
||||
|
||||
$this->sql = 'PLAIN SQL';
|
||||
$result = $this->stmt->execute(array());
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @group MySQL
|
||||
@ -112,6 +173,49 @@ class MySQLiStatementTest extends PHPUnit_Framework_TestCase
|
||||
* @runInSeparateProcess
|
||||
* @group MySQL
|
||||
*/
|
||||
public function testFetchPairs()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
define('DEBUG', false);
|
||||
}
|
||||
|
||||
$resultMock = $this->getMockBuilder('mysqli_result')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('fetch_array', 'close'))
|
||||
->setMockClassName('Mysqli_Result_Mock')
|
||||
->getMock();
|
||||
$resultMock
|
||||
->expects($this->at(0))
|
||||
->method('fetch_array')
|
||||
->will($this->returnValue(array('pair', 'value')));
|
||||
$resultMock
|
||||
->expects($this->at(1))
|
||||
->method('fetch_array')
|
||||
->will($this->returnValue(false));
|
||||
$resultMock
|
||||
->expects($this->any())
|
||||
->method('close')
|
||||
->will($this->returnValue(TRUE));
|
||||
|
||||
$mysqliMock = $this->getMock('MysqliDrvr', array('query'));
|
||||
$mysqliMock
|
||||
->expects($this->any())
|
||||
->method('query')
|
||||
->with($this->anything())
|
||||
->will($this->returnValue($resultMock));
|
||||
|
||||
$this->driver
|
||||
->expects($this->any())
|
||||
->method('getConnection')
|
||||
->will($this->returnValue($mysqliMock));
|
||||
|
||||
$this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
|
||||
$this->assertSame(array('pair' => 'value'), $this->stmt->fetchPairs());
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
*/
|
||||
public function testFetchWithDebug()
|
||||
{
|
||||
if (!defined('DEBUG')) {
|
||||
@ -192,7 +296,7 @@ class MySQLiStatementTest extends PHPUnit_Framework_TestCase
|
||||
$this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
|
||||
|
||||
$this->setExpectedException('GeneralException');
|
||||
|
||||
|
||||
$this->stmt->fetch(324);
|
||||
}
|
||||
|
||||
@ -226,7 +330,7 @@ class MySQLiStatementTest extends PHPUnit_Framework_TestCase
|
||||
->method('query')
|
||||
->with($this->anything())
|
||||
->will($this->returnValue($resultMock));
|
||||
|
||||
|
||||
$this->driver
|
||||
->expects($this->any())
|
||||
->method('getConnection')
|
||||
@ -254,4 +358,14 @@ class MySQLiStatementTest extends PHPUnit_Framework_TestCase
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function driverQuote($val)
|
||||
{
|
||||
return $val;
|
||||
}
|
||||
|
||||
public function dbStatementAssemble($val)
|
||||
{
|
||||
return $val;
|
||||
}
|
||||
|
||||
}
|
@ -13,23 +13,24 @@
|
||||
require_once dirname(__FILE__) . '/../../model/DbExpr.php';
|
||||
require_once dirname(__FILE__) . '/../../model/Db.php';
|
||||
require_once dirname(__FILE__) . '/../../model/DbDriver.php';
|
||||
require_once dirname(__FILE__) . '/../../model/SqlDbDriver.php';
|
||||
require_once dirname(__FILE__) . '/../../exception/GeneralException.php';
|
||||
|
||||
class DbDriverTest extends PHPUnit_Framework_TestCase
|
||||
class SqlDbDriverTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
private $driver;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$conf = array('hostname' => 'localhost', 'database' => 'db', 'username' => 'test', 'password' => '1234');
|
||||
$this->driver = $this->getMockForAbstractClass('DbDriver', array($conf));
|
||||
$this->driver = $this->getMockForAbstractClass('SqlDbDriver', array($conf));
|
||||
}
|
||||
|
||||
public function testConstruct()
|
||||
{
|
||||
$conf = array('hostname' => 'localhost', 'database' => 'db', 'username' => 'test', 'password' => '1234');
|
||||
try {
|
||||
$this->driver = $this->getMockForAbstractClass('DbDriver', array($conf));
|
||||
$this->driver = $this->getMockForAbstractClass('SqlDbDriver', array($conf));
|
||||
}
|
||||
catch (GeneralException $expected) {
|
||||
$this->fail($expected->getMessage());
|
||||
@ -43,7 +44,7 @@ class DbDriverTest extends PHPUnit_Framework_TestCase
|
||||
|
||||
$this->setExpectedException('GeneralException', 'Configuration must have a "username"');
|
||||
|
||||
$this->getMockForAbstractClass('DbDriver', array($conf));
|
||||
$this->getMockForAbstractClass('SqlDbDriver', array($conf));
|
||||
}
|
||||
|
||||
public function testGetConnection()
|
@ -16,9 +16,11 @@ require_once dirname(__FILE__) . '/../../cache/Cacher.php';
|
||||
require_once dirname(__FILE__) . '/../../model/DbExpr.php';
|
||||
require_once dirname(__FILE__) . '/../../model/Db.php';
|
||||
require_once dirname(__FILE__) . '/../../model/DbDriver.php';
|
||||
require_once dirname(__FILE__) . '/MyDbDriver.php';
|
||||
require_once dirname(__FILE__) . '/../../model/Model.php';
|
||||
require_once dirname(__FILE__) . '/../../model/SqlModel.php';
|
||||
|
||||
class ModelTest extends PHPUnit_Framework_TestCase
|
||||
class SqlModelTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
private $model;
|
||||
@ -32,7 +34,7 @@ class ModelTest extends PHPUnit_Framework_TestCase
|
||||
|
||||
Config::set('Db', $conf);
|
||||
if (!class_exists('MockModel')) {
|
||||
$this->model = $this->getMockForAbstractClass('Model', array(), 'MockModel');
|
||||
$this->model = $this->getMockForAbstractClass('SqlModel', array(), 'MockModel');
|
||||
} else {
|
||||
$this->model = new MockModel();
|
||||
}
|
||||
@ -41,7 +43,7 @@ class ModelTest extends PHPUnit_Framework_TestCase
|
||||
|
||||
public function testModel()
|
||||
{
|
||||
$this->assertInstanceOf('Model', $this->model);
|
||||
$this->assertInstanceOf('SqlModel', $this->model);
|
||||
}
|
||||
|
||||
public function testGetInsertId()
|
||||
@ -83,22 +85,19 @@ class ModelTest extends PHPUnit_Framework_TestCase
|
||||
|
||||
public function testOrder()
|
||||
{
|
||||
$model = new ReflectionClass('Model');
|
||||
$model = new ReflectionClass('SqlModel');
|
||||
$method = $model->getMethod('order');
|
||||
$method->setAccessible(true);
|
||||
$this->assertSame(' ORDER BY id DESC', $method->invoke($this->model, array('sort' => 'id', 'order' => 'desc')));
|
||||
$this->assertSame(' ORDER BY name ASC', $method->invoke($this->model, array('sort' => 'name'), array('id', 'name')));
|
||||
$this->assertEmpty($method->invoke($this->model, array()));
|
||||
|
||||
/**
|
||||
* @TODO: Model::order - check DESC condition - make case insensitive
|
||||
*/
|
||||
$this->assertSame(' ORDER BY name ASC', $method->invoke($this->model, array('sort' => 'name', 'order' => 'DESC'), array('id', 'name')));
|
||||
}
|
||||
|
||||
public function testSearch()
|
||||
{
|
||||
$model = new ReflectionClass('Model');
|
||||
$model = new ReflectionClass('SqlModel');
|
||||
$method = $model->getMethod('search');
|
||||
$method->setAccessible(true);
|
||||
$this->assertEmpty($method->invoke($this->model, array()));
|
||||
@ -108,7 +107,7 @@ class ModelTest extends PHPUnit_Framework_TestCase
|
||||
|
||||
public function testFetch()
|
||||
{
|
||||
$model = new ReflectionClass('Model');
|
||||
$model = new ReflectionClass('SqlModel');
|
||||
$method = $model->getMethod('fetch');
|
||||
$method->setAccessible(true);
|
||||
$key = $this->getCacheKeyMockGetSet();
|
||||
@ -117,7 +116,7 @@ class ModelTest extends PHPUnit_Framework_TestCase
|
||||
|
||||
public function testFetchField()
|
||||
{
|
||||
$model = new ReflectionClass('Model');
|
||||
$model = new ReflectionClass('SqlModel');
|
||||
$method = $model->getMethod('fetchField');
|
||||
$method->setAccessible(true);
|
||||
|
||||
@ -127,7 +126,7 @@ class ModelTest extends PHPUnit_Framework_TestCase
|
||||
|
||||
public function testFetchAll()
|
||||
{
|
||||
$model = new ReflectionClass('Model');
|
||||
$model = new ReflectionClass('SqlModel');
|
||||
$method = $model->getMethod('fetchAll');
|
||||
$method->setAccessible(true);
|
||||
|
||||
@ -166,7 +165,7 @@ class ModelTest extends PHPUnit_Framework_TestCase
|
||||
|
||||
public function testAddCleanCache()
|
||||
{
|
||||
$model = new ReflectionClass('Model');
|
||||
$model = new ReflectionClass('SqlModel');
|
||||
$method = $model->getMethod('addCleanCache');
|
||||
$method->setAccessible(true);
|
||||
|
||||
@ -179,7 +178,7 @@ class ModelTest extends PHPUnit_Framework_TestCase
|
||||
|
||||
public function testCleanCaches()
|
||||
{
|
||||
$model = new ReflectionClass('Model');
|
||||
$model = new ReflectionClass('SqlModel');
|
||||
$method = $model->getMethod('addCleanCache');
|
||||
$method->setAccessible(true);
|
||||
|
||||
@ -189,7 +188,7 @@ class ModelTest extends PHPUnit_Framework_TestCase
|
||||
$method->invoke($this->model, $key);
|
||||
$this->assertAttributeEquals(array($key, $key, $key), 'caches_clean', $this->model);
|
||||
|
||||
$model = new ReflectionClass('Model');
|
||||
$model = new ReflectionClass('SqlModel');
|
||||
$method = $model->getMethod('cleanCaches');
|
||||
$method->setAccessible(true);
|
||||
|
||||
@ -244,63 +243,4 @@ class ModelTest extends PHPUnit_Framework_TestCase
|
||||
return $className;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class MyDbDriver extends DbDriver
|
||||
{
|
||||
public function getInsertId($table = null, $key = null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function quoteIdentifier($param)
|
||||
{
|
||||
return $param;
|
||||
}
|
||||
|
||||
public function quote($param)
|
||||
{
|
||||
return $param;
|
||||
}
|
||||
|
||||
public function insert($table, $bind, $on_duplicate = array())
|
||||
{
|
||||
return $table;
|
||||
}
|
||||
|
||||
public function update($table, $bind, $where = '')
|
||||
{
|
||||
return $table;
|
||||
}
|
||||
|
||||
public function delete($table, $where = '')
|
||||
{
|
||||
return $table;
|
||||
}
|
||||
|
||||
public function query($sql, $params = array())
|
||||
{
|
||||
$conf = array('driver' => 'MockDbDriver', 'hostname' => 'localhost', 'database' => 'db', 'username' => 'test', 'password' => '1234');
|
||||
return new MockDbDriver($conf);
|
||||
}
|
||||
|
||||
public function execute()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function fetch()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function fetchField($field)
|
||||
{
|
||||
return $field;
|
||||
}
|
||||
|
||||
public function fetchAll()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
110
tests/session/SessionModelTest.php
Normal file
110
tests/session/SessionModelTest.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright NetMonsters <team@netmonsters.ru>
|
||||
* @link http://netmonsters.ru
|
||||
* @package Majestic
|
||||
* @subpackage UnitTests
|
||||
* @since 2011-11-15
|
||||
*
|
||||
* Unit tests for SessionModel class
|
||||
*/
|
||||
|
||||
require_once dirname(__FILE__) . '/../../Registry.php';
|
||||
require_once dirname(__FILE__) . '/../../Config.php';
|
||||
require_once dirname(__FILE__) . '/../../classes/Env.class.php';
|
||||
require_once dirname(__FILE__) . '/../../model/Db.php';
|
||||
require_once dirname(__FILE__) . '/../../model/DbDriver.php';
|
||||
require_once dirname(__FILE__) . '/../model/MyDbDriver.php';
|
||||
require_once dirname(__FILE__) . '/../../model/Model.php';
|
||||
require_once dirname(__FILE__) . '/../../model/SqlModel.php';
|
||||
require_once dirname(__FILE__) . '/../../session/Session.model.php';
|
||||
|
||||
class SessionModelTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
protected $model;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$conf = array('default' => array('driver' => 'MockDbDriver', 'hostname' => 'somehost', 'database' => 'db', 'username' => 'test', 'password' => '1234'));
|
||||
if (!class_exists('MockDbDriver')) {
|
||||
$this->getMockForAbstractClass('MyDbDriver', array($conf), 'MockDbDriver', false);
|
||||
}
|
||||
if (!class_exists('MockDbExpr')) {
|
||||
$this->getMock('DbExpr', array(), array(), 'MockDbExpr', false);
|
||||
}
|
||||
|
||||
Config::set('Db', $conf);
|
||||
|
||||
set_new_overload(array($this, 'newCallback'));
|
||||
}
|
||||
|
||||
public function testOpen()
|
||||
{
|
||||
$this->model = new SessionModel();
|
||||
$this->assertTrue($this->model->open('path', 'name'));
|
||||
}
|
||||
|
||||
public function testClose()
|
||||
{
|
||||
$this->model = new SessionModel();
|
||||
$this->assertTrue($this->model->close());
|
||||
}
|
||||
|
||||
public function testRead()
|
||||
{
|
||||
$this->model = new SessionModel();
|
||||
$this->assertEquals('data', $this->model->read(1));
|
||||
}
|
||||
|
||||
public function testWrite()
|
||||
{
|
||||
$this->model = new SessionModel();
|
||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||
$this->assertEmpty(Env::Server('HTTP_X_FORWARDED_FOR'));
|
||||
|
||||
$this->assertTrue($this->model->write(2, 'user|.s:20;id=2;id=2'));
|
||||
}
|
||||
|
||||
public function testDestroy()
|
||||
{
|
||||
$this->model = new SessionModel();
|
||||
$this->assertTrue($this->model->destroy(2));
|
||||
}
|
||||
public function testGc()
|
||||
{
|
||||
$this->model = new SessionModel();
|
||||
$this->assertTrue($this->model->gc(2000));
|
||||
}
|
||||
|
||||
public function testDestroyByUserId()
|
||||
{
|
||||
$this->model = new SessionModel();
|
||||
$this->assertEquals('session', $this->model->destroyByUserId(12));
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
Config::getInstance()->offsetUnset('Db');
|
||||
$config = new ReflectionClass('Db');
|
||||
$registry = $config->getProperty('connections');
|
||||
$registry->setAccessible(true);
|
||||
$registry->setValue('Db', array());
|
||||
unset_new_overload();
|
||||
}
|
||||
|
||||
protected function newCallback($className)
|
||||
{
|
||||
switch ($className) {
|
||||
case 'DbExpr':
|
||||
return 'MockDbExpr';
|
||||
case 'MockDbDriver':
|
||||
return 'MockDbDriver';
|
||||
case 'CacheKey':
|
||||
return 'MockCacheKey';
|
||||
default:
|
||||
return $className;
|
||||
}
|
||||
}
|
||||
}
|
BIN
uml_model.zargo
Normal file
BIN
uml_model.zargo
Normal file
Binary file not shown.
@ -20,14 +20,17 @@ class AutoloadBuilder
|
||||
|
||||
protected $dirs;
|
||||
|
||||
protected $exclude;
|
||||
|
||||
protected $handler;
|
||||
|
||||
protected $regex = '/(class|interface) ([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)/';
|
||||
|
||||
public function __construct($autoload, $dirs = array())
|
||||
public function __construct($autoload, $dirs = array(), $exclude = array())
|
||||
{
|
||||
$this->autoload = $autoload;
|
||||
$this->dirs = $dirs;
|
||||
$this->exclude = $exclude;
|
||||
}
|
||||
|
||||
public function build()
|
||||
@ -42,6 +45,10 @@ class AutoloadBuilder
|
||||
);
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
|
||||
if($this->isExcluded($file->getRealPath())) {
|
||||
continue;
|
||||
}
|
||||
// skip non php files
|
||||
$e = explode('.', $file->getFileName());
|
||||
if ((end($e) !== 'php') || $this->rightSubstr($file->getFileName(), 8) == 'Test.php') {
|
||||
@ -68,6 +75,17 @@ class AutoloadBuilder
|
||||
$this->closeAutoload();
|
||||
}
|
||||
|
||||
protected function isExcluded($file)
|
||||
{
|
||||
foreach ($this->exclude as $dir) {
|
||||
if (stripos($file, PATH . $dir) === 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
protected function openAutoload()
|
||||
{
|
||||
$this->write("<?php\n// This file is autogenerated by \n// " . __FILE__ . " script.\nreturn array(\n");
|
||||
|
Reference in New Issue
Block a user