Commit 2cab70b0 by Carsten Brandt

Ensure consistent behavior in ActiveRecord::afterSave()

fixes #4012
parent cb87d7be
......@@ -395,35 +395,31 @@ class ActiveRecord extends BaseActiveRecord
if ($runValidation && !$this->validate($attributes)) {
return false;
}
if ($this->beforeSave(true)) {
$values = $this->getDirtyAttributes($attributes);
$response = static::getDb()->createCommand()->insert(
static::index(),
static::type(),
$values,
$this->getPrimaryKey(),
$options
);
// if (!isset($response['ok'])) {
// return false;
// }
$pk = static::primaryKey()[0];
$this->$pk = $response['_id'];
if ($pk != '_id') {
$values[$pk] = $response['_id'];
}
$this->_version = $response['_version'];
$this->_score = null;
if (!$this->beforeSave(true)) {
return false;
}
$values = $this->getDirtyAttributes($attributes);
$this->afterSave(true);
$this->setOldAttributes($values);
$response = static::getDb()->createCommand()->insert(
static::index(),
static::type(),
$values,
$this->getPrimaryKey(),
$options
);
return true;
$pk = static::primaryKey()[0];
$this->$pk = $response['_id'];
if ($pk != '_id') {
$values[$pk] = $response['_id'];
}
$this->_version = $response['_version'];
$this->_score = null;
$this->setOldAttributes($values);
$this->afterSave(true, $values);
return false;
return true;
}
/**
......
......@@ -224,8 +224,8 @@ abstract class ActiveRecord extends BaseActiveRecord
$this->setAttribute('_id', $newId);
$values['_id'] = $newId;
$this->afterSave(true);
$this->setOldAttributes($values);
$this->afterSave(true, $values);
return true;
}
......@@ -241,7 +241,7 @@ abstract class ActiveRecord extends BaseActiveRecord
}
$values = $this->getDirtyAttributes($attributes);
if (empty($values)) {
$this->afterSave(false);
$this->afterSave(false, $values);
return 0;
}
$condition = $this->getOldPrimaryKey(true);
......@@ -260,10 +260,10 @@ abstract class ActiveRecord extends BaseActiveRecord
throw new StaleObjectException('The object being updated is outdated.');
}
$this->afterSave(false);
foreach ($values as $name => $value) {
$this->setOldAttribute($name, $this->getAttribute($name));
}
$this->afterSave(false, $values);
return $rows;
}
......
......@@ -127,8 +127,8 @@ abstract class ActiveRecord extends \yii\mongodb\ActiveRecord
$this->setAttribute('_id', $newId);
$values['_id'] = $newId;
$this->afterSave(true);
$this->setOldAttributes($values);
$this->afterSave(true, $values);
return true;
}
......@@ -144,7 +144,7 @@ abstract class ActiveRecord extends \yii\mongodb\ActiveRecord
}
$values = $this->getDirtyAttributes($attributes);
if (empty($values)) {
$this->afterSave(false);
$this->afterSave(false, $values);
return 0;
}
......@@ -196,10 +196,10 @@ abstract class ActiveRecord extends \yii\mongodb\ActiveRecord
}
}
$this->afterSave(false);
foreach ($values as $name => $value) {
$this->setOldAttribute($name, $this->getAttribute($name));
}
$this->afterSave(false, $values);
return $rows;
}
......
......@@ -99,38 +99,35 @@ class ActiveRecord extends BaseActiveRecord
if ($runValidation && !$this->validate($attributes)) {
return false;
}
if ($this->beforeSave(true)) {
$db = static::getDb();
$values = $this->getDirtyAttributes($attributes);
$pk = [];
// if ($values === []) {
foreach ($this->primaryKey() as $key) {
$pk[$key] = $values[$key] = $this->getAttribute($key);
if ($pk[$key] === null) {
$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::keyPrefix(), static::buildKey($pk)]);
$key = static::keyPrefix() . ':a:' . static::buildKey($pk);
// save attributes
$args = [$key];
foreach ($values as $attribute => $value) {
$args[] = $attribute;
$args[] = $value;
if (!$this->beforeSave(true)) {
return false;
}
$db = static::getDb();
$values = $this->getDirtyAttributes($attributes);
$pk = [];
foreach ($this->primaryKey() as $key) {
$pk[$key] = $values[$key] = $this->getAttribute($key);
if ($pk[$key] === null) {
$pk[$key] = $values[$key] = $db->executeCommand('INCR', [static::keyPrefix() . ':s:' . $key]);
$this->setAttribute($key, $values[$key]);
}
$db->executeCommand('HMSET', $args);
$this->afterSave(true);
$this->setOldAttributes($values);
}
// save pk in a findall pool
$db->executeCommand('RPUSH', [static::keyPrefix(), static::buildKey($pk)]);
return true;
$key = static::keyPrefix() . ':a:' . static::buildKey($pk);
// save attributes
$args = [$key];
foreach ($values as $attribute => $value) {
$args[] = $attribute;
$args[] = $value;
}
$db->executeCommand('HMSET', $args);
$this->setOldAttributes($values);
$this->afterSave(true, $values);
return false;
return true;
}
/**
......
......@@ -395,8 +395,8 @@ abstract class ActiveRecord extends BaseActiveRecord
return false;
}
$this->afterSave(true);
$this->setOldAttributes($values);
$this->afterSave(true, $values);
return true;
}
......@@ -488,7 +488,7 @@ abstract class ActiveRecord extends BaseActiveRecord
}
$values = $this->getDirtyAttributes($attributes);
if (empty($values)) {
$this->afterSave(false);
$this->afterSave(false, $values);
return 0;
}
......@@ -530,10 +530,10 @@ abstract class ActiveRecord extends BaseActiveRecord
}
}
$this->afterSave(false);
foreach ($values as $name => $value) {
$this->setOldAttribute($name, $this->getAttribute($name));
}
$this->afterSave(false, $values);
return $rows;
}
......
......@@ -21,6 +21,7 @@ Yii Framework 2 Change Log
- Bug #3194: Date formatter works only for timestamps in the year range 1970 to 2038 (kartik-v)
- Bug #3204: `yii\di\Container` did not handle the `$config` parameter well in case when it does not have a default value (qiangxue)
- Bug #3216: Fixed the bug that `yii.activeForm.destroy()` did not remove `submit` event handlers (qiangxue)
- Bug #3233: Ensure consistent behavior in ActiveRecord::afterSave() (cebe, qiangxue)
- Bug #3236: Return value for DateTime->format('U') casted to double to allow correct date formatting (pgaultier)
- Bug #3268: Fixed the bug that the schema name in a table name was not respected by `yii\db\mysql\Schema` (terazoid, qiangxue)
- Bug #3311: Fixed the bug that `yii\di\Container::has()` did not return correct value (mgrechanik, qiangxue)
......
......@@ -55,3 +55,7 @@ Upgrade from Yii 2.0 Beta
This change is needed because `yii\web\View` no longer automatically generates CSRF meta tags due to issue #3358.
* If your model code is using the `file` validation rule, you should rename its `types` option to `extensions`.
* The behavior and signature of `ActiveRecord::afterSave()` has changed. `ActiveRecord::$isNewRecord` will now always be
false in afterSave and also dirty attributes are not available. This change has been made to have a more consistent and
expected behavior. The changed attributes are now available in the new parameter of afterSave() `$changedAttributes`.
\ No newline at end of file
......@@ -431,8 +431,8 @@ class ActiveRecord extends BaseActiveRecord
}
}
$this->afterSave(true);
$this->setOldAttributes($values);
$this->afterSave(true, $values);
return true;
}
......
......@@ -680,7 +680,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
}
$values = $this->getDirtyAttributes($attributes);
if (empty($values)) {
$this->afterSave(false);
$this->afterSave(false, $values);
return 0;
}
$condition = $this->getOldPrimaryKey(true);
......@@ -699,10 +699,10 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
throw new StaleObjectException('The object being updated is outdated.');
}
$this->afterSave(false);
foreach ($values as $name => $value) {
$this->_oldAttributes[$name] = $this->_attributes[$name];
}
$this->afterSave(false, $values);
return $rows;
}
......@@ -859,11 +859,14 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
* When overriding this method, make sure you call the parent implementation so that
* the event is triggered.
* @param boolean $insert whether this method called while inserting a record.
* @param array $changedAttributes the attribute values that have changed during save.
* If false, it means the method is called while updating a record.
*/
public function afterSave($insert)
public function afterSave($insert, $changedAttributes)
{
$this->trigger($insert ? self::EVENT_AFTER_INSERT : self::EVENT_AFTER_UPDATE);
$this->trigger($insert ? self::EVENT_AFTER_INSERT : self::EVENT_AFTER_UPDATE, new ModelEvent([
'data' => ['changedAttributes' => $changedAttributes]
]));
}
/**
......
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