Browse Source

added MongoStatement class, modified DbDriver hierarchy

master
Anton Grebnev 13 years ago
parent
commit
5bff74f20b
  1. 19
      model/DbDriver.php
  2. 79
      model/DbStatement.php
  3. 21
      model/MongoDbCommand.php
  4. 85
      model/MongoDriver.php
  5. 121
      model/MongoStatement.php
  6. 74
      model/MySQLiStatement.php
  7. 2
      model/NoSqlDbDriver.php
  8. 17
      model/SqlDbDriver.php

19
model/DbDriver.php

@ -49,6 +49,23 @@ abstract class DbDriver
return $this->connection; 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 methods */
abstract public function insert($table, $data); abstract public function insert($table, $data);
@ -56,6 +73,8 @@ abstract class DbDriver
abstract public function update($table, $data, $condition); abstract public function update($table, $data, $condition);
abstract public function delete($table, $condition); abstract public function delete($table, $condition);
abstract public function prepare($request);
abstract public function getInsertId($table = null, $key = null); abstract public function getInsertId($table = null, $key = null);

79
model/DbStatement.php

@ -20,38 +20,16 @@ abstract class DbStatement
/** /**
* @var string * @var string
*/ */
protected $sql;
protected $map = null;
protected $request;
protected $params = array(); protected $params = array();
protected $result; 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()); 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() public function __destruct()
{ {
$this->close(); $this->close();
@ -164,6 +101,10 @@ abstract class DbStatement
} }
/* Abstract methods */ /* Abstract methods */
abstract public function bindParam($param, &$value);
abstract protected function assemble();
abstract public function fetch($style = Db::FETCH_OBJ); abstract public function fetch($style = Db::FETCH_OBJ);
@ -181,5 +122,5 @@ abstract class DbStatement
/** /**
* @return bool * @return bool
*/ */
abstract protected function driverExecute($sql);
abstract protected function driverExecute($request);
} }

21
model/MongoDbCommand.php

@ -65,9 +65,15 @@ class FindMongoCommand extends MongoDbCommand
protected $fields; protected $fields;
protected $multiple = true;
protected function concreteExecute() 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() protected function checkParams()
@ -84,7 +90,7 @@ class InsertMongoCommand extends MongoDbCommand
{ {
protected $data; protected $data;
protected $safe;
protected $safe = true;
protected function concreteExecute() protected function concreteExecute()
{ {
@ -107,13 +113,16 @@ class UpdateMongoCommand extends MongoDbCommand
protected $data; protected $data;
protected $upsert;
protected $multiple = true;
protected $upsert = false;
protected $safe;
protected $safe = true;
protected function concreteExecute() 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() protected function checkParams()
@ -132,7 +141,7 @@ class RemoveMongoCommand extends MongoDbCommand
{ {
protected $condition; protected $condition;
protected $safe;
protected $safe = true;
protected function concreteExecute() protected function concreteExecute()
{ {

85
model/MongoDriver.php

@ -12,66 +12,90 @@
*/ */
class MongoDriver extends NoSqlDbDriver class MongoDriver extends NoSqlDbDriver
{ {
protected $last_inset_id = 0;
protected $last_insert_id = 0;
protected $db_name = 'admin'; protected $db_name = 'admin';
protected $db = null;
protected function getCollection($name) protected function getCollection($name)
{ {
if (!$this->connection) {
$this->connect();
}
return $this->connection->selectCollection($this->db, $name); 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()) 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) 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) 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) public function getInsertId($table = null, $key = null)
{ {
return $this->last_inset_id;
return $this->last_insert_id;
} }
public function isConnected() public function isConnected()
@ -110,4 +134,3 @@ class MongoDriver extends NoSqlDbDriver
$this->db = $this->connection->selectDB($this->config['db']); $this->db = $this->connection->selectDB($this->config['db']);
} }
} }

121
model/MongoStatement.php

@ -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;
}
}

74
model/MySQLiStatement.php

@ -15,7 +15,69 @@
*/ */
class MySQLiStatement extends DbStatement 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 * Fetches single row
* *
@ -77,21 +139,21 @@ class MySQLiStatement extends DbStatement
return false; return false;
} }
protected function driverExecute($sql)
protected function driverExecute($request)
{ {
/** /**
* @var MySQLi * @var MySQLi
*/ */
$mysqli = $this->driver->getConnection(); $mysqli = $this->driver->getConnection();
if (DEBUG) { if (DEBUG) {
$profiler = Profiler::getInstance()->profilerCommand('MySQL', $sql);
$result = $mysqli->query($sql);
$profiler = Profiler::getInstance()->profilerCommand('MySQL', $request);
$result = $mysqli->query($request);
$profiler->end(); $profiler->end();
} else { } else {
$result = $mysqli->query($sql);
$result = $mysqli->query($request);
} }
if ($result === false) { if ($result === false) {
$message = $mysqli->error . "\nQuery: \"" . $sql . '"';
$message = $mysqli->error . "\nQuery: \"" . $request . '"';
throw new Exception($message, $mysqli->errno); throw new Exception($message, $mysqli->errno);
} }
if ($result instanceof MySQLi_Result) { if ($result instanceof MySQLi_Result) {

2
model/NoSqlDbDriver.php

@ -10,5 +10,5 @@
abstract class NoSqlDbDriver extends DbDriver abstract class NoSqlDbDriver extends DbDriver
{ {
abstract function find($collection, $condition = array(), $fields = array(), $cache_key = null);
abstract function find($collection, $condition = array(), $fields = array());
} }

17
model/SqlDbDriver.php

@ -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 string $table
* @param mixed $bind * @param mixed $bind
* @param mixed $on_duplicate * @param mixed $on_duplicate
@ -171,7 +155,6 @@ abstract class SqlDbDriver extends DbDriver
/** /**
* @return DbStatement * @return DbStatement
*/ */
abstract public function prepare($sql);
abstract protected function driverQuote($value); abstract protected function driverQuote($value);

Loading…
Cancel
Save