Carsten Brandt
12 years ago
7 changed files with 1281 additions and 0 deletions
@ -0,0 +1,172 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* ActiveRecord class file. |
||||||
|
* |
||||||
|
* @author Carsten Brandt <mail@cebe.cc> |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright © 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\db\redis; |
||||||
|
|
||||||
|
/** |
||||||
|
* ActiveRecord is the base class for classes representing relational data in terms of objects. |
||||||
|
* |
||||||
|
* |
||||||
|
* @author Carsten Brandt <mail@cebe.cc> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class ActiveQuery extends \yii\db\ActiveQuery |
||||||
|
{ |
||||||
|
/** |
||||||
|
* Executes query and returns all results as an array. |
||||||
|
* @return array the query results. If the query results in nothing, an empty array will be returned. |
||||||
|
*/ |
||||||
|
public function all() |
||||||
|
{ |
||||||
|
$command = $this->createCommand(); |
||||||
|
$rows = $command->queryAll(); |
||||||
|
if ($rows !== array()) { |
||||||
|
$models = $this->createModels($rows); |
||||||
|
if (!empty($this->with)) { |
||||||
|
$this->populateRelations($models, $this->with); |
||||||
|
} |
||||||
|
return $models; |
||||||
|
} else { |
||||||
|
return array(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Executes query and returns a single row of result. |
||||||
|
* @return ActiveRecord|array|null a single row of query result. Depending on the setting of [[asArray]], |
||||||
|
* the query result may be either an array or an ActiveRecord object. Null will be returned |
||||||
|
* if the query results in nothing. |
||||||
|
*/ |
||||||
|
public function one() |
||||||
|
{ |
||||||
|
$command = $this->createCommand(); |
||||||
|
$row = $command->queryRow(); |
||||||
|
if ($row !== false && !$this->asArray) { |
||||||
|
/** @var $class ActiveRecord */ |
||||||
|
$class = $this->modelClass; |
||||||
|
$model = $class::create($row); |
||||||
|
if (!empty($this->with)) { |
||||||
|
$models = array($model); |
||||||
|
$this->populateRelations($models, $this->with); |
||||||
|
$model = $models[0]; |
||||||
|
} |
||||||
|
return $model; |
||||||
|
} else { |
||||||
|
return $row === false ? null : $row; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the number of records. |
||||||
|
* @param string $q the COUNT expression. Defaults to '*'. |
||||||
|
* Make sure you properly quote column names. |
||||||
|
* @return integer number of records |
||||||
|
*/ |
||||||
|
public function count($q = '*') |
||||||
|
{ |
||||||
|
$this->select = array("COUNT($q)"); |
||||||
|
return $this->createCommand()->queryScalar(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the sum of the specified column values. |
||||||
|
* @param string $q the column name or expression. |
||||||
|
* Make sure you properly quote column names. |
||||||
|
* @return integer the sum of the specified column values |
||||||
|
*/ |
||||||
|
public function sum($q) |
||||||
|
{ |
||||||
|
$this->select = array("SUM($q)"); |
||||||
|
return $this->createCommand()->queryScalar(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the average of the specified column values. |
||||||
|
* @param string $q the column name or expression. |
||||||
|
* Make sure you properly quote column names. |
||||||
|
* @return integer the average of the specified column values. |
||||||
|
*/ |
||||||
|
public function average($q) |
||||||
|
{ |
||||||
|
$this->select = array("AVG($q)"); |
||||||
|
return $this->createCommand()->queryScalar(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the minimum of the specified column values. |
||||||
|
* @param string $q the column name or expression. |
||||||
|
* Make sure you properly quote column names. |
||||||
|
* @return integer the minimum of the specified column values. |
||||||
|
*/ |
||||||
|
public function min($q) |
||||||
|
{ |
||||||
|
$this->select = array("MIN($q)"); |
||||||
|
return $this->createCommand()->queryScalar(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the maximum of the specified column values. |
||||||
|
* @param string $q the column name or expression. |
||||||
|
* Make sure you properly quote column names. |
||||||
|
* @return integer the maximum of the specified column values. |
||||||
|
*/ |
||||||
|
public function max($q) |
||||||
|
{ |
||||||
|
$this->select = array("MAX($q)"); |
||||||
|
return $this->createCommand()->queryScalar(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the query result as a scalar value. |
||||||
|
* The value returned will be the first column in the first row of the query results. |
||||||
|
* @return string|boolean the value of the first column in the first row of the query result. |
||||||
|
* False is returned if the query result is empty. |
||||||
|
*/ |
||||||
|
public function scalar() |
||||||
|
{ |
||||||
|
return $this->createCommand()->queryScalar(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a value indicating whether the query result contains any row of data. |
||||||
|
* @return boolean whether the query result contains any row of data. |
||||||
|
*/ |
||||||
|
public function exists() |
||||||
|
{ |
||||||
|
$this->select = array(new Expression('1')); |
||||||
|
return $this->scalar() !== false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a DB command that can be used to execute this query. |
||||||
|
* @param Connection $db the DB connection used to create the DB command. |
||||||
|
* If null, the DB connection returned by [[modelClass]] will be used. |
||||||
|
* @return Command the created DB command instance. |
||||||
|
*/ |
||||||
|
public function createCommand($db = null) |
||||||
|
{ |
||||||
|
/** @var $modelClass ActiveRecord */ |
||||||
|
$modelClass = $this->modelClass; |
||||||
|
if ($db === null) { |
||||||
|
$db = $modelClass::getDb(); |
||||||
|
} |
||||||
|
if ($this->sql === null) { |
||||||
|
if ($this->from === null) { |
||||||
|
$tableName = $modelClass::tableName(); |
||||||
|
$this->from = array($tableName); |
||||||
|
} |
||||||
|
/** @var $qb QueryBuilder */ |
||||||
|
$qb = $db->getQueryBuilder(); |
||||||
|
$this->sql = $qb->build($this); |
||||||
|
} |
||||||
|
return $db->createCommand($this->sql, $this->params); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,145 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* ActiveRecord class file. |
||||||
|
* |
||||||
|
* @author Carsten Brandt <mail@cebe.cc> |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright © 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\db\redis; |
||||||
|
|
||||||
|
/** |
||||||
|
* ActiveRecord is the base class for classes representing relational data in terms of objects. |
||||||
|
* |
||||||
|
* @include @yii/db/ActiveRecord.md |
||||||
|
* |
||||||
|
* @author Carsten Brandt <mail@cebe.cc> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
abstract class ActiveRecord extends \yii\db\ActiveRecord |
||||||
|
{ |
||||||
|
/** |
||||||
|
* Returns the list of all attribute names of the model. |
||||||
|
* The default implementation will return all column names of the table associated with this AR class. |
||||||
|
* @return array list of attribute names. |
||||||
|
*/ |
||||||
|
public function attributes() |
||||||
|
{ |
||||||
|
return array(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the database connection used by this AR class. |
||||||
|
* By default, the "db" application component is used as the database connection. |
||||||
|
* You may override this method if you want to use a different database connection. |
||||||
|
* @return Connection the database connection used by this AR class. |
||||||
|
*/ |
||||||
|
public static function getDb() |
||||||
|
{ |
||||||
|
// TODO |
||||||
|
return \Yii::$application->getDb(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates an [[ActiveQuery]] instance for query purpose. |
||||||
|
* |
||||||
|
* @include @yii/db/ActiveRecord-find.md |
||||||
|
* |
||||||
|
* @param mixed $q the query parameter. This can be one of the followings: |
||||||
|
* |
||||||
|
* - a scalar value (integer or string): query by a single primary key value and return the |
||||||
|
* corresponding record. |
||||||
|
* - an array of name-value pairs: query by a set of column values and return a single record matching all of them. |
||||||
|
* - null: return a new [[ActiveQuery]] object for further query purpose. |
||||||
|
* |
||||||
|
* @return ActiveQuery|ActiveRecord|null When `$q` is null, a new [[ActiveQuery]] instance |
||||||
|
* is returned; when `$q` is a scalar or an array, an ActiveRecord object matching it will be |
||||||
|
* returned (null will be returned if there is no matching). |
||||||
|
* @see createQuery() |
||||||
|
*/ |
||||||
|
public static function find($q = null) |
||||||
|
{ |
||||||
|
// TODO |
||||||
|
$query = static::createQuery(); |
||||||
|
if (is_array($q)) { |
||||||
|
return $query->where($q)->one(); |
||||||
|
} elseif ($q !== null) { |
||||||
|
// query by primary key |
||||||
|
$primaryKey = static::primaryKey(); |
||||||
|
return $query->where(array($primaryKey[0] => $q))->one(); |
||||||
|
} |
||||||
|
return $query; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates an [[ActiveQuery]] instance with a given SQL statement. |
||||||
|
* |
||||||
|
* Note that because the SQL statement is already specified, calling additional |
||||||
|
* query modification methods (such as `where()`, `order()`) on the created [[ActiveQuery]] |
||||||
|
* instance will have no effect. However, calling `with()`, `asArray()` or `indexBy()` is |
||||||
|
* still fine. |
||||||
|
* |
||||||
|
* Below is an example: |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* $customers = Customer::findBySql('SELECT * FROM tbl_customer')->all(); |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* @param string $sql the SQL statement to be executed |
||||||
|
* @param array $params parameters to be bound to the SQL statement during execution. |
||||||
|
* @return ActiveQuery the newly created [[ActiveQuery]] instance |
||||||
|
*/ |
||||||
|
public static function findBySql($sql, $params = array()) |
||||||
|
{ |
||||||
|
$query = static::createQuery(); |
||||||
|
$query->sql = $sql; |
||||||
|
return $query->params($params); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Creates an [[ActiveQuery]] instance. |
||||||
|
* This method is called by [[find()]], [[findBySql()]] and [[count()]] to start a SELECT query. |
||||||
|
* You may override this method to return a customized query (e.g. `CustomerQuery` specified |
||||||
|
* written for querying `Customer` purpose.) |
||||||
|
* @return ActiveQuery the newly created [[ActiveQuery]] instance. |
||||||
|
*/ |
||||||
|
public static function createQuery() |
||||||
|
{ |
||||||
|
return new ActiveQuery(array( |
||||||
|
'modelClass' => get_called_class(), |
||||||
|
)); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the schema information of the DB table associated with this AR class. |
||||||
|
* @return TableSchema the schema information of the DB table associated with this AR class. |
||||||
|
*/ |
||||||
|
public static function getTableSchema() |
||||||
|
{ |
||||||
|
return static::getDb()->getTableSchema(static::tableName()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the primary key name(s) for this AR class. |
||||||
|
* The default implementation will return the primary key(s) as declared |
||||||
|
* in the DB table that is associated with this AR class. |
||||||
|
* |
||||||
|
* If the DB table does not declare any primary key, you should override |
||||||
|
* this method to return the attributes that you want to use as primary keys |
||||||
|
* for this AR class. |
||||||
|
* |
||||||
|
* Note that an array should be returned even for a table with single primary key. |
||||||
|
* |
||||||
|
* @return string[] the primary keys of the associated database table. |
||||||
|
*/ |
||||||
|
public static function primaryKey() |
||||||
|
{ |
||||||
|
return static::getTableSchema()->primaryKey; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* ActiveRecord class file. |
||||||
|
* |
||||||
|
* @author Carsten Brandt <mail@cebe.cc> |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright © 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\db\redis; |
||||||
|
|
||||||
|
/** |
||||||
|
* ActiveRecord is the base class for classes representing relational data in terms of objects. |
||||||
|
* |
||||||
|
* |
||||||
|
* @author Carsten Brandt <mail@cebe.cc> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class ActiveRelation extends \yii\db\ActiveRelation |
||||||
|
{ |
||||||
|
|
||||||
|
} |
@ -0,0 +1,567 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* Command class file. |
||||||
|
* |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright © 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\db\redis; |
||||||
|
|
||||||
|
use yii\base\NotSupportedException; |
||||||
|
use yii\db\Exception; |
||||||
|
|
||||||
|
// TODO ensure proper value quoting against "SQL"injection |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class Command extends \yii\base\Component |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var Connection the DB connection that this command is associated with |
||||||
|
*/ |
||||||
|
public $db; |
||||||
|
/** |
||||||
|
* @var array the parameter log information (name=>value) |
||||||
|
*/ |
||||||
|
private $_params = array(); |
||||||
|
|
||||||
|
private $_query; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Determines the PDO type for the give PHP data value. |
||||||
|
* @param mixed $data the data whose PDO type is to be determined |
||||||
|
* @return integer the PDO type |
||||||
|
* @see http://www.php.net/manual/en/pdo.constants.php |
||||||
|
*/ |
||||||
|
private function getRedisType($data) |
||||||
|
{ |
||||||
|
static $typeMap = array( |
||||||
|
'boolean' => \PDO::PARAM_BOOL, |
||||||
|
'integer' => \PDO::PARAM_INT, |
||||||
|
'string' => \PDO::PARAM_STR, |
||||||
|
'NULL' => \PDO::PARAM_NULL, |
||||||
|
); |
||||||
|
$type = gettype($data); |
||||||
|
return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Executes the SQL statement. |
||||||
|
* This method should only be used for executing non-query SQL statement, such as `INSERT`, `DELETE`, `UPDATE` SQLs. |
||||||
|
* No result set will be returned. |
||||||
|
* @param array $params input parameters (name=>value) for the SQL execution. This is an alternative |
||||||
|
* to [[bindValues()]]. Note that if you pass parameters in this way, any previous call to [[bindParam()]] |
||||||
|
* or [[bindValue()]] will be ignored. |
||||||
|
* @return integer number of rows affected by the execution. |
||||||
|
* @throws Exception execution failed |
||||||
|
*/ |
||||||
|
public function execute() |
||||||
|
{ |
||||||
|
$query = $this->_query; |
||||||
|
|
||||||
|
if ($this->_params === array()) { |
||||||
|
$paramLog = ''; |
||||||
|
} else { |
||||||
|
$paramLog = "\nParameters: " . var_export($this->_params, true); |
||||||
|
} |
||||||
|
|
||||||
|
\Yii::trace("Executing SQL: {$query}{$paramLog}", __CLASS__); |
||||||
|
|
||||||
|
if ($query == '') { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
if ($this->db->enableProfiling) { |
||||||
|
\Yii::beginProfile(__METHOD__ . "($query)", __CLASS__); |
||||||
|
} |
||||||
|
|
||||||
|
$n = $this->db->redis->send_command(array_merge(array($query), $this->_params)); |
||||||
|
|
||||||
|
if ($this->db->enableProfiling) { |
||||||
|
\Yii::endProfile(__METHOD__ . "($query)", __CLASS__); |
||||||
|
} |
||||||
|
return $n; |
||||||
|
} catch (\Exception $e) { |
||||||
|
if ($this->db->enableProfiling) { |
||||||
|
\Yii::endProfile(__METHOD__ . "($query)", __CLASS__); |
||||||
|
} |
||||||
|
$message = $e->getMessage(); |
||||||
|
|
||||||
|
\Yii::error("$message\nFailed to execute SQL: {$query}{$paramLog}", __CLASS__); |
||||||
|
|
||||||
|
throw new Exception($message, (int)$e->getCode()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Executes the SQL statement and returns query result. |
||||||
|
* This method is for executing a SQL query that returns result set, such as `SELECT`. |
||||||
|
* @param array $params input parameters (name=>value) for the SQL execution. This is an alternative |
||||||
|
* to [[bindValues()]]. Note that if you pass parameters in this way, any previous call to [[bindParam()]] |
||||||
|
* or [[bindValue()]] will be ignored. |
||||||
|
* @return DataReader the reader object for fetching the query result |
||||||
|
* @throws Exception execution failed |
||||||
|
*/ |
||||||
|
public function query($params = array()) |
||||||
|
{ |
||||||
|
return $this->queryInternal('', $params); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Executes the SQL statement and returns ALL rows at once. |
||||||
|
* @param array $params input parameters (name=>value) for the SQL execution. This is an alternative |
||||||
|
* to [[bindValues()]]. Note that if you pass parameters in this way, any previous call to [[bindParam()]] |
||||||
|
* or [[bindValue()]] will be ignored. |
||||||
|
* @param mixed $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php) |
||||||
|
* for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used. |
||||||
|
* @return array all rows of the query result. Each array element is an array representing a row of data. |
||||||
|
* An empty array is returned if the query results in nothing. |
||||||
|
* @throws Exception execution failed |
||||||
|
*/ |
||||||
|
public function queryAll($params = array(), $fetchMode = null) |
||||||
|
{ |
||||||
|
return $this->queryInternal('fetchAll', $params, $fetchMode); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Executes the SQL statement and returns the first row of the result. |
||||||
|
* This method is best used when only the first row of result is needed for a query. |
||||||
|
* @param array $params input parameters (name=>value) for the SQL execution. This is an alternative |
||||||
|
* to [[bindValues()]]. Note that if you pass parameters in this way, any previous call to [[bindParam()]] |
||||||
|
* or [[bindValue()]] will be ignored. |
||||||
|
* @param mixed $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php) |
||||||
|
* for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used. |
||||||
|
* @return array|boolean the first row (in terms of an array) of the query result. False is returned if the query |
||||||
|
* results in nothing. |
||||||
|
* @throws Exception execution failed |
||||||
|
*/ |
||||||
|
public function queryRow($params = array(), $fetchMode = null) |
||||||
|
{ |
||||||
|
return $this->queryInternal('fetch', $params, $fetchMode); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Executes the SQL statement and returns the value of the first column in the first row of data. |
||||||
|
* This method is best used when only a single value is needed for a query. |
||||||
|
* @param array $params input parameters (name=>value) for the SQL execution. This is an alternative |
||||||
|
* to [[bindValues()]]. Note that if you pass parameters in this way, any previous call to [[bindParam()]] |
||||||
|
* or [[bindValue()]] will be ignored. |
||||||
|
* @return string|boolean the value of the first column in the first row of the query result. |
||||||
|
* False is returned if there is no value. |
||||||
|
* @throws Exception execution failed |
||||||
|
*/ |
||||||
|
public function queryScalar($params = array()) |
||||||
|
{ |
||||||
|
$result = $this->queryInternal('fetchColumn', $params, 0); |
||||||
|
if (is_resource($result) && get_resource_type($result) === 'stream') { |
||||||
|
return stream_get_contents($result); |
||||||
|
} else { |
||||||
|
return $result; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Executes the SQL statement and returns the first column of the result. |
||||||
|
* This method is best used when only the first column of result (i.e. the first element in each row) |
||||||
|
* is needed for a query. |
||||||
|
* @param array $params input parameters (name=>value) for the SQL execution. This is an alternative |
||||||
|
* to [[bindValues()]]. Note that if you pass parameters in this way, any previous call to [[bindParam()]] |
||||||
|
* or [[bindValue()]] will be ignored. |
||||||
|
* @return array the first column of the query result. Empty array is returned if the query results in nothing. |
||||||
|
* @throws Exception execution failed |
||||||
|
*/ |
||||||
|
public function queryColumn($params = array()) |
||||||
|
{ |
||||||
|
return $this->queryInternal('fetchAll', $params, \PDO::FETCH_COLUMN); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs the actual DB query of a SQL statement. |
||||||
|
* @param string $method method of PDOStatement to be called |
||||||
|
* @param array $params input parameters (name=>value) for the SQL execution. This is an alternative |
||||||
|
* to [[bindValues()]]. Note that if you pass parameters in this way, any previous call to [[bindParam()]] |
||||||
|
* or [[bindValue()]] will be ignored. |
||||||
|
* @param mixed $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php) |
||||||
|
* for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used. |
||||||
|
* @return mixed the method execution result |
||||||
|
* @throws Exception if the query causes any problem |
||||||
|
*/ |
||||||
|
private function queryInternal($method, $params, $fetchMode = null) |
||||||
|
{ |
||||||
|
$db = $this->db; |
||||||
|
$sql = $this->getSql(); |
||||||
|
$this->_params = array_merge($this->_params, $params); |
||||||
|
if ($this->_params === array()) { |
||||||
|
$paramLog = ''; |
||||||
|
} else { |
||||||
|
$paramLog = "\nParameters: " . var_export($this->_params, true); |
||||||
|
} |
||||||
|
|
||||||
|
\Yii::trace("Querying SQL: {$sql}{$paramLog}", __CLASS__); |
||||||
|
|
||||||
|
/** @var $cache \yii\caching\Cache */ |
||||||
|
if ($db->enableQueryCache && $method !== '') { |
||||||
|
$cache = \Yii::$application->getComponent($db->queryCacheID); |
||||||
|
} |
||||||
|
|
||||||
|
if (isset($cache)) { |
||||||
|
$cacheKey = $cache->buildKey(__CLASS__, $db->dsn, $db->username, $sql, $paramLog); |
||||||
|
if (($result = $cache->get($cacheKey)) !== false) { |
||||||
|
\Yii::trace('Query result found in cache', __CLASS__); |
||||||
|
return $result; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
if ($db->enableProfiling) { |
||||||
|
\Yii::beginProfile(__METHOD__ . "($sql)", __CLASS__); |
||||||
|
} |
||||||
|
|
||||||
|
$this->prepare(); |
||||||
|
if ($params === array()) { |
||||||
|
$this->pdoStatement->execute(); |
||||||
|
} else { |
||||||
|
$this->pdoStatement->execute($params); |
||||||
|
} |
||||||
|
|
||||||
|
if ($method === '') { |
||||||
|
$result = new DataReader($this); |
||||||
|
} else { |
||||||
|
if ($fetchMode === null) { |
||||||
|
$fetchMode = $this->fetchMode; |
||||||
|
} |
||||||
|
$result = call_user_func_array(array($this->pdoStatement, $method), (array)$fetchMode); |
||||||
|
$this->pdoStatement->closeCursor(); |
||||||
|
} |
||||||
|
|
||||||
|
if ($db->enableProfiling) { |
||||||
|
\Yii::endProfile(__METHOD__ . "($sql)", __CLASS__); |
||||||
|
} |
||||||
|
|
||||||
|
if (isset($cache, $cacheKey)) { |
||||||
|
$cache->set($cacheKey, $result, $db->queryCacheDuration, $db->queryCacheDependency); |
||||||
|
\Yii::trace('Saved query result in cache', __CLASS__); |
||||||
|
} |
||||||
|
|
||||||
|
return $result; |
||||||
|
} catch (\Exception $e) { |
||||||
|
if ($db->enableProfiling) { |
||||||
|
\Yii::endProfile(__METHOD__ . "($sql)", __CLASS__); |
||||||
|
} |
||||||
|
$message = $e->getMessage(); |
||||||
|
\Yii::error("$message\nCommand::$method() failed: {$sql}{$paramLog}", __CLASS__); |
||||||
|
$errorInfo = $e instanceof \PDOException ? $e->errorInfo : null; |
||||||
|
throw new Exception($message, (int)$e->getCode(), $errorInfo); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates an INSERT command. |
||||||
|
* For example, |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* $connection->createCommand()->insert('tbl_user', array( |
||||||
|
* 'name' => 'Sam', |
||||||
|
* 'age' => 30, |
||||||
|
* ))->execute(); |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* The method will properly escape the column names, and bind the values to be inserted. |
||||||
|
* |
||||||
|
* Note that the created command is not executed until [[execute()]] is called. |
||||||
|
* |
||||||
|
* @param string $table the table that new rows will be inserted into. |
||||||
|
* @param array $columns the column data (name=>value) to be inserted into the table. |
||||||
|
* @return Command the command object itself |
||||||
|
*/ |
||||||
|
public function insert($table, $columns) |
||||||
|
{ |
||||||
|
$params = array(); |
||||||
|
$sql = $this->db->getQueryBuilder()->insert($table, $columns, $params); |
||||||
|
return $this->setSql($sql)->bindValues($params); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a batch INSERT command. |
||||||
|
* For example, |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* $connection->createCommand()->batchInsert('tbl_user', array('name', 'age'), array( |
||||||
|
* array('Tom', 30), |
||||||
|
* array('Jane', 20), |
||||||
|
* array('Linda', 25), |
||||||
|
* ))->execute(); |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* Not that the values in each row must match the corresponding column names. |
||||||
|
* |
||||||
|
* @param string $table the table that new rows will be inserted into. |
||||||
|
* @param array $columns the column names |
||||||
|
* @param array $rows the rows to be batch inserted into the table |
||||||
|
* @return Command the command object itself |
||||||
|
*/ |
||||||
|
public function batchInsert($table, $columns, $rows) |
||||||
|
{ |
||||||
|
$sql = $this->db->getQueryBuilder()->batchInsert($table, $columns, $rows); |
||||||
|
return $this->setSql($sql); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates an UPDATE command. |
||||||
|
* For example, |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* $connection->createCommand()->update('tbl_user', array( |
||||||
|
* 'status' => 1, |
||||||
|
* ), 'age > 30')->execute(); |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* The method will properly escape the column names and bind the values to be updated. |
||||||
|
* |
||||||
|
* Note that the created command is not executed until [[execute()]] is called. |
||||||
|
* |
||||||
|
* @param string $table the table to be updated. |
||||||
|
* @param array $columns the column data (name=>value) to be updated. |
||||||
|
* @param mixed $condition the condition that will be put in the WHERE part. Please |
||||||
|
* refer to [[Query::where()]] on how to specify condition. |
||||||
|
* @param array $params the parameters to be bound to the command |
||||||
|
* @return Command the command object itself |
||||||
|
*/ |
||||||
|
public function update($table, $columns, $condition = '', $params = array()) |
||||||
|
{ |
||||||
|
$sql = $this->db->getQueryBuilder()->update($table, $columns, $condition, $params); |
||||||
|
return $this->setSql($sql)->bindValues($params); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a DELETE command. |
||||||
|
* For example, |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* $connection->createCommand()->delete('tbl_user', 'status = 0')->execute(); |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* The method will properly escape the table and column names. |
||||||
|
* |
||||||
|
* Note that the created command is not executed until [[execute()]] is called. |
||||||
|
* |
||||||
|
* @param string $table the table where the data will be deleted from. |
||||||
|
* @param mixed $condition the condition that will be put in the WHERE part. Please |
||||||
|
* refer to [[Query::where()]] on how to specify condition. |
||||||
|
* @param array $params the parameters to be bound to the command |
||||||
|
* @return Command the command object itself |
||||||
|
*/ |
||||||
|
public function delete($table, $condition = '', $params = array()) |
||||||
|
{ |
||||||
|
$sql = $this->db->getQueryBuilder()->delete($table, $condition); |
||||||
|
return $this->setSql($sql)->bindValues($params); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a SQL command for creating a new DB table. |
||||||
|
* |
||||||
|
* The columns in the new table should be specified as name-definition pairs (e.g. 'name'=>'string'), |
||||||
|
* where name stands for a column name which will be properly quoted by the method, and definition |
||||||
|
* stands for the column type which can contain an abstract DB type. |
||||||
|
* The method [[QueryBuilder::getColumnType()]] will be called |
||||||
|
* to convert the abstract column types to physical ones. For example, `string` will be converted |
||||||
|
* as `varchar(255)`, and `string not null` becomes `varchar(255) not null`. |
||||||
|
* |
||||||
|
* If a column is specified with definition only (e.g. 'PRIMARY KEY (name, type)'), it will be directly |
||||||
|
* inserted into the generated SQL. |
||||||
|
* |
||||||
|
* @param string $table the name of the table to be created. The name will be properly quoted by the method. |
||||||
|
* @param array $columns the columns (name=>definition) in the new table. |
||||||
|
* @param string $options additional SQL fragment that will be appended to the generated SQL. |
||||||
|
* @return Command the command object itself |
||||||
|
*/ |
||||||
|
public function createTable($table, $columns, $options = null) |
||||||
|
{ |
||||||
|
$sql = $this->db->getQueryBuilder()->createTable($table, $columns, $options); |
||||||
|
return $this->setSql($sql); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a SQL command for renaming a DB table. |
||||||
|
* @param string $table the table to be renamed. The name will be properly quoted by the method. |
||||||
|
* @param string $newName the new table name. The name will be properly quoted by the method. |
||||||
|
* @return Command the command object itself |
||||||
|
*/ |
||||||
|
public function renameTable($table, $newName) |
||||||
|
{ |
||||||
|
$sql = $this->db->getQueryBuilder()->renameTable($table, $newName); |
||||||
|
return $this->setSql($sql); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a SQL command for dropping a DB table. |
||||||
|
* @param string $table the table to be dropped. The name will be properly quoted by the method. |
||||||
|
* @return Command the command object itself |
||||||
|
*/ |
||||||
|
public function dropTable($table) |
||||||
|
{ |
||||||
|
$sql = $this->db->getQueryBuilder()->dropTable($table); |
||||||
|
return $this->setSql($sql); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a SQL command for truncating a DB table. |
||||||
|
* @param string $table the table to be truncated. The name will be properly quoted by the method. |
||||||
|
* @return Command the command object itself |
||||||
|
*/ |
||||||
|
public function truncateTable($table) |
||||||
|
{ |
||||||
|
$sql = $this->db->getQueryBuilder()->truncateTable($table); |
||||||
|
return $this->setSql($sql); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a SQL command for adding a new DB column. |
||||||
|
* @param string $table the table that the new column will be added to. The table name will be properly quoted by the method. |
||||||
|
* @param string $column the name of the new column. The name will be properly quoted by the method. |
||||||
|
* @param string $type the column type. [[\yii\db\QueryBuilder::getColumnType()]] will be called |
||||||
|
* to convert the give column type to the physical one. For example, `string` will be converted |
||||||
|
* as `varchar(255)`, and `string not null` becomes `varchar(255) not null`. |
||||||
|
* @return Command the command object itself |
||||||
|
*/ |
||||||
|
public function addColumn($table, $column, $type) |
||||||
|
{ |
||||||
|
$sql = $this->db->getQueryBuilder()->addColumn($table, $column, $type); |
||||||
|
return $this->setSql($sql); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a SQL command for dropping a DB column. |
||||||
|
* @param string $table the table whose column is to be dropped. The name will be properly quoted by the method. |
||||||
|
* @param string $column the name of the column to be dropped. The name will be properly quoted by the method. |
||||||
|
* @return Command the command object itself |
||||||
|
*/ |
||||||
|
public function dropColumn($table, $column) |
||||||
|
{ |
||||||
|
$sql = $this->db->getQueryBuilder()->dropColumn($table, $column); |
||||||
|
return $this->setSql($sql); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a SQL command for renaming a column. |
||||||
|
* @param string $table the table whose column is to be renamed. The name will be properly quoted by the method. |
||||||
|
* @param string $oldName the old name of the column. The name will be properly quoted by the method. |
||||||
|
* @param string $newName the new name of the column. The name will be properly quoted by the method. |
||||||
|
* @return Command the command object itself |
||||||
|
*/ |
||||||
|
public function renameColumn($table, $oldName, $newName) |
||||||
|
{ |
||||||
|
$sql = $this->db->getQueryBuilder()->renameColumn($table, $oldName, $newName); |
||||||
|
return $this->setSql($sql); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a SQL command for changing the definition of a column. |
||||||
|
* @param string $table the table whose column is to be changed. The table name will be properly quoted by the method. |
||||||
|
* @param string $column the name of the column to be changed. The name will be properly quoted by the method. |
||||||
|
* @param string $type the column type. [[\yii\db\QueryBuilder::getColumnType()]] will be called |
||||||
|
* to convert the give column type to the physical one. For example, `string` will be converted |
||||||
|
* as `varchar(255)`, and `string not null` becomes `varchar(255) not null`. |
||||||
|
* @return Command the command object itself |
||||||
|
*/ |
||||||
|
public function alterColumn($table, $column, $type) |
||||||
|
{ |
||||||
|
$sql = $this->db->getQueryBuilder()->alterColumn($table, $column, $type); |
||||||
|
return $this->setSql($sql); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a SQL command for adding a foreign key constraint to an existing table. |
||||||
|
* The method will properly quote the table and column names. |
||||||
|
* @param string $name the name of the foreign key constraint. |
||||||
|
* @param string $table the table that the foreign key constraint will be added to. |
||||||
|
* @param string $columns the name of the column to that the constraint will be added on. If there are multiple columns, separate them with commas. |
||||||
|
* @param string $refTable the table that the foreign key references to. |
||||||
|
* @param string $refColumns the name of the column that the foreign key references to. If there are multiple columns, separate them with commas. |
||||||
|
* @param string $delete the ON DELETE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL |
||||||
|
* @param string $update the ON UPDATE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL |
||||||
|
* @return Command the command object itself |
||||||
|
*/ |
||||||
|
public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete = null, $update = null) |
||||||
|
{ |
||||||
|
$sql = $this->db->getQueryBuilder()->addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete, $update); |
||||||
|
return $this->setSql($sql); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a SQL command for dropping a foreign key constraint. |
||||||
|
* @param string $name the name of the foreign key constraint to be dropped. The name will be properly quoted by the method. |
||||||
|
* @param string $table the table whose foreign is to be dropped. The name will be properly quoted by the method. |
||||||
|
* @return Command the command object itself |
||||||
|
*/ |
||||||
|
public function dropForeignKey($name, $table) |
||||||
|
{ |
||||||
|
$sql = $this->db->getQueryBuilder()->dropForeignKey($name, $table); |
||||||
|
return $this->setSql($sql); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a SQL command for creating a new index. |
||||||
|
* @param string $name the name of the index. The name will be properly quoted by the method. |
||||||
|
* @param string $table the table that the new index will be created for. The table name will be properly quoted by the method. |
||||||
|
* @param string $columns the column(s) that should be included in the index. If there are multiple columns, please separate them |
||||||
|
* by commas. The column names will be properly quoted by the method. |
||||||
|
* @param boolean $unique whether to add UNIQUE constraint on the created index. |
||||||
|
* @return Command the command object itself |
||||||
|
*/ |
||||||
|
public function createIndex($name, $table, $columns, $unique = false) |
||||||
|
{ |
||||||
|
$sql = $this->db->getQueryBuilder()->createIndex($name, $table, $columns, $unique); |
||||||
|
return $this->setSql($sql); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a SQL command for dropping an index. |
||||||
|
* @param string $name the name of the index to be dropped. The name will be properly quoted by the method. |
||||||
|
* @param string $table the table whose index is to be dropped. The name will be properly quoted by the method. |
||||||
|
* @return Command the command object itself |
||||||
|
*/ |
||||||
|
public function dropIndex($name, $table) |
||||||
|
{ |
||||||
|
$sql = $this->db->getQueryBuilder()->dropIndex($name, $table); |
||||||
|
return $this->setSql($sql); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a SQL command for resetting the sequence value of a table's primary key. |
||||||
|
* The sequence will be reset such that the primary key of the next new row inserted |
||||||
|
* will have the specified value or 1. |
||||||
|
* @param string $table the name of the table whose primary key sequence will be reset |
||||||
|
* @param mixed $value the value for the primary key of the next new row inserted. If this is not set, |
||||||
|
* the next new row's primary key will have a value 1. |
||||||
|
* @return Command the command object itself |
||||||
|
* @throws NotSupportedException if this is not supported by the underlying DBMS |
||||||
|
*/ |
||||||
|
public function resetSequence($table, $value = null) |
||||||
|
{ |
||||||
|
$sql = $this->db->getQueryBuilder()->resetSequence($table, $value); |
||||||
|
return $this->setSql($sql); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds a SQL command for enabling or disabling integrity check. |
||||||
|
* @param boolean $check whether to turn on or off the integrity check. |
||||||
|
* @param string $schema the schema name of the tables. Defaults to empty string, meaning the current |
||||||
|
* or default schema. |
||||||
|
* @return Command the command object itself |
||||||
|
* @throws NotSupportedException if this is not supported by the underlying DBMS |
||||||
|
*/ |
||||||
|
public function checkIntegrity($check = true, $schema = '') |
||||||
|
{ |
||||||
|
$sql = $this->db->getQueryBuilder()->checkIntegrity($check, $schema); |
||||||
|
return $this->setSql($sql); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,248 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* Connection class file |
||||||
|
* |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright © 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\db\redis; |
||||||
|
|
||||||
|
use \yii\base\Component; |
||||||
|
use yii\base\NotSupportedException; |
||||||
|
use yii\base\InvalidConfigException; |
||||||
|
use \yii\db\Exception; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* |
||||||
|
* |
||||||
|
* |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class Connection extends Component |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @event Event an event that is triggered after a DB connection is established |
||||||
|
*/ |
||||||
|
const EVENT_AFTER_OPEN = 'afterOpen'; |
||||||
|
|
||||||
|
/** |
||||||
|
* @var string the Data Source Name, or DSN, contains the information required to connect to the database. |
||||||
|
* DSN format: redis://[auth@][server][:port][/db] |
||||||
|
* @see charset |
||||||
|
*/ |
||||||
|
public $dsn; |
||||||
|
/** |
||||||
|
* @var string the username for establishing DB connection. Defaults to empty string. |
||||||
|
*/ |
||||||
|
public $username = ''; |
||||||
|
/** |
||||||
|
* @var string the password for establishing DB connection. Defaults to empty string. |
||||||
|
*/ |
||||||
|
public $password = ''; |
||||||
|
|
||||||
|
/** |
||||||
|
* @var \Jamm\Memory\RedisServer |
||||||
|
*/ |
||||||
|
public $redis; |
||||||
|
|
||||||
|
/** |
||||||
|
* @var boolean whether to enable profiling for the SQL statements being executed. |
||||||
|
* Defaults to false. This should be mainly enabled and used during development |
||||||
|
* to find out the bottleneck of SQL executions. |
||||||
|
* @see getStats |
||||||
|
*/ |
||||||
|
public $enableProfiling = false; |
||||||
|
/** |
||||||
|
* @var string the common prefix or suffix for table names. If a table name is given |
||||||
|
* as `{{%TableName}}`, then the percentage character `%` will be replaced with this |
||||||
|
* property value. For example, `{{%post}}` becomes `{{tbl_post}}` if this property is |
||||||
|
* set as `"tbl_"`. Note that this property is only effective when [[enableAutoQuoting]] |
||||||
|
* is true. |
||||||
|
* @see enableAutoQuoting |
||||||
|
*/ |
||||||
|
public $keyPrefix; |
||||||
|
/** |
||||||
|
* @var Transaction the currently active transaction |
||||||
|
*/ |
||||||
|
private $_transaction; |
||||||
|
|
||||||
|
/** |
||||||
|
* Closes the connection when this component is being serialized. |
||||||
|
* @return array |
||||||
|
*/ |
||||||
|
public function __sleep() |
||||||
|
{ |
||||||
|
$this->close(); |
||||||
|
return array_keys(get_object_vars($this)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a value indicating whether the DB connection is established. |
||||||
|
* @return boolean whether the DB connection is established |
||||||
|
*/ |
||||||
|
public function getIsActive() |
||||||
|
{ |
||||||
|
return $this->redis !== null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Establishes a DB connection. |
||||||
|
* It does nothing if a DB connection has already been established. |
||||||
|
* @throws Exception if connection fails |
||||||
|
*/ |
||||||
|
public function open() |
||||||
|
{ |
||||||
|
if ($this->redis === null) { |
||||||
|
if (empty($this->dsn)) { |
||||||
|
throw new InvalidConfigException('Connection.dsn cannot be empty.'); |
||||||
|
} |
||||||
|
// TODO parse DSN |
||||||
|
$host = 'localhost'; |
||||||
|
$port = 6379; |
||||||
|
try { |
||||||
|
\Yii::trace('Opening DB connection: ' . $this->dsn, __CLASS__); |
||||||
|
// TODO connection to redis seems to be very easy, consider writing own connect |
||||||
|
$this->redis = new \Jamm\Memory\RedisServer($host, $port); |
||||||
|
$this->initConnection(); |
||||||
|
} |
||||||
|
catch (\PDOException $e) { |
||||||
|
\Yii::error("Failed to open DB connection ({$this->dsn}): " . $e->getMessage(), __CLASS__); |
||||||
|
$message = YII_DEBUG ? 'Failed to open DB connection: ' . $e->getMessage() : 'Failed to open DB connection.'; |
||||||
|
throw new Exception($message, (int)$e->getCode(), $e->errorInfo); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Closes the currently active DB connection. |
||||||
|
* It does nothing if the connection is already closed. |
||||||
|
*/ |
||||||
|
public function close() |
||||||
|
{ |
||||||
|
if ($this->redis !== null) { |
||||||
|
\Yii::trace('Closing DB connection: ' . $this->dsn, __CLASS__); |
||||||
|
$this->redis = null; |
||||||
|
$this->_transaction = null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Initializes the DB connection. |
||||||
|
* This method is invoked right after the DB connection is established. |
||||||
|
* The default implementation turns on `PDO::ATTR_EMULATE_PREPARES` |
||||||
|
* if [[emulatePrepare]] is true, and sets the database [[charset]] if it is not empty. |
||||||
|
* It then triggers an [[EVENT_AFTER_OPEN]] event. |
||||||
|
*/ |
||||||
|
protected function initConnection() |
||||||
|
{ |
||||||
|
$this->trigger(self::EVENT_AFTER_OPEN); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a command for execution. |
||||||
|
* @param string $query the SQL statement to be executed |
||||||
|
* @param array $params the parameters to be bound to the SQL statement |
||||||
|
* @return Command the DB command |
||||||
|
*/ |
||||||
|
public function createCommand($query = null, $params = array()) |
||||||
|
{ |
||||||
|
$this->open(); |
||||||
|
$command = new Command(array( |
||||||
|
'db' => $this, |
||||||
|
'query' => $query, |
||||||
|
)); |
||||||
|
return $command->addValues($params); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the currently active transaction. |
||||||
|
* @return Transaction the currently active transaction. Null if no active transaction. |
||||||
|
*/ |
||||||
|
public function getTransaction() |
||||||
|
{ |
||||||
|
return $this->_transaction && $this->_transaction->isActive ? $this->_transaction : null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Starts a transaction. |
||||||
|
* @return Transaction the transaction initiated |
||||||
|
*/ |
||||||
|
public function beginTransaction() |
||||||
|
{ |
||||||
|
$this->open(); |
||||||
|
$this->_transaction = new Transaction(array( |
||||||
|
'db' => $this, |
||||||
|
)); |
||||||
|
$this->_transaction->begin(); |
||||||
|
return $this->_transaction; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the schema information for the database opened by this connection. |
||||||
|
* @return Schema the schema information for the database opened by this connection. |
||||||
|
* @throws NotSupportedException if there is no support for the current driver type |
||||||
|
*/ |
||||||
|
public function getSchema() |
||||||
|
{ |
||||||
|
$driver = $this->getDriverName(); |
||||||
|
throw new NotSupportedException("Connection does not support reading schema information for '$driver' DBMS."); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the query builder for the current DB connection. |
||||||
|
* @return QueryBuilder the query builder for the current DB connection. |
||||||
|
*/ |
||||||
|
public function getQueryBuilder() |
||||||
|
{ |
||||||
|
return $this->getSchema()->getQueryBuilder(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Obtains the schema information for the named table. |
||||||
|
* @param string $name table name. |
||||||
|
* @param boolean $refresh whether to reload the table schema even if it is found in the cache. |
||||||
|
* @return TableSchema table schema information. Null if the named table does not exist. |
||||||
|
*/ |
||||||
|
public function getTableSchema($name, $refresh = false) |
||||||
|
{ |
||||||
|
return $this->getSchema()->getTableSchema($name, $refresh); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the name of the DB driver for the current [[dsn]]. |
||||||
|
* @return string name of the DB driver |
||||||
|
*/ |
||||||
|
public function getDriverName() |
||||||
|
{ |
||||||
|
if (($pos = strpos($this->dsn, ':')) !== false) { |
||||||
|
return strtolower(substr($this->dsn, 0, $pos)); |
||||||
|
} else { |
||||||
|
return 'redis'; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the statistical results of SQL queries. |
||||||
|
* The results returned include the number of SQL statements executed and |
||||||
|
* the total time spent. |
||||||
|
* In order to use this method, [[enableProfiling]] has to be set true. |
||||||
|
* @return array the first element indicates the number of SQL statements executed, |
||||||
|
* and the second element the total time spent in SQL execution. |
||||||
|
* @see \yii\logging\Logger::getProfiling() |
||||||
|
*/ |
||||||
|
public function getQuerySummary() |
||||||
|
{ |
||||||
|
$logger = \Yii::getLogger(); |
||||||
|
$timings = $logger->getProfiling(array('yii\db\Command::query', 'yii\db\Command::execute')); |
||||||
|
$count = count($timings); |
||||||
|
$time = 0; |
||||||
|
foreach ($timings as $timing) { |
||||||
|
$time += $timing[1]; |
||||||
|
} |
||||||
|
return array($count, $time); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,91 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* Transaction class file. |
||||||
|
* |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright © 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\db\redis; |
||||||
|
|
||||||
|
use yii\base\InvalidConfigException; |
||||||
|
use yii\db\Exception; |
||||||
|
|
||||||
|
/** |
||||||
|
* Transaction represents a DB transaction. |
||||||
|
* |
||||||
|
* @property boolean $isActive Whether the transaction is active. This property is read-only. |
||||||
|
* |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class Transaction extends \yii\base\Object |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var Connection the database connection that this transaction is associated with. |
||||||
|
*/ |
||||||
|
public $db; |
||||||
|
/** |
||||||
|
* @var boolean whether this transaction is active. Only an active transaction |
||||||
|
* can [[commit()]] or [[rollBack()]]. This property is set true when the transaction is started. |
||||||
|
*/ |
||||||
|
private $_active = false; |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a value indicating whether this transaction is active. |
||||||
|
* @return boolean whether this transaction is active. Only an active transaction |
||||||
|
* can [[commit()]] or [[rollBack()]]. |
||||||
|
*/ |
||||||
|
public function getIsActive() |
||||||
|
{ |
||||||
|
return $this->_active; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Begins a transaction. |
||||||
|
* @throws InvalidConfigException if [[connection]] is null |
||||||
|
*/ |
||||||
|
public function begin() |
||||||
|
{ |
||||||
|
if (!$this->_active) { |
||||||
|
if ($this->db === null) { |
||||||
|
throw new InvalidConfigException('Transaction::db must be set.'); |
||||||
|
} |
||||||
|
\Yii::trace('Starting transaction', __CLASS__); |
||||||
|
$this->db->open(); |
||||||
|
$this->db->createCommand('MULTI')->execute(); |
||||||
|
$this->_active = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Commits a transaction. |
||||||
|
* @throws Exception if the transaction or the DB connection is not active. |
||||||
|
*/ |
||||||
|
public function commit() |
||||||
|
{ |
||||||
|
if ($this->_active && $this->db && $this->db->isActive) { |
||||||
|
\Yii::trace('Committing transaction', __CLASS__); |
||||||
|
$this->db->createCommand('EXEC')->execute(); |
||||||
|
// TODO handle result of EXEC |
||||||
|
$this->_active = false; |
||||||
|
} else { |
||||||
|
throw new Exception('Failed to commit transaction: transaction was inactive.'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Rolls back a transaction. |
||||||
|
* @throws Exception if the transaction or the DB connection is not active. |
||||||
|
*/ |
||||||
|
public function rollback() |
||||||
|
{ |
||||||
|
if ($this->_active && $this->db && $this->db->isActive) { |
||||||
|
\Yii::trace('Rolling back transaction', __CLASS__); |
||||||
|
$this->db->pdo->commit(); |
||||||
|
$this->_active = false; |
||||||
|
} else { |
||||||
|
throw new Exception('Failed to roll back transaction: transaction was inactive.'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
To allow AR to be stored in redis we need a special Schema for it. |
||||||
|
|
||||||
|
HSET prefix:className:primaryKey |
||||||
|
|
||||||
|
|
||||||
|
http://redis.io/commands |
||||||
|
|
||||||
|
Current Redis connection: |
||||||
|
https://github.com/jamm/Memory |
||||||
|
|
||||||
|
|
||||||
|
# Queries |
||||||
|
|
||||||
|
wrap all these in transactions MULTI |
||||||
|
|
||||||
|
## insert |
||||||
|
|
||||||
|
SET all attribute key-value pairs |
||||||
|
SET all relation key-value pairs |
||||||
|
make sure to create back-relations |
||||||
|
|
||||||
|
## update |
||||||
|
|
||||||
|
SET all attribute key-value pairs |
||||||
|
SET all relation key-value pairs |
||||||
|
|
||||||
|
|
||||||
|
## delete |
||||||
|
|
||||||
|
DEL all attribute key-value pairs |
||||||
|
DEL all relation key-value pairs |
||||||
|
make sure to update back-relations |
||||||
|
|
||||||
|
|
||||||
|
http://redis.io/commands/hmget sounds suiteable! |
Loading…
Reference in new issue