Commit f5f443ab by Qiang Xue

Merge pull request #1359 from yiisoft/activerecord-interface

ActiveRecord Interface and BaseAR
parents 199fe352 48199cfc
...@@ -10,6 +10,8 @@ namespace yii\elasticsearch; ...@@ -10,6 +10,8 @@ namespace yii\elasticsearch;
use yii\base\InvalidCallException; use yii\base\InvalidCallException;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\base\NotSupportedException; use yii\base\NotSupportedException;
use yii\db\ActiveRecordInterface;
use yii\db\BaseActiveRecord;
use yii\helpers\Inflector; use yii\helpers\Inflector;
use yii\helpers\Json; use yii\helpers\Json;
use yii\helpers\StringHelper; use yii\helpers\StringHelper;
...@@ -42,7 +44,7 @@ use yii\helpers\StringHelper; ...@@ -42,7 +44,7 @@ use yii\helpers\StringHelper;
* @author Carsten Brandt <mail@cebe.cc> * @author Carsten Brandt <mail@cebe.cc>
* @since 2.0 * @since 2.0
*/ */
class ActiveRecord extends \yii\db\ActiveRecord class ActiveRecord extends BaseActiveRecord
{ {
const PRIMARY_KEY_NAME = 'id'; const PRIMARY_KEY_NAME = 'id';
...@@ -428,47 +430,4 @@ class ActiveRecord extends \yii\db\ActiveRecord ...@@ -428,47 +430,4 @@ class ActiveRecord extends \yii\db\ActiveRecord
} }
return $n; return $n;
} }
/**
* @inheritdoc
*/
public static function updateAllCounters($counters, $condition = null, $params = [])
{
throw new NotSupportedException('Update Counters is not supported by elasticsearch ActiveRecord.');
}
/**
* @inheritdoc
*/
public static function getTableSchema()
{
throw new NotSupportedException('getTableSchema() is not supported by elasticsearch ActiveRecord.');
}
/**
* @inheritdoc
*/
public static function tableName()
{
return static::index() . '/' . static::type();
}
/**
* @inheritdoc
*/
public static function findBySql($sql, $params = [])
{
throw new NotSupportedException('findBySql() is not supported by elasticsearch 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 elasticsearch.
* @param integer $operation the operation to check. Possible values are [[OP_INSERT]], [[OP_UPDATE]] and [[OP_DELETE]].
* @return boolean whether the specified operation is transactional in the current [[scenario]].
*/
public function isTransactional($operation)
{
return false;
}
} }
...@@ -132,7 +132,7 @@ class ActiveQuery extends \yii\base\Component implements ActiveQueryInterface ...@@ -132,7 +132,7 @@ class ActiveQuery extends \yii\base\Component implements ActiveQueryInterface
if ($db === null) { if ($db === null) {
$db = $modelClass::getDb(); $db = $modelClass::getDb();
} }
return $db->executeCommand('LLEN', [$modelClass::tableName()]); return $db->executeCommand('LLEN', [$modelClass::keyPrefix()]);
} else { } else {
return $this->executeScript($db, 'Count'); return $this->executeScript($db, 'Count');
} }
...@@ -296,7 +296,7 @@ class ActiveQuery extends \yii\base\Component implements ActiveQueryInterface ...@@ -296,7 +296,7 @@ class ActiveQuery extends \yii\base\Component implements ActiveQueryInterface
$data = []; $data = [];
foreach($pks as $pk) { foreach($pks as $pk) {
if (++$i > $start && ($this->limit === null || $i <= $start + $this->limit)) { if (++$i > $start && ($this->limit === null || $i <= $start + $this->limit)) {
$key = $modelClass::tableName() . ':a:' . $modelClass::buildKey($pk); $key = $modelClass::keyPrefix() . ':a:' . $modelClass::buildKey($pk);
$result = $db->executeCommand('HGETALL', [$key]); $result = $db->executeCommand('HGETALL', [$key]);
if (!empty($result)) { if (!empty($result)) {
$data[] = $result; $data[] = $result;
......
...@@ -9,6 +9,8 @@ namespace yii\redis; ...@@ -9,6 +9,8 @@ namespace yii\redis;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\base\NotSupportedException; use yii\base\NotSupportedException;
use yii\db\BaseActiveRecord;
use yii\helpers\Inflector;
use yii\helpers\StringHelper; use yii\helpers\StringHelper;
/** /**
...@@ -34,7 +36,7 @@ use yii\helpers\StringHelper; ...@@ -34,7 +36,7 @@ use yii\helpers\StringHelper;
* @author Carsten Brandt <mail@cebe.cc> * @author Carsten Brandt <mail@cebe.cc>
* @since 2.0 * @since 2.0
*/ */
class ActiveRecord extends \yii\db\ActiveRecord class ActiveRecord extends BaseActiveRecord
{ {
/** /**
* Returns the database connection used by this AR class. * Returns the database connection used by this AR class.
...@@ -87,6 +89,18 @@ class ActiveRecord extends \yii\db\ActiveRecord ...@@ -87,6 +89,18 @@ class ActiveRecord extends \yii\db\ActiveRecord
} }
/** /**
* Declares prefix of the key that represents the keys that store this records in redis.
* By default this method returns the class name as the table name by calling [[Inflector::camel2id()]].
* For example, 'Customer' becomes 'customer', and 'OrderItem' becomes
* 'order_item'. You may override this method if you want different key naming.
* @return string the prefix to apply to all AR keys
*/
public static function keyPrefix()
{
return Inflector::camel2id(StringHelper::basename(get_called_class()), '_');
}
/**
* @inheritdoc * @inheritdoc
*/ */
public function insert($runValidation = true, $attributes = null) public function insert($runValidation = true, $attributes = null)
...@@ -102,15 +116,15 @@ class ActiveRecord extends \yii\db\ActiveRecord ...@@ -102,15 +116,15 @@ class ActiveRecord extends \yii\db\ActiveRecord
foreach ($this->primaryKey() as $key) { foreach ($this->primaryKey() as $key) {
$pk[$key] = $values[$key] = $this->getAttribute($key); $pk[$key] = $values[$key] = $this->getAttribute($key);
if ($pk[$key] === null) { if ($pk[$key] === null) {
$pk[$key] = $values[$key] = $db->executeCommand('INCR', [static::tableName() . ':s:' . $key]); $pk[$key] = $values[$key] = $db->executeCommand('INCR', [static::keyPrefix() . ':s:' . $key]);
$this->setAttribute($key, $values[$key]); $this->setAttribute($key, $values[$key]);
} }
} }
// } // }
// save pk in a findall pool // save pk in a findall pool
$db->executeCommand('RPUSH', [static::tableName(), static::buildKey($pk)]); $db->executeCommand('RPUSH', [static::keyPrefix(), static::buildKey($pk)]);
$key = static::tableName() . ':a:' . static::buildKey($pk); $key = static::keyPrefix() . ':a:' . static::buildKey($pk);
// save attributes // save attributes
$args = [$key]; $args = [$key];
foreach($values as $attribute => $value) { foreach($values as $attribute => $value) {
...@@ -150,7 +164,7 @@ class ActiveRecord extends \yii\db\ActiveRecord ...@@ -150,7 +164,7 @@ class ActiveRecord extends \yii\db\ActiveRecord
foreach(static::fetchPks($condition) as $pk) { foreach(static::fetchPks($condition) as $pk) {
$newPk = $pk; $newPk = $pk;
$pk = static::buildKey($pk); $pk = static::buildKey($pk);
$key = static::tableName() . ':a:' . $pk; $key = static::keyPrefix() . ':a:' . $pk;
// save attributes // save attributes
$args = [$key]; $args = [$key];
foreach($attributes as $attribute => $value) { foreach($attributes as $attribute => $value) {
...@@ -161,13 +175,13 @@ class ActiveRecord extends \yii\db\ActiveRecord ...@@ -161,13 +175,13 @@ class ActiveRecord extends \yii\db\ActiveRecord
$args[] = $value; $args[] = $value;
} }
$newPk = static::buildKey($newPk); $newPk = static::buildKey($newPk);
$newKey = static::tableName() . ':a:' . $newPk; $newKey = static::keyPrefix() . ':a:' . $newPk;
// rename index if pk changed // rename index if pk changed
if ($newPk != $pk) { if ($newPk != $pk) {
$db->executeCommand('MULTI'); $db->executeCommand('MULTI');
$db->executeCommand('HMSET', $args); $db->executeCommand('HMSET', $args);
$db->executeCommand('LINSERT', [static::tableName(), 'AFTER', $pk, $newPk]); $db->executeCommand('LINSERT', [static::keyPrefix(), 'AFTER', $pk, $newPk]);
$db->executeCommand('LREM', [static::tableName(), 0, $pk]); $db->executeCommand('LREM', [static::keyPrefix(), 0, $pk]);
$db->executeCommand('RENAME', [$key, $newKey]); $db->executeCommand('RENAME', [$key, $newKey]);
$db->executeCommand('EXEC'); $db->executeCommand('EXEC');
} else { } else {
...@@ -201,7 +215,7 @@ class ActiveRecord extends \yii\db\ActiveRecord ...@@ -201,7 +215,7 @@ class ActiveRecord extends \yii\db\ActiveRecord
$db = static::getDb(); $db = static::getDb();
$n=0; $n=0;
foreach(static::fetchPks($condition) as $pk) { foreach(static::fetchPks($condition) as $pk) {
$key = static::tableName() . ':a:' . static::buildKey($pk); $key = static::keyPrefix() . ':a:' . static::buildKey($pk);
foreach($counters as $attribute => $value) { foreach($counters as $attribute => $value) {
$db->executeCommand('HINCRBY', [$key, $attribute, $value]); $db->executeCommand('HINCRBY', [$key, $attribute, $value]);
} }
...@@ -233,8 +247,8 @@ class ActiveRecord extends \yii\db\ActiveRecord ...@@ -233,8 +247,8 @@ class ActiveRecord extends \yii\db\ActiveRecord
$db->executeCommand('MULTI'); $db->executeCommand('MULTI');
foreach($pks as $pk) { foreach($pks as $pk) {
$pk = static::buildKey($pk); $pk = static::buildKey($pk);
$db->executeCommand('LREM', [static::tableName(), 0, $pk]); $db->executeCommand('LREM', [static::keyPrefix(), 0, $pk]);
$attributeKeys[] = static::tableName() . ':a:' . $pk; $attributeKeys[] = static::keyPrefix() . ':a:' . $pk;
} }
if (empty($attributeKeys)) { if (empty($attributeKeys)) {
$db->executeCommand('EXEC'); $db->executeCommand('EXEC');
...@@ -292,31 +306,4 @@ class ActiveRecord extends \yii\db\ActiveRecord ...@@ -292,31 +306,4 @@ class ActiveRecord extends \yii\db\ActiveRecord
} }
return md5(json_encode($key)); 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.
* @param integer $operation the operation to check. Possible values are [[OP_INSERT]], [[OP_UPDATE]] and [[OP_DELETE]].
* @return boolean whether the specified operation is transactional in the current [[scenario]].
*/
public function isTransactional($operation)
{
return false;
}
} }
...@@ -29,7 +29,7 @@ class LuaScriptBuilder extends \yii\base\Object ...@@ -29,7 +29,7 @@ class LuaScriptBuilder extends \yii\base\Object
// TODO add support for orderBy // TODO add support for orderBy
/** @var ActiveRecord $modelClass */ /** @var ActiveRecord $modelClass */
$modelClass = $query->modelClass; $modelClass = $query->modelClass;
$key = $this->quoteValue($modelClass::tableName() . ':a:'); $key = $this->quoteValue($modelClass::keyPrefix() . ':a:');
return $this->build($query, "n=n+1 pks[n]=redis.call('HGETALL',$key .. pk)", 'pks'); return $this->build($query, "n=n+1 pks[n]=redis.call('HGETALL',$key .. pk)", 'pks');
} }
...@@ -43,7 +43,7 @@ class LuaScriptBuilder extends \yii\base\Object ...@@ -43,7 +43,7 @@ class LuaScriptBuilder extends \yii\base\Object
// TODO add support for orderBy // TODO add support for orderBy
/** @var ActiveRecord $modelClass */ /** @var ActiveRecord $modelClass */
$modelClass = $query->modelClass; $modelClass = $query->modelClass;
$key = $this->quoteValue($modelClass::tableName() . ':a:'); $key = $this->quoteValue($modelClass::keyPrefix() . ':a:');
return $this->build($query, "do return redis.call('HGETALL',$key .. pk) end", 'pks'); return $this->build($query, "do return redis.call('HGETALL',$key .. pk) end", 'pks');
} }
...@@ -58,7 +58,7 @@ class LuaScriptBuilder extends \yii\base\Object ...@@ -58,7 +58,7 @@ class LuaScriptBuilder extends \yii\base\Object
// TODO add support for orderBy and indexBy // TODO add support for orderBy and indexBy
/** @var ActiveRecord $modelClass */ /** @var ActiveRecord $modelClass */
$modelClass = $query->modelClass; $modelClass = $query->modelClass;
$key = $this->quoteValue($modelClass::tableName() . ':a:'); $key = $this->quoteValue($modelClass::keyPrefix() . ':a:');
return $this->build($query, "n=n+1 pks[n]=redis.call('HGET',$key .. pk," . $this->quoteValue($column) . ")", 'pks'); return $this->build($query, "n=n+1 pks[n]=redis.call('HGET',$key .. pk," . $this->quoteValue($column) . ")", 'pks');
} }
...@@ -82,7 +82,7 @@ class LuaScriptBuilder extends \yii\base\Object ...@@ -82,7 +82,7 @@ class LuaScriptBuilder extends \yii\base\Object
{ {
/** @var ActiveRecord $modelClass */ /** @var ActiveRecord $modelClass */
$modelClass = $query->modelClass; $modelClass = $query->modelClass;
$key = $this->quoteValue($modelClass::tableName() . ':a:'); $key = $this->quoteValue($modelClass::keyPrefix() . ':a:');
return $this->build($query, "n=n+redis.call('HGET',$key .. pk," . $this->quoteValue($column) . ")", 'n'); return $this->build($query, "n=n+redis.call('HGET',$key .. pk," . $this->quoteValue($column) . ")", 'n');
} }
...@@ -96,7 +96,7 @@ class LuaScriptBuilder extends \yii\base\Object ...@@ -96,7 +96,7 @@ class LuaScriptBuilder extends \yii\base\Object
{ {
/** @var ActiveRecord $modelClass */ /** @var ActiveRecord $modelClass */
$modelClass = $query->modelClass; $modelClass = $query->modelClass;
$key = $this->quoteValue($modelClass::tableName() . ':a:'); $key = $this->quoteValue($modelClass::keyPrefix() . ':a:');
return $this->build($query, "n=n+1 if v==nil then v=0 end v=v+redis.call('HGET',$key .. pk," . $this->quoteValue($column) . ")", 'v/n'); return $this->build($query, "n=n+1 if v==nil then v=0 end v=v+redis.call('HGET',$key .. pk," . $this->quoteValue($column) . ")", 'v/n');
} }
...@@ -110,7 +110,7 @@ class LuaScriptBuilder extends \yii\base\Object ...@@ -110,7 +110,7 @@ class LuaScriptBuilder extends \yii\base\Object
{ {
/** @var ActiveRecord $modelClass */ /** @var ActiveRecord $modelClass */
$modelClass = $query->modelClass; $modelClass = $query->modelClass;
$key = $this->quoteValue($modelClass::tableName() . ':a:'); $key = $this->quoteValue($modelClass::keyPrefix() . ':a:');
return $this->build($query, "n=redis.call('HGET',$key .. pk," . $this->quoteValue($column) . ") if v==nil or n<v then v=n end", 'v'); return $this->build($query, "n=redis.call('HGET',$key .. pk," . $this->quoteValue($column) . ") if v==nil or n<v then v=n end", 'v');
} }
...@@ -124,7 +124,7 @@ class LuaScriptBuilder extends \yii\base\Object ...@@ -124,7 +124,7 @@ class LuaScriptBuilder extends \yii\base\Object
{ {
/** @var ActiveRecord $modelClass */ /** @var ActiveRecord $modelClass */
$modelClass = $query->modelClass; $modelClass = $query->modelClass;
$key = $this->quoteValue($modelClass::tableName() . ':a:'); $key = $this->quoteValue($modelClass::keyPrefix() . ':a:');
return $this->build($query, "n=redis.call('HGET',$key .. pk," . $this->quoteValue($column) . ") if v==nil or n>v then v=n end", 'v'); return $this->build($query, "n=redis.call('HGET',$key .. pk," . $this->quoteValue($column) . ") if v==nil or n>v then v=n end", 'v');
} }
...@@ -152,7 +152,7 @@ class LuaScriptBuilder extends \yii\base\Object ...@@ -152,7 +152,7 @@ class LuaScriptBuilder extends \yii\base\Object
/** @var ActiveRecord $modelClass */ /** @var ActiveRecord $modelClass */
$modelClass = $query->modelClass; $modelClass = $query->modelClass;
$key = $this->quoteValue($modelClass::tableName()); $key = $this->quoteValue($modelClass::keyPrefix());
$loadColumnValues = ''; $loadColumnValues = '';
foreach($columns as $column => $alias) { foreach($columns as $column => $alias) {
$loadColumnValues .= "local $alias=redis.call('HGET',$key .. ':a:' .. pk, '$column')\n"; $loadColumnValues .= "local $alias=redis.call('HGET',$key .. ':a:' .. pk, '$column')\n";
......
...@@ -104,7 +104,7 @@ trait ActiveRelationTrait ...@@ -104,7 +104,7 @@ trait ActiveRelationTrait
if (count($primaryModels) === 1 && !$this->multiple) { if (count($primaryModels) === 1 && !$this->multiple) {
$model = $this->one(); $model = $this->one();
foreach ($primaryModels as $i => $primaryModel) { foreach ($primaryModels as $i => $primaryModel) {
if ($primaryModel instanceof ActiveRecord) { if ($primaryModel instanceof ActiveRecordInterface) {
$primaryModel->populateRelation($name, $model); $primaryModel->populateRelation($name, $model);
} else { } else {
$primaryModels[$i][$name] = $model; $primaryModels[$i][$name] = $model;
...@@ -123,7 +123,7 @@ trait ActiveRelationTrait ...@@ -123,7 +123,7 @@ trait ActiveRelationTrait
foreach ($primaryModels as $i => $primaryModel) { foreach ($primaryModels as $i => $primaryModel) {
$key = $this->getModelKey($primaryModel, $link); $key = $this->getModelKey($primaryModel, $link);
$value = isset($buckets[$key]) ? $buckets[$key] : ($this->multiple ? [] : null); $value = isset($buckets[$key]) ? $buckets[$key] : ($this->multiple ? [] : null);
if ($primaryModel instanceof ActiveRecord) { if ($primaryModel instanceof ActiveRecordInterface) {
$primaryModel->populateRelation($name, $value); $primaryModel->populateRelation($name, $value);
} else { } else {
$primaryModels[$i][$name] = $value; $primaryModels[$i][$name] = $value;
......
...@@ -11,6 +11,7 @@ use Yii; ...@@ -11,6 +11,7 @@ use Yii;
use yii\base\Component; use yii\base\Component;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\db\ActiveRecord; use yii\db\ActiveRecord;
use yii\db\ActiveRecordInterface;
use yii\db\Connection; use yii\db\Connection;
/** /**
...@@ -92,7 +93,7 @@ class DbFixtureManager extends Component ...@@ -92,7 +93,7 @@ class DbFixtureManager extends Component
foreach ($fixtures as $name => $fixture) { foreach ($fixtures as $name => $fixture) {
if (strpos($fixture, '\\') !== false) { if (strpos($fixture, '\\') !== false) {
$model = new $fixture; $model = new $fixture;
if ($model instanceof ActiveRecord) { if ($model instanceof ActiveRecordInterface) {
$this->_modelClasses[$name] = $fixture; $this->_modelClasses[$name] = $fixture;
$fixtures[$name] = $model->getTableSchema()->name; $fixtures[$name] = $model->getTableSchema()->name;
} else { } else {
......
...@@ -10,6 +10,7 @@ namespace yii\validators; ...@@ -10,6 +10,7 @@ namespace yii\validators;
use Yii; use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\db\ActiveRecord; use yii\db\ActiveRecord;
use yii\db\ActiveRecordInterface;
/** /**
* UniqueValidator validates that the attribute value is unique in the corresponding database table. * UniqueValidator validates that the attribute value is unique in the corresponding database table.
...@@ -67,7 +68,7 @@ class UniqueValidator extends Validator ...@@ -67,7 +68,7 @@ class UniqueValidator extends Validator
$query = $className::find(); $query = $className::find();
$query->where([$attributeName => $value]); $query->where([$attributeName => $value]);
if (!$object instanceof ActiveRecord || $object->getIsNewRecord()) { if (!$object instanceof ActiveRecordInterface || $object->getIsNewRecord()) {
// if current $object isn't in the database yet then it's OK just to call exists() // if current $object isn't in the database yet then it's OK just to call exists()
$exists = $query->exists(); $exists = $query->exists();
} else { } else {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment