mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-11 19:20:01 +08:00
refactored Model and redis AR to allow drop of RecordSchema
This commit is contained in:
@@ -229,14 +229,13 @@ class Model extends Component implements IteratorAggregate, ArrayAccess
|
||||
* You may override this method to change the default behavior.
|
||||
* @return array list of attribute names.
|
||||
*/
|
||||
public function attributes()
|
||||
public static function attributes()
|
||||
{
|
||||
$class = new ReflectionClass($this);
|
||||
$class = new ReflectionClass(get_called_class());
|
||||
$names = [];
|
||||
foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
|
||||
$name = $property->getName();
|
||||
if (!$property->isStatic()) {
|
||||
$names[] = $name;
|
||||
$names[] = $property->getName();
|
||||
}
|
||||
}
|
||||
return $names;
|
||||
|
||||
@@ -568,9 +568,9 @@ class ActiveRecord extends 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()
|
||||
public static function attributes()
|
||||
{
|
||||
return array_keys($this->getTableSchema()->columns);
|
||||
return array_keys(static::getTableSchema()->columns);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -580,7 +580,7 @@ class ActiveRecord extends Model
|
||||
*/
|
||||
public function hasAttribute($name)
|
||||
{
|
||||
return isset($this->_attributes[$name]) || isset($this->getTableSchema()->columns[$name]);
|
||||
return isset($this->_attributes[$name]) || in_array($name, $this->attributes());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1244,7 +1244,7 @@ class ActiveRecord extends Model
|
||||
public static function create($row)
|
||||
{
|
||||
$record = static::instantiate($row);
|
||||
$columns = static::getTableSchema()->columns;
|
||||
$columns = array_flip(static::attributes());
|
||||
foreach ($row as $name => $value) {
|
||||
if (isset($columns[$name])) {
|
||||
$record->_attributes[$name] = $value;
|
||||
|
||||
@@ -9,22 +9,33 @@ namespace yii\redis;
|
||||
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\base\NotSupportedException;
|
||||
use yii\db\TableSchema;
|
||||
use yii\helpers\StringHelper;
|
||||
|
||||
/**
|
||||
* ActiveRecord is the base class for classes representing relational data in terms of objects.
|
||||
*
|
||||
* This class implements the ActiveRecord pattern for the [redis](http://redis.io/) key-value store.
|
||||
*
|
||||
* For defining a record a subclass should at least implement the [[attributes()]] method to define
|
||||
* attributes. A primary key can be defined via [[primaryKey()]] which defaults to `id` if not specified.
|
||||
*
|
||||
* The following is an example model called `Customer`:
|
||||
*
|
||||
* ```php
|
||||
* class Customer extends \yii\redis\ActiveRecord
|
||||
* {
|
||||
* public function attributes()
|
||||
* {
|
||||
* return ['id', 'name', 'address', 'registration_date'];
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @author Carsten Brandt <mail@cebe.cc>
|
||||
* @since 2.0
|
||||
*/
|
||||
class ActiveRecord extends \yii\db\ActiveRecord
|
||||
{
|
||||
/**
|
||||
* @var array cache for TableSchema instances
|
||||
*/
|
||||
private static $_tables = [];
|
||||
|
||||
/**
|
||||
* Returns the database connection used by this AR class.
|
||||
* By default, the "redis" application component is used as the database connection.
|
||||
@@ -36,14 +47,6 @@ class ActiveRecord extends \yii\db\ActiveRecord
|
||||
return \Yii::$app->getComponent('redis');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static function findBySql($sql, $params = [])
|
||||
{
|
||||
throw new NotSupportedException('findBySql() is not supported by redis ActiveRecord');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -61,35 +64,26 @@ class ActiveRecord extends \yii\db\ActiveRecord
|
||||
}
|
||||
|
||||
/**
|
||||
* Declares the name of the database table associated with this AR class.
|
||||
* @return string the table name
|
||||
* Returns the primary key name(s) for this AR class.
|
||||
* This method should be overridden by child classes to define the primary key.
|
||||
*
|
||||
* Note that an array should be returned even when it is a single primary key.
|
||||
*
|
||||
* @return string[] the primary keys of this record.
|
||||
*/
|
||||
public static function tableName()
|
||||
public static function primaryKey()
|
||||
{
|
||||
return static::getTableSchema()->name;
|
||||
return ['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is ment to be overridden in redis ActiveRecord subclasses to return a [[RecordSchema]] instance.
|
||||
* @return RecordSchema
|
||||
* @throws \yii\base\InvalidConfigException
|
||||
* Returns the list of all attribute names of the model.
|
||||
* This method must be overridden by child classes to define available attributes.
|
||||
* @return array list of attribute names.
|
||||
*/
|
||||
public static function getRecordSchema()
|
||||
public static function attributes()
|
||||
{
|
||||
throw new InvalidConfigException(__CLASS__.'::getRecordSchema() needs to be overridden in subclasses and return a RecordSchema.');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
$class = get_called_class();
|
||||
if (isset(self::$_tables[$class])) {
|
||||
return self::$_tables[$class];
|
||||
}
|
||||
return self::$_tables[$class] = static::getRecordSchema();
|
||||
throw new InvalidConfigException('The attributes() method of redis ActiveRecord has to be implemented by child classes.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -299,6 +293,22 @@ class ActiveRecord extends \yii\db\ActiveRecord
|
||||
return md5(json_encode($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static function getTableSchema()
|
||||
{
|
||||
throw new NotSupportedException('getTableSchema() is not supported by redis ActiveRecord');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static function findBySql($sql, $params = [])
|
||||
{
|
||||
throw new NotSupportedException('findBySql() is not supported by redis ActiveRecord');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value indicating whether the specified operation is transactional in the current [[scenario]].
|
||||
* This method will always return false as transactional operations are not supported by redis.
|
||||
|
||||
@@ -21,8 +21,6 @@ use yii\helpers\Inflector;
|
||||
* @property string $driverName Name of the DB driver. This property is read-only.
|
||||
* @property boolean $isActive Whether the DB connection is established. This property is read-only.
|
||||
* @property LuaScriptBuilder $luaScriptBuilder This property is read-only.
|
||||
* @property Transaction $transaction The currently active transaction. Null if no active transaction. This
|
||||
* property is read-only.
|
||||
*
|
||||
* @author Carsten Brandt <mail@cebe.cc>
|
||||
* @since 2.0
|
||||
@@ -201,10 +199,6 @@ class Connection extends Component
|
||||
'ZSCORE', // key member Get the score associated with the given member in a sorted set
|
||||
'ZUNIONSTORE', // destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] Add multiple sorted sets and store the resulting sorted set in a new key
|
||||
];
|
||||
/**
|
||||
* @var Transaction the currently active transaction
|
||||
*/
|
||||
private $_transaction;
|
||||
/**
|
||||
* @var resource redis socket connection
|
||||
*/
|
||||
@@ -296,27 +290,6 @@ class Connection extends Component
|
||||
$this->trigger(self::EVENT_AFTER_OPEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(['db' => $this]);
|
||||
$this->_transaction->begin();
|
||||
return $this->_transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the DB driver for the current [[dsn]].
|
||||
* @return string name of the DB driver
|
||||
|
||||
@@ -129,6 +129,10 @@ class LuaScriptBuilder extends \yii\base\Object
|
||||
*/
|
||||
private function build($query, $buildResult, $return)
|
||||
{
|
||||
if (!empty($query->orderBy)) {
|
||||
throw new NotSupportedException('orderBy is currently not supported by redis ActiveRecord.');
|
||||
}
|
||||
|
||||
$columns = [];
|
||||
if ($query->where !== null) {
|
||||
$condition = $this->buildCondition($query->where, $columns);
|
||||
@@ -139,6 +143,7 @@ class LuaScriptBuilder extends \yii\base\Object
|
||||
$start = $query->offset === null ? 0 : $query->offset;
|
||||
$limitCondition = 'i>' . $start . ($query->limit === null ? '' : ' and i<=' . ($start + $query->limit));
|
||||
|
||||
/** @var ActiveRecord $modelClass */
|
||||
$modelClass = $query->modelClass;
|
||||
$key = $this->quoteValue($modelClass::tableName());
|
||||
$loadColumnValues = '';
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\redis;
|
||||
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\db\TableSchema;
|
||||
|
||||
/**
|
||||
* Class RecordSchema defines the data schema for a redis active record
|
||||
*
|
||||
* As there is no schema in a redis DB this class is used to define one.
|
||||
*
|
||||
* @package yii\db\redis
|
||||
*/
|
||||
class RecordSchema extends TableSchema
|
||||
{
|
||||
/**
|
||||
* @var string[] column names.
|
||||
*/
|
||||
public $columns = array();
|
||||
|
||||
/**
|
||||
* @return string the column type
|
||||
*/
|
||||
public function getColumn($name)
|
||||
{
|
||||
parent::getColumn($name);
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
if (empty($this->name)) {
|
||||
throw new InvalidConfigException('name of RecordSchema must not be empty.');
|
||||
}
|
||||
if (empty($this->primaryKey)) {
|
||||
throw new InvalidConfigException('primaryKey of RecordSchema must not be empty.');
|
||||
}
|
||||
if (!is_array($this->primaryKey)) {
|
||||
$this->primaryKey = [$this->primaryKey];
|
||||
}
|
||||
foreach($this->primaryKey as $pk) {
|
||||
if (!isset($this->columns[$pk])) {
|
||||
throw new InvalidConfigException('primaryKey '.$pk.' is not a colum of RecordSchema.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,13 +64,13 @@ class UniqueValidator extends Validator
|
||||
$className = $this->className === null ? get_class($object) : $this->className;
|
||||
$attributeName = $this->attributeName === null ? $attribute : $this->attributeName;
|
||||
|
||||
$table = $className::getTableSchema();
|
||||
if (($column = $table->getColumn($attributeName)) === null) {
|
||||
throw new InvalidConfigException("Table '{$table->name}' does not have a column named '$attributeName'.");
|
||||
$attributes = $className::attributes();
|
||||
if (!in_array($attribute, $attributes)) {
|
||||
throw new InvalidConfigException("'$className' does not have an attribute named '$attributeName'.");
|
||||
}
|
||||
|
||||
$query = $className::find();
|
||||
$query->where([$column->name => $value]);
|
||||
$query->where([$attribute => $value]);
|
||||
|
||||
if (!$object instanceof ActiveRecord || $object->getIsNewRecord()) {
|
||||
// if current $object isn't in the database yet then it's OK just to call exists()
|
||||
@@ -82,7 +82,7 @@ class UniqueValidator extends Validator
|
||||
|
||||
$n = count($objects);
|
||||
if ($n === 1) {
|
||||
if ($column->isPrimaryKey) {
|
||||
if (in_array($attribute, $className::primaryKey())) {
|
||||
// primary key is modified and not unique
|
||||
$exists = $object->getOldPrimaryKey() != $object->getPrimaryKey();
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user