upgrade(); * ``` * * @author Salem Ouerdani * @since 2.0.16 * @see \yii\db\BaseActiveRecord::optimisticLock() for details on how to enable optimistic lock. */ class OptimisticLockBehavior extends AttributeBehavior { /** * {@inheritdoc} * * In case of `null` value it will be directly parsed from [[\yii\web\Request::getBodyParam()|getBodyParam()]] or set to 0. */ public $value; /** * {@inheritdoc} */ public $skipUpdateOnClean = false; /** * @var string the attribute name holding the version value. */ private $_lockAttribute; /** * {@inheritdoc} */ public function attach($owner) { parent::attach($owner); if (empty($this->attributes)) { $lock = $this->getLockAttribute(); $this->attributes = array_fill_keys(array_keys($this->events()), $lock); } } /** * {@inheritdoc} */ public function events() { return Yii::$app->request instanceof \yii\web\Request ? [ BaseActiveRecord::EVENT_BEFORE_INSERT => 'evaluateAttributes', BaseActiveRecord::EVENT_BEFORE_UPDATE => 'evaluateAttributes', BaseActiveRecord::EVENT_BEFORE_DELETE => 'evaluateAttributes', ] : []; } /** * Returns the column name to hold the version value as defined in [[\yii\db\BaseActiveRecord::optimisticLock()|optimisticLock()]]. * @return string the property name. * @throws InvalidCallException if [[\yii\db\BaseActiveRecord::optimisticLock()|optimisticLock()]] is not properly configured. * @since 2.0.16 */ protected function getLockAttribute() { if ($this->_lockAttribute) { return $this->_lockAttribute; } /* @var $owner BaseActiveRecord */ $owner = $this->owner; $lock = $owner->optimisticLock(); if ($lock === null || $owner->hasAttribute($lock) === false) { throw new InvalidCallException("Unable to get the optimistic lock attribute. Probably 'optimisticLock()' method is misconfigured."); } $this->_lockAttribute = $lock; return $lock; } /** * {@inheritdoc} * * In case of `null`, value will be parsed from [[\yii\web\Request::getBodyParam()|getBodyParam()]] or set to 0. */ protected function getValue($event) { if ($this->value === null) { $request = Yii::$app->getRequest(); $lock = $this->getLockAttribute(); $formName = $this->owner->formName(); $formValue = $formName ? ArrayHelper::getValue($request->getBodyParams(), $formName . '.' . $lock) : null; $input = $formValue ?: $request->getBodyParam($lock); $isValid = $input && (new NumberValidator())->validate($input); return $isValid ? $input : 0; } return parent::getValue($event); } /** * Upgrades the version value by one and stores it to database. * * ```php * $model->upgrade(); * ``` * @throws InvalidCallException if owner is a new record. * @since 2.0.16 */ public function upgrade() { /* @var $owner BaseActiveRecord */ $owner = $this->owner; if ($owner->getIsNewRecord()) { throw new InvalidCallException('Upgrading the model version is not possible on a new record.'); } $lock = $this->getLockAttribute(); $version = $owner->$lock ?: 0; $owner->updateAttributes([$lock => $version + 1]); } }