Multi databases support, #12
git-svn-id: svn+ssh://code.netmonsters.ru/svn/majestic/branches/evo@113 4cb57b5f-5bbd-dd11-951b-001d605cbbc5
This commit is contained in:
67
Config.php
Normal file
67
Config.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright NetMonsters <team@netmonsters.ru>
|
||||||
|
* @link http://netmonsters.ru
|
||||||
|
* @package Majestic
|
||||||
|
* @subpackage Model
|
||||||
|
* @since 2010-02-17
|
||||||
|
* @version SVN: $Id$
|
||||||
|
* @filesource $URL$
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Config extends ArrayObject
|
||||||
|
{
|
||||||
|
|
||||||
|
private static $_instance = null;
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct($config = array())
|
||||||
|
{
|
||||||
|
parent::__construct($config, ArrayObject::ARRAY_AS_PROPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Config
|
||||||
|
*/
|
||||||
|
static public function getInstance()
|
||||||
|
{
|
||||||
|
if (is_null(self::$_instance)) {
|
||||||
|
self::$_instance = new Config();
|
||||||
|
}
|
||||||
|
return self::$_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public function get($name)
|
||||||
|
{
|
||||||
|
$instance = self::getInstance();
|
||||||
|
if (! $instance->offsetExists($name)) {
|
||||||
|
throw new Exception('Configuration variable "' . $name . '" undefined');
|
||||||
|
}
|
||||||
|
return $instance->offsetGet($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public function set($name, $value)
|
||||||
|
{
|
||||||
|
if (is_array($value)) {
|
||||||
|
$value = new ConfigArray($value);
|
||||||
|
}
|
||||||
|
self::getInstance()->offsetSet($name, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConfigArray extends ArrayObject
|
||||||
|
{
|
||||||
|
public function __construct($array)
|
||||||
|
{
|
||||||
|
parent::__construct($array, ArrayObject::ARRAY_AS_PROPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetGet($index)
|
||||||
|
{
|
||||||
|
if (! $this->offsetExists($index)) {
|
||||||
|
throw new Exception('Configuration variable "' . $index . '" undefined');
|
||||||
|
}
|
||||||
|
return parent::offsetGet($index);
|
||||||
|
}
|
||||||
|
}
|
65
model/Db.php
Normal file
65
model/Db.php
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright NetMonsters <team@netmonsters.ru>
|
||||||
|
* @link http://netmonsters.ru
|
||||||
|
* @package Majestic
|
||||||
|
* @subpackage db
|
||||||
|
* @since 2010-02-16
|
||||||
|
* @version SVN: $Id$
|
||||||
|
* @filesource $URL$
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Db
|
||||||
|
{
|
||||||
|
|
||||||
|
const FETCH_ASSOC = 2;
|
||||||
|
const FETCH_NUM = 3;
|
||||||
|
const FETCH_BOTH = 4;
|
||||||
|
const FETCH_OBJ = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Databases connections
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
static protected $connections = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect to database
|
||||||
|
*
|
||||||
|
* @param string $name Database name. If not set 'default' will be used.
|
||||||
|
* @param array $config Configuration array.
|
||||||
|
*
|
||||||
|
* @return DbDriver
|
||||||
|
*/
|
||||||
|
static public function connect($name = null, $config = null)
|
||||||
|
{
|
||||||
|
if ($name === null) {
|
||||||
|
$name = 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! isset(self::$connections[$name])) {
|
||||||
|
if (!$config) {
|
||||||
|
$config = Config::get('databases')->$name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! is_array($config)) {
|
||||||
|
throw new Exception('Connection parameters must be an array');
|
||||||
|
}
|
||||||
|
|
||||||
|
$driver = 'MySQLiDriver';
|
||||||
|
if (isset($config['driver'])) {
|
||||||
|
$driver = $config['driver'];
|
||||||
|
unset($config['driver']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$connection = new $driver($config);
|
||||||
|
|
||||||
|
if (! $connection instanceof DbDriver) {
|
||||||
|
throw new Exception('Database driver must extends DbDriver');
|
||||||
|
}
|
||||||
|
self::$connections[$name] = $connection;
|
||||||
|
}
|
||||||
|
return self::$connections[$name];
|
||||||
|
}
|
||||||
|
}
|
229
model/DbDriver.php
Normal file
229
model/DbDriver.php
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright NetMonsters <team@netmonsters.ru>
|
||||||
|
* @link http://netmonsters.ru
|
||||||
|
* @package Majestic
|
||||||
|
* @subpackage db
|
||||||
|
* @since 2010-02-16
|
||||||
|
* @version SVN: $Id$
|
||||||
|
* @filesource $URL$
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class DbDriver
|
||||||
|
{
|
||||||
|
|
||||||
|
protected $identifier_quote = '`';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database connection
|
||||||
|
*
|
||||||
|
* @var object
|
||||||
|
*/
|
||||||
|
protected $connection = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration data
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $config = array();
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct($config)
|
||||||
|
{
|
||||||
|
$this->checkConfig($config);
|
||||||
|
$this->config = $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkConfig($config)
|
||||||
|
{
|
||||||
|
$required = array('database', 'username', 'password', 'hostname');
|
||||||
|
foreach ($required as $option) {
|
||||||
|
if (!isset($config[$option])) {
|
||||||
|
throw new Exception('Configuration must have a "' . $option . '".');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 $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
|
||||||
|
* @return int Affected rows count
|
||||||
|
*/
|
||||||
|
public function insert($table, $bind)
|
||||||
|
{
|
||||||
|
$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 = 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 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return DbStatement
|
||||||
|
*/
|
||||||
|
abstract public function prepare($sql);
|
||||||
|
|
||||||
|
abstract public function getInsertId($table = null, $key = null);
|
||||||
|
|
||||||
|
abstract public function isConnected();
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
30
model/DbExpr.php
Normal file
30
model/DbExpr.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright NetMonsters <team@netmonsters.ru>
|
||||||
|
* @link http://netmonsters.ru
|
||||||
|
* @package Majestic
|
||||||
|
* @subpackage db
|
||||||
|
* @since 2010-02-19
|
||||||
|
* @version SVN: $Id$
|
||||||
|
* @filesource $URL$
|
||||||
|
*/
|
||||||
|
|
||||||
|
class DbExpr
|
||||||
|
{
|
||||||
|
|
||||||
|
protected $expression;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $expression
|
||||||
|
* @return DbExpr
|
||||||
|
*/
|
||||||
|
public function __construct($expression)
|
||||||
|
{
|
||||||
|
$this->expression = (string) $expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return $this->expression;
|
||||||
|
}
|
||||||
|
}
|
161
model/DbStatement.php
Normal file
161
model/DbStatement.php
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright NetMonsters <team@netmonsters.ru>
|
||||||
|
* @link http://netmonsters.ru
|
||||||
|
* @package Majestic
|
||||||
|
* @subpackage db
|
||||||
|
* @since 2010-02-19
|
||||||
|
* @version SVN: $Id$
|
||||||
|
* @filesource $URL$
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class DbStatement
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var DbDriver
|
||||||
|
*/
|
||||||
|
protected $driver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $sql;
|
||||||
|
|
||||||
|
protected $map = null;
|
||||||
|
|
||||||
|
protected $params = array();
|
||||||
|
|
||||||
|
protected $result;
|
||||||
|
|
||||||
|
public function __construct($driver, $sql)
|
||||||
|
{
|
||||||
|
$this->driver = $driver;
|
||||||
|
$this->sql = $sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $style
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function fetchAll($style = Db::FETCH_OBJ)
|
||||||
|
{
|
||||||
|
$data = array();
|
||||||
|
while ($row = $this->fetch($style)) {
|
||||||
|
$data[] = $row;
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $field
|
||||||
|
*/
|
||||||
|
public function fetchField($field)
|
||||||
|
{
|
||||||
|
$row = $this->fetch(Db::FETCH_ASSOC);
|
||||||
|
if (isset($row[$field])) {
|
||||||
|
return $row[$field];
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $params
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function execute($params = null)
|
||||||
|
{
|
||||||
|
if (is_array($params)) {
|
||||||
|
foreach ($params as $param => &$value) {
|
||||||
|
$this->bindParam($param, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Abstract methods */
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
135
model/Model.php
Normal file
135
model/Model.php
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Класс модели данных
|
||||||
|
*
|
||||||
|
* @copyright NetMonsters <team@netmonsters.ru>
|
||||||
|
* @link http://netmonsters.ru
|
||||||
|
* @package Majestic
|
||||||
|
* @subpackage Model
|
||||||
|
* @since 2010-02-16
|
||||||
|
* @version SVN: $Id$
|
||||||
|
* @filesource $URL$
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class Model
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DbDriver instance
|
||||||
|
*
|
||||||
|
* @var DbDriver
|
||||||
|
*/
|
||||||
|
protected $db;
|
||||||
|
|
||||||
|
protected $cache;
|
||||||
|
|
||||||
|
protected $table;
|
||||||
|
|
||||||
|
protected $connection = 'default';
|
||||||
|
|
||||||
|
protected $key = 'id';
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->db = Db::connect($this->connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getInsertId()
|
||||||
|
{
|
||||||
|
return $this->db->getInsertId($this->table(), $this->key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 ' . $this->identify($this->table())
|
||||||
|
. ' WHERE ' . $this->identify($this->key) . '=' . (int) $id;
|
||||||
|
return $this->db->query($sql)->fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
* @return int Affect row or id of inserted field.
|
||||||
|
*/
|
||||||
|
public function save($data)
|
||||||
|
{
|
||||||
|
$key = isset($data[$this->key]) ? $data[$this->key] : false;
|
||||||
|
$result = false;
|
||||||
|
if ($key) {
|
||||||
|
unset($data[$this->key]);
|
||||||
|
$result = $this->update($data, $this->identify($this->key) . '=' . (int) $id);
|
||||||
|
} else {
|
||||||
|
$result = $this->insert($data);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
* @return int Id of inserted row
|
||||||
|
*/
|
||||||
|
public function insert($data)
|
||||||
|
{
|
||||||
|
if (! $this->db->insert($this->table(), $data)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $this->getInsertId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
* @param mixed $where
|
||||||
|
* @return int Number of affected rows
|
||||||
|
*/
|
||||||
|
public function update($data, $where)
|
||||||
|
{
|
||||||
|
return $this->db->update($this->table(), $data, $where);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $where
|
||||||
|
* @return int Number of affected rows
|
||||||
|
*/
|
||||||
|
public function delete($where)
|
||||||
|
{
|
||||||
|
if (is_int($where)) {
|
||||||
|
$where = $this->identify($this->key) . '=' . (int) $where;
|
||||||
|
}
|
||||||
|
return $this->db->delete($this->table(), $where);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function table()
|
||||||
|
{
|
||||||
|
if (! $this->table) {
|
||||||
|
$this->table = rtrim(strtolower(get_class($this)), 'model');
|
||||||
|
}
|
||||||
|
return $this->table;
|
||||||
|
}
|
||||||
|
}
|
104
model/MySQLiDriver.php
Normal file
104
model/MySQLiDriver.php
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright NetMonsters <team@netmonsters.ru>
|
||||||
|
* @link http://netmonsters.ru
|
||||||
|
* @package Majestic
|
||||||
|
* @subpackage db
|
||||||
|
* @since 2010-02-17
|
||||||
|
* @version SVN: $Id$
|
||||||
|
* @filesource $URL$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property MySQLi $connection
|
||||||
|
*/
|
||||||
|
class MySQLiDriver extends DbDriver
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $sql
|
||||||
|
* @return DbStatement
|
||||||
|
*/
|
||||||
|
public function prepare($sql)
|
||||||
|
{
|
||||||
|
return new MySQLiStatement($this, $sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInsertId($table = null, $key = null)
|
||||||
|
{
|
||||||
|
return $this->connection->insert_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isConnected()
|
||||||
|
{
|
||||||
|
return ($this->connection instanceof MySQLi);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function disconnect()
|
||||||
|
{
|
||||||
|
if ($this->isConnected()) {
|
||||||
|
$this->connection->close();
|
||||||
|
}
|
||||||
|
$this->connection = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function connect()
|
||||||
|
{
|
||||||
|
if ($this->connection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$port = isset($this->config['port']) ? (int) $this->config['port'] : null;
|
||||||
|
$this->connection = mysqli_init();
|
||||||
|
$connected = @mysqli_real_connect($this->connection,
|
||||||
|
$this->config['hostname'],
|
||||||
|
$this->config['username'],
|
||||||
|
$this->config['password'],
|
||||||
|
$this->config['database'],
|
||||||
|
$port);
|
||||||
|
// Connection errors check
|
||||||
|
if (mysqli_connect_error()) {
|
||||||
|
throw new Exception(mysqli_connect_error(), mysqli_connect_errno());
|
||||||
|
}
|
||||||
|
|
||||||
|
$charset = (!empty($this->config['charset'])) ? $this->config['charset'] : 'utf8';
|
||||||
|
$this->connection->set_charset($charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function driverQuote($value)
|
||||||
|
{
|
||||||
|
if (is_int($value) || is_float($value)) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_bool($value)) {
|
||||||
|
var_dump($value);
|
||||||
|
return (int) $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value === null) {
|
||||||
|
return 'NULL';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->connect();
|
||||||
|
return '\'' . $this->connection->real_escape_string($value) . '\'';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function driverBeginTransaction()
|
||||||
|
{
|
||||||
|
$this->connect();
|
||||||
|
$this->connection->autocommit(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function driverCommitTransaction()
|
||||||
|
{
|
||||||
|
$this->connection->commit();
|
||||||
|
$this->connection->autocommit(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function driverRollbackTransaction()
|
||||||
|
{
|
||||||
|
$this->connection->rollback();
|
||||||
|
$this->connection->autocommit(true);
|
||||||
|
}
|
||||||
|
}
|
89
model/MySQLiStatement.php
Normal file
89
model/MySQLiStatement.php
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright NetMonsters <team@netmonsters.ru>
|
||||||
|
* @link http://netmonsters.ru
|
||||||
|
* @package Majestic
|
||||||
|
* @subpackage db
|
||||||
|
* @since 2010-02-19
|
||||||
|
* @version SVN: $Id$
|
||||||
|
* @filesource $URL$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property MySQLiDriver $driver
|
||||||
|
* @property MySQLi_Result $result
|
||||||
|
*/
|
||||||
|
class MySQLiStatement extends DbStatement
|
||||||
|
{
|
||||||
|
|
||||||
|
public function fetch($style = Db::FETCH_OBJ)
|
||||||
|
{
|
||||||
|
if (! $this->result) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$row = false;
|
||||||
|
switch ($style) {
|
||||||
|
case Db::FETCH_OBJ:
|
||||||
|
$row = $this->result->fetch_object();
|
||||||
|
break;
|
||||||
|
case Db::FETCH_NUM:
|
||||||
|
$row = $this->result->fetch_array(MYSQLI_NUM);
|
||||||
|
break;
|
||||||
|
case Db::FETCH_ASSOC:
|
||||||
|
$row = $this->result->fetch_assoc();
|
||||||
|
break;
|
||||||
|
case Db::FETCH_BOTH:
|
||||||
|
$row = $this->result->fetch_array(MYSQLI_BOTH);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception('Invalid fetch mode "' . $style . '" specified');
|
||||||
|
}
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $class
|
||||||
|
*/
|
||||||
|
public function fetchObject($class = 'stdClass')
|
||||||
|
{
|
||||||
|
return $this->result->fetch_object($class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function close()
|
||||||
|
{
|
||||||
|
if ($this->result !== null) {
|
||||||
|
$this->result->close();
|
||||||
|
$this->result = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function affectedRows()
|
||||||
|
{
|
||||||
|
return $this->driver->getConnection()->affected_rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function numRows()
|
||||||
|
{
|
||||||
|
if ($this->result) {
|
||||||
|
return $this->result->num_rows;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function driverExecute($sql)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var MySQLi
|
||||||
|
*/
|
||||||
|
$mysqli = $this->driver->getConnection();
|
||||||
|
$result = $mysqli->query($sql);
|
||||||
|
if ($result === false) {
|
||||||
|
throw new Exception($mysqli->error, $mysqli->errno);
|
||||||
|
}
|
||||||
|
if ($result instanceof MySQLi_Result) {
|
||||||
|
$this->result = $result;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user