added MongoStatement class, modified DbDriver hierarchy
This commit is contained in:
@ -49,6 +49,23 @@ abstract class DbDriver
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $request
|
||||
* @param mixed $params
|
||||
* @return DbStatement
|
||||
*/
|
||||
public function query($request, $params = array())
|
||||
{
|
||||
$this->connect();
|
||||
if (!is_array($params)) {
|
||||
$params = array($params);
|
||||
}
|
||||
$stmt = $this->prepare($request);
|
||||
$stmt->execute($params);
|
||||
return $stmt;
|
||||
}
|
||||
|
||||
|
||||
/* Abstract methods */
|
||||
|
||||
abstract public function insert($table, $data);
|
||||
@ -56,6 +73,8 @@ abstract class DbDriver
|
||||
abstract public function update($table, $data, $condition);
|
||||
|
||||
abstract public function delete($table, $condition);
|
||||
|
||||
abstract public function prepare($request);
|
||||
|
||||
abstract public function getInsertId($table = null, $key = null);
|
||||
|
||||
|
@ -20,38 +20,16 @@ abstract class DbStatement
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
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 Exception('Placeholder must be an array or string');
|
||||
}
|
||||
if (is_object($value) && ! ($value instanceof DbExpr)) {
|
||||
throw new Exception('Objects excepts DbExpr not allowed.');
|
||||
}
|
||||
if (isset($this->map[$param])) {
|
||||
$this->params[$param] = &$value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
$this->driver = $driver;
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -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();
|
||||
@ -164,6 +101,10 @@ abstract class DbStatement
|
||||
}
|
||||
|
||||
/* Abstract methods */
|
||||
|
||||
abstract public function bindParam($param, &$value);
|
||||
|
||||
abstract protected function assemble();
|
||||
|
||||
abstract public function fetch($style = Db::FETCH_OBJ);
|
||||
|
||||
@ -181,5 +122,5 @@ abstract class DbStatement
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
abstract protected function driverExecute($sql);
|
||||
abstract protected function driverExecute($request);
|
||||
}
|
||||
|
@ -65,9 +65,15 @@ class FindMongoCommand extends MongoDbCommand
|
||||
|
||||
protected $fields;
|
||||
|
||||
protected $multiple = true;
|
||||
|
||||
protected function concreteExecute()
|
||||
{
|
||||
return $this->collection->find($this->condition, $this->fields);
|
||||
if($this->multiple) {
|
||||
return $this->collection->find($this->condition, $this->fields);
|
||||
} else {
|
||||
return $this->collection->findOne($this->condition, $this->fields);
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkParams()
|
||||
@ -84,7 +90,7 @@ class InsertMongoCommand extends MongoDbCommand
|
||||
{
|
||||
protected $data;
|
||||
|
||||
protected $safe;
|
||||
protected $safe = true;
|
||||
|
||||
protected function concreteExecute()
|
||||
{
|
||||
@ -107,13 +113,16 @@ class UpdateMongoCommand extends MongoDbCommand
|
||||
|
||||
protected $data;
|
||||
|
||||
protected $upsert;
|
||||
protected $multiple = true;
|
||||
|
||||
protected $safe;
|
||||
protected $upsert = false;
|
||||
|
||||
protected $safe = true;
|
||||
|
||||
protected function concreteExecute()
|
||||
{
|
||||
return $this->collection->update($this->condition, $this->data, array('upsert' => $this->upsert, 'safe' => $this->safe));
|
||||
return $this->collection->update($this->condition, $this->data,
|
||||
array('multiple' => $this->multiple, 'upsert' => $this->upsert, 'safe' => $this->safe));
|
||||
}
|
||||
|
||||
protected function checkParams()
|
||||
@ -132,7 +141,7 @@ class RemoveMongoCommand extends MongoDbCommand
|
||||
{
|
||||
protected $condition;
|
||||
|
||||
protected $safe;
|
||||
protected $safe = true;
|
||||
|
||||
protected function concreteExecute()
|
||||
{
|
||||
|
@ -12,66 +12,90 @@
|
||||
*/
|
||||
class MongoDriver extends NoSqlDbDriver
|
||||
{
|
||||
|
||||
|
||||
protected $last_inset_id = 0;
|
||||
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 find($collection, $condition = array(), $fields = array(), $cache_key = null)
|
||||
public function find($collection, $condition = array(), $fields = array())
|
||||
{
|
||||
return $this->getCollection($collection)->find($condition, $fields);
|
||||
$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())
|
||||
{
|
||||
return $this->getCollection($collection)->findOne($condition, $fields);
|
||||
$command = MongoCommandBuilder::factory(MongoCommandBuilder::FIND, $this->getCollection($collection));
|
||||
$params = array(
|
||||
'condition' => $condition,
|
||||
'fields' => $fields,
|
||||
'multiple' => false
|
||||
);
|
||||
return $this->query($command, $params);
|
||||
}
|
||||
|
||||
public function insert($collection, $data, $safe = true)
|
||||
{
|
||||
$result = $this->getCollection($collection)->insert($data, array('safe' => $safe));
|
||||
if (isset($result['ok']) && $result['ok'] == 1) {
|
||||
$this->last_inset_id = (string) $data['_id'];
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
$command = MongoCommandBuilder::factory(MongoCommandBuilder::INSERT, $this->getCollection($collection));
|
||||
$params = array(
|
||||
'data' => $data,
|
||||
'safe' => $safe
|
||||
);
|
||||
|
||||
return $this->query($command, $params)->affectedRows();
|
||||
}
|
||||
|
||||
public function update($collection, $data, $condition = array(), $upsert = false, $safe = true)
|
||||
public function update($collection, $data, $condition = array(), $multiple = true, $upsert = false, $safe = true)
|
||||
{
|
||||
$result = $this->getCollection($collection)->update($condition, $data, array('upsert' => $upsert, 'safe' => $safe));
|
||||
$command = MongoCommandBuilder::factory(MongoCommandBuilder::UPDATE, $this->getCollection($collection));
|
||||
$params = array(
|
||||
'data' => $data,
|
||||
'condition' => $condition,
|
||||
'multiple' => $multiple,
|
||||
'upsert' => $upsert,
|
||||
'safe' => $safe
|
||||
);
|
||||
|
||||
if (isset($result['ok']) && $result['ok'] == 1) {
|
||||
if(isset($result['updatedExisting']) && isset($result['upserted'])) {
|
||||
$this->last_inset_id = (string) $result['upserted'];
|
||||
}
|
||||
return $result['n'];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return $this->query($command, $params)->affectedRows();
|
||||
}
|
||||
|
||||
public function delete($collection, $condition = array(), $safe = true)
|
||||
{
|
||||
$result = $this->getCollection($collection)->remove($condition, array('safe' => $safe));
|
||||
if (isset($result['ok']) && $result['ok'] == 1) {
|
||||
return $result['n'];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
$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_inset_id;
|
||||
return $this->last_insert_id;
|
||||
}
|
||||
|
||||
public function isConnected()
|
||||
@ -110,4 +134,3 @@ class MongoDriver extends NoSqlDbDriver
|
||||
$this->db = $this->connection->selectDB($this->config['db']);
|
||||
}
|
||||
}
|
||||
|
||||
|
121
model/MongoStatement.php
Normal file
121
model/MongoStatement.php
Normal file
@ -0,0 +1,121 @@
|
||||
<?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
|
||||
{
|
||||
|
||||
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 Exception('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()
|
||||
{
|
||||
// TODO: Implement close() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function affectedRows()
|
||||
{
|
||||
if (is_array($this->result)) {
|
||||
if (isset($this->result['ok']) && $this->result['ok'] == 1 && 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 MongoDbComand $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 Exception('MongoDB request error.');
|
||||
}
|
||||
if ($result instanceof MongoCursor || is_array($result)) {
|
||||
$this->result = $result;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
throw new Exception('No connection to MongoDB server.');
|
||||
}
|
||||
}
|
||||
|
||||
public function bindParam($param, &$value)
|
||||
{
|
||||
$this->request->bindParam($param, $value);
|
||||
}
|
||||
|
||||
protected function assemble()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
}
|
@ -15,7 +15,69 @@
|
||||
*/
|
||||
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 Exception('Placeholder must be an array or string');
|
||||
}
|
||||
if (is_object($value) && ! ($value instanceof DbExpr)) {
|
||||
throw new Exception('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
|
||||
*
|
||||
@ -77,21 +139,21 @@ 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 Exception($message, $mysqli->errno);
|
||||
}
|
||||
if ($result instanceof MySQLi_Result) {
|
||||
|
@ -10,5 +10,5 @@
|
||||
abstract class NoSqlDbDriver extends DbDriver
|
||||
{
|
||||
|
||||
abstract function find($collection, $condition = array(), $fields = array(), $cache_key = null);
|
||||
abstract function find($collection, $condition = array(), $fields = array());
|
||||
}
|
@ -36,22 +36,6 @@ abstract class SqlDbDriver extends DbDriver
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param mixed $params
|
||||
* @return DbStatement
|
||||
*/
|
||||
public function query($sql, $params = array())
|
||||
{
|
||||
$this->connect();
|
||||
if (!is_array($params)) {
|
||||
$params = array($params);
|
||||
}
|
||||
$stmt = $this->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
return $stmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param mixed $bind
|
||||
* @param mixed $on_duplicate
|
||||
@ -171,7 +155,6 @@ abstract class SqlDbDriver extends DbDriver
|
||||
/**
|
||||
* @return DbStatement
|
||||
*/
|
||||
abstract public function prepare($sql);
|
||||
|
||||
abstract protected function driverQuote($value);
|
||||
|
||||
|
Reference in New Issue
Block a user