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;
use yii\base\InvalidCallException;
use yii\base\InvalidConfigException;
use yii\base\NotSupportedException;
use yii\db\ActiveRecordInterface;
use yii\db\BaseActiveRecord;
use yii\helpers\Inflector;
use yii\helpers\Json;
use yii\helpers\StringHelper;
......@@ -42,7 +44,7 @@ use yii\helpers\StringHelper;
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class ActiveRecord extends \yii\db\ActiveRecord
class ActiveRecord extends BaseActiveRecord
{
const PRIMARY_KEY_NAME = 'id';
......@@ -428,47 +430,4 @@ class ActiveRecord extends \yii\db\ActiveRecord
}
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
if ($db === null) {
$db = $modelClass::getDb();
}
return $db->executeCommand('LLEN', [$modelClass::tableName()]);
return $db->executeCommand('LLEN', [$modelClass::keyPrefix()]);
} else {
return $this->executeScript($db, 'Count');
}
......@@ -296,7 +296,7 @@ class ActiveQuery extends \yii\base\Component implements ActiveQueryInterface
$data = [];
foreach($pks as $pk) {
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]);
if (!empty($result)) {
$data[] = $result;
......
......@@ -9,6 +9,8 @@ namespace yii\redis;
use yii\base\InvalidConfigException;
use yii\base\NotSupportedException;
use yii\db\BaseActiveRecord;
use yii\helpers\Inflector;
use yii\helpers\StringHelper;
/**
......@@ -34,7 +36,7 @@ use yii\helpers\StringHelper;
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class ActiveRecord extends \yii\db\ActiveRecord
class ActiveRecord extends BaseActiveRecord
{
/**
* Returns the database connection used by this AR class.
......@@ -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
*/
public function insert($runValidation = true, $attributes = null)
......@@ -102,15 +116,15 @@ class ActiveRecord extends \yii\db\ActiveRecord
foreach ($this->primaryKey() as $key) {
$pk[$key] = $values[$key] = $this->getAttribute($key);
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]);
}
}
// }
// 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
$args = [$key];
foreach($values as $attribute => $value) {
......@@ -150,7 +164,7 @@ class ActiveRecord extends \yii\db\ActiveRecord
foreach(static::fetchPks($condition) as $pk) {
$newPk = $pk;
$pk = static::buildKey($pk);
$key = static::tableName() . ':a:' . $pk;
$key = static::keyPrefix() . ':a:' . $pk;
// save attributes
$args = [$key];
foreach($attributes as $attribute => $value) {
......@@ -161,13 +175,13 @@ class ActiveRecord extends \yii\db\ActiveRecord
$args[] = $value;
}
$newPk = static::buildKey($newPk);
$newKey = static::tableName() . ':a:' . $newPk;
$newKey = static::keyPrefix() . ':a:' . $newPk;
// rename index if pk changed
if ($newPk != $pk) {
$db->executeCommand('MULTI');
$db->executeCommand('HMSET', $args);
$db->executeCommand('LINSERT', [static::tableName(), 'AFTER', $pk, $newPk]);
$db->executeCommand('LREM', [static::tableName(), 0, $pk]);
$db->executeCommand('LINSERT', [static::keyPrefix(), 'AFTER', $pk, $newPk]);
$db->executeCommand('LREM', [static::keyPrefix(), 0, $pk]);
$db->executeCommand('RENAME', [$key, $newKey]);
$db->executeCommand('EXEC');
} else {
......@@ -201,7 +215,7 @@ class ActiveRecord extends \yii\db\ActiveRecord
$db = static::getDb();
$n=0;
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) {
$db->executeCommand('HINCRBY', [$key, $attribute, $value]);
}
......@@ -233,8 +247,8 @@ class ActiveRecord extends \yii\db\ActiveRecord
$db->executeCommand('MULTI');
foreach($pks as $pk) {
$pk = static::buildKey($pk);
$db->executeCommand('LREM', [static::tableName(), 0, $pk]);
$attributeKeys[] = static::tableName() . ':a:' . $pk;
$db->executeCommand('LREM', [static::keyPrefix(), 0, $pk]);
$attributeKeys[] = static::keyPrefix() . ':a:' . $pk;
}
if (empty($attributeKeys)) {
$db->executeCommand('EXEC');
......@@ -292,31 +306,4 @@ 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.
* @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
// TODO add support for orderBy
/** @var ActiveRecord $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');
}
......@@ -43,7 +43,7 @@ class LuaScriptBuilder extends \yii\base\Object
// TODO add support for orderBy
/** @var ActiveRecord $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');
}
......@@ -58,7 +58,7 @@ class LuaScriptBuilder extends \yii\base\Object
// TODO add support for orderBy and indexBy
/** @var ActiveRecord $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');
}
......@@ -82,7 +82,7 @@ class LuaScriptBuilder extends \yii\base\Object
{
/** @var ActiveRecord $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');
}
......@@ -96,7 +96,7 @@ class LuaScriptBuilder extends \yii\base\Object
{
/** @var ActiveRecord $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');
}
......@@ -110,7 +110,7 @@ class LuaScriptBuilder extends \yii\base\Object
{
/** @var ActiveRecord $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');
}
......@@ -124,7 +124,7 @@ class LuaScriptBuilder extends \yii\base\Object
{
/** @var ActiveRecord $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');
}
......@@ -152,7 +152,7 @@ class LuaScriptBuilder extends \yii\base\Object
/** @var ActiveRecord $modelClass */
$modelClass = $query->modelClass;
$key = $this->quoteValue($modelClass::tableName());
$key = $this->quoteValue($modelClass::keyPrefix());
$loadColumnValues = '';
foreach($columns as $column => $alias) {
$loadColumnValues .= "local $alias=redis.call('HGET',$key .. ':a:' .. pk, '$column')\n";
......
......@@ -104,7 +104,7 @@ trait ActiveRelationTrait
if (count($primaryModels) === 1 && !$this->multiple) {
$model = $this->one();
foreach ($primaryModels as $i => $primaryModel) {
if ($primaryModel instanceof ActiveRecord) {
if ($primaryModel instanceof ActiveRecordInterface) {
$primaryModel->populateRelation($name, $model);
} else {
$primaryModels[$i][$name] = $model;
......@@ -123,7 +123,7 @@ trait ActiveRelationTrait
foreach ($primaryModels as $i => $primaryModel) {
$key = $this->getModelKey($primaryModel, $link);
$value = isset($buckets[$key]) ? $buckets[$key] : ($this->multiple ? [] : null);
if ($primaryModel instanceof ActiveRecord) {
if ($primaryModel instanceof ActiveRecordInterface) {
$primaryModel->populateRelation($name, $value);
} else {
$primaryModels[$i][$name] = $value;
......
......@@ -11,6 +11,7 @@ use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
use yii\db\ActiveRecord;
use yii\db\ActiveRecordInterface;
use yii\db\Connection;
/**
......@@ -92,7 +93,7 @@ class DbFixtureManager extends Component
foreach ($fixtures as $name => $fixture) {
if (strpos($fixture, '\\') !== false) {
$model = new $fixture;
if ($model instanceof ActiveRecord) {
if ($model instanceof ActiveRecordInterface) {
$this->_modelClasses[$name] = $fixture;
$fixtures[$name] = $model->getTableSchema()->name;
} else {
......
......@@ -10,6 +10,7 @@ namespace yii\validators;
use Yii;
use yii\base\InvalidConfigException;
use yii\db\ActiveRecord;
use yii\db\ActiveRecordInterface;
/**
* UniqueValidator validates that the attribute value is unique in the corresponding database table.
......@@ -67,7 +68,7 @@ class UniqueValidator extends Validator
$query = $className::find();
$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()
$exists = $query->exists();
} 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