# OptimisticLockBehavior

> OptimisticLockBehavior automatically upgrades a model's lock version using the column name returned by optimisticLock() (yii\db\BaseActiveRecord::optimisticLock()).

[API reference](/docs/api/index.md) › [yii](/docs/api/yii/index.md) › [behaviors](/docs/api/yii/behaviors/index.md) › OptimisticLockBehavior

| class | `yii\behaviors\OptimisticLockBehavior` |
| --- | --- |
| Extends | [`AttributeBehavior`](/docs/api/yii/behaviors/attributebehavior/index.md) » [`yii\base\Behavior`](/docs/api/yii/base/behavior/index.md) » [`yii\base\BaseObject`](/docs/api/yii/base/baseobject/index.md) |
| Implements | [`yii\base\Configurable`](/docs/api/yii/base/configurable/index.md) |
| Since | 2.0.16 |
| Source | [`framework/behaviors/OptimisticLockBehavior.php`](https://github.com/yiisoft/yii2/blob/22.0/framework/behaviors/OptimisticLockBehavior.php#L69) |

OptimisticLockBehavior automatically upgrades a model's lock version using the column name
returned by [optimisticLock()](/docs/api/yii/db/baseactiverecord/index.md#method-optimisticLock).

Optimistic locking allows multiple users to access the same record for edits and avoids
potential conflicts. In case when a user attempts to save the record upon some staled data
(because another user has modified the data), a `StaleObjectException` exception will be thrown,
and the update or deletion is skipped.

To use this behavior, first enable optimistic lock by following the steps listed in
[optimisticLock()](/docs/api/yii/db/baseactiverecord/index.md#method-optimisticLock), remove the column name
holding the lock version from the [rules()](/docs/api/yii/base/model/index.md#method-rules) method of your
ActiveRecord class, then add the following code to it:

```
use yii\behaviors\OptimisticLockBehavior;

public function behaviors()
{
    return [
        OptimisticLockBehavior::class,
    ];
}
```

By default, OptimisticLockBehavior will use [getBodyParam()](/docs/api/yii/web/request/index.md#method-getBodyParam) to parse
the submitted value or set it to 0 on any fail. That means a request not holding the version attribute
may achieve a first successful update to entity, but starting from there any further try should fail
unless the request is holding the expected version number.

Once attached, internal use of the model class should also fail to save the record if the version number
isn't held by [getBodyParam()](/docs/api/yii/web/request/index.md#method-getBodyParam). It may be useful to extend your model class,
enable optimistic lock in parent class by overriding [optimisticLock()](/docs/api/yii/db/baseactiverecord/index.md#method-optimisticLock),
then attach the behavior to the child class so you can tie the parent model to internal use while linking the child model
holding this behavior to the controllers responsible of receiving end user inputs.
Alternatively, you can also configure the [`$value`](/docs/api/yii/behaviors/optimisticlockbehavior/index.md#property-value) property with a PHP callable to implement a different logic.

OptimisticLockBehavior also provides a method named [`upgrade()`](/docs/api/yii/behaviors/optimisticlockbehavior/index.md#method-upgrade) that increases a model's
version by one, that may be useful when you need to mark an entity as stale among connected clients
and avoid any change to it until they load it again:

```
$model->upgrade();
```

See also: [`BaseActiveRecord::optimisticLock()`](/docs/api/yii/db/baseactiverecord/index.md#method-optimisticLock) (for details on how to enable optimistic lock.).

## Properties

| Property | Type | Description | Defined by |
| --- | --- | --- | --- |
| <span id="property-attributes"></span>[`$attributes`](/docs/api/yii/behaviors/attributebehavior/index.md#property-attributes) | `array` | List of attributes that are to be automatically filled with the value specified via [`$value`](/docs/api/yii/behaviors/attributebehavior/index.md#property-value). Default: `[]`. | [`AttributeBehavior`](/docs/api/yii/behaviors/attributebehavior/index.md) |
| <span id="property-owner"></span>[`$owner`](/docs/api/yii/base/behavior/index.md#property-owner) | `yii\base\T\|null` | The owner of this behavior Default: `null`. | [`yii\base\Behavior`](/docs/api/yii/base/behavior/index.md) |
| <span id="property-preserveNonEmptyValues"></span>[`$preserveNonEmptyValues`](/docs/api/yii/behaviors/attributebehavior/index.md#property-preserveNonEmptyValues) | `bool` | Whether to preserve non-empty attribute values. Default: `false`. Available since 2.0.13. | [`AttributeBehavior`](/docs/api/yii/behaviors/attributebehavior/index.md) |
| <span id="property-skipUpdateOnClean"></span>`$skipUpdateOnClean` | `bool` | Default: `false`. Available since 2.0.8. | `OptimisticLockBehavior` |
| [`$value`](#property-value) | `mixed` | Default: `null`. | `OptimisticLockBehavior` |

## Methods

| Method | Description | Defined by |
| --- | --- | --- |
| <span id="method-__construct"></span>[`__construct()`](/docs/api/yii/base/baseobject/index.md#method-__construct) | Constructor. | [`yii\base\BaseObject`](/docs/api/yii/base/baseobject/index.md) |
| <span id="method-__call"></span>[`__call()`](/docs/api/yii/base/baseobject/index.md#method-__call) | Calls the named method which is not a class method. | [`yii\base\BaseObject`](/docs/api/yii/base/baseobject/index.md) |
| <span id="method-__get"></span>[`__get()`](/docs/api/yii/base/baseobject/index.md#method-__get) | Returns the value of an object property. | [`yii\base\BaseObject`](/docs/api/yii/base/baseobject/index.md) |
| <span id="method-__isset"></span>[`__isset()`](/docs/api/yii/base/baseobject/index.md#method-__isset) | Checks if a property is set, i.e. defined and not null. | [`yii\base\BaseObject`](/docs/api/yii/base/baseobject/index.md) |
| <span id="method-__set"></span>[`__set()`](/docs/api/yii/base/baseobject/index.md#method-__set) | Sets value of an object property. | [`yii\base\BaseObject`](/docs/api/yii/base/baseobject/index.md) |
| <span id="method-__unset"></span>[`__unset()`](/docs/api/yii/base/baseobject/index.md#method-__unset) | Sets an object property to null. | [`yii\base\BaseObject`](/docs/api/yii/base/baseobject/index.md) |
| [`attach()`](#method-attach) | Attaches the behavior object to the component. | `OptimisticLockBehavior` |
| <span id="method-canGetProperty"></span>[`canGetProperty()`](/docs/api/yii/base/baseobject/index.md#method-canGetProperty) | Returns a value indicating whether a property can be read. | [`yii\base\BaseObject`](/docs/api/yii/base/baseobject/index.md) |
| <span id="method-canSetProperty"></span>[`canSetProperty()`](/docs/api/yii/base/baseobject/index.md#method-canSetProperty) | Returns a value indicating whether a property can be set. | [`yii\base\BaseObject`](/docs/api/yii/base/baseobject/index.md) |
| <span id="method-className"></span>[`className()`](/docs/api/yii/base/baseobject/index.md#method-className) static | Returns the fully qualified name of this class. | [`yii\base\BaseObject`](/docs/api/yii/base/baseobject/index.md) |
| <span id="method-detach"></span>[`detach()`](/docs/api/yii/base/behavior/index.md#method-detach) | Detaches the behavior object from the component. | [`yii\base\Behavior`](/docs/api/yii/base/behavior/index.md) |
| <span id="method-evaluateAttributes"></span>[`evaluateAttributes()`](/docs/api/yii/behaviors/attributebehavior/index.md#method-evaluateAttributes) | Evaluates the attribute value and assigns it to the current attributes. | [`AttributeBehavior`](/docs/api/yii/behaviors/attributebehavior/index.md) |
| [`events()`](#method-events) | Declares event handlers for the [`$owner`](/docs/api/yii/base/behavior/index.md#property-owner)'s events. | `OptimisticLockBehavior` |
| <span id="method-hasMethod"></span>[`hasMethod()`](/docs/api/yii/base/baseobject/index.md#method-hasMethod) | Returns a value indicating whether a method is defined. | [`yii\base\BaseObject`](/docs/api/yii/base/baseobject/index.md) |
| <span id="method-hasProperty"></span>[`hasProperty()`](/docs/api/yii/base/baseobject/index.md#method-hasProperty) | Returns a value indicating whether a property is defined. | [`yii\base\BaseObject`](/docs/api/yii/base/baseobject/index.md) |
| <span id="method-init"></span>[`init()`](/docs/api/yii/base/baseobject/index.md#method-init) | Initializes the object. | [`yii\base\BaseObject`](/docs/api/yii/base/baseobject/index.md) |
| [`upgrade()`](#method-upgrade) | Upgrades the version value by one and stores it to database. | `OptimisticLockBehavior` |
| [`getLockAttribute()`](#method-getLockAttribute) protected | Returns the column name to hold the version value as defined in [optimisticLock()](/docs/api/yii/db/baseactiverecord/index.md#method-optimisticLock). | `OptimisticLockBehavior` |
| [`getValue()`](#method-getValue) protected | Returns the value for the current attributes. | `OptimisticLockBehavior` |

## Property details

### $value <span id="property-value"></span>

```php
public mixed $value = null
```

In case of `null` value it will be directly parsed from [getBodyParam()](/docs/api/yii/web/request/index.md#method-getBodyParam) or set to 0.

This can be an anonymous function,
callable in array format (e.g. `[$this, 'methodName']`), an [Expression](/docs/api/yii/db/expression/index.md) object representing a DB expression
(e.g. `new Expression('NOW()')`), scalar, string or an arbitrary value. If the former, the return value of the
function will be assigned to the attributes.
The signature of the function should be as follows,

```
function ($event)
{
    // return value will be assigned to the attribute
}
```

## Method details

### attach() <span id="method-attach"></span>

```php
public function attach(mixed $owner): mixed
```

Attaches the behavior object to the component.

The default implementation will set the [`$owner`](/docs/api/yii/base/behavior/index.md#property-owner) property
and attach event handlers as declared in [`events()`](/docs/api/yii/behaviors/optimisticlockbehavior/index.md#method-events).
Make sure you call the parent implementation if you override this method.

**Parameters**

| Parameter | Type | Description |
| --- | --- | --- |
| `$owner` | `mixed` | The component that this behavior is to be attached to. |

**Returns**

`mixed`

### events() <span id="method-events"></span>

```php
public function events(): array
```

Declares event handlers for the [`$owner`](/docs/api/yii/base/behavior/index.md#property-owner)'s events.

Child classes may override this method to declare what PHP callbacks should
be attached to the events of the [`$owner`](/docs/api/yii/base/behavior/index.md#property-owner) component.

The callbacks will be attached to the [`$owner`](/docs/api/yii/base/behavior/index.md#property-owner)'s events when the behavior is
attached to the owner; and they will be detached from the events when
the behavior is detached from the component.

The callbacks can be any of the following:

- method in this behavior: `'handleClick'`, equivalent to `[$this, 'handleClick']`
- object method: `[$object, 'handleClick']`
- static method: `['Page', 'handleClick']`
- anonymous function: `function ($event) { ... }`

The following is an example:

```
[
    Model::EVENT_BEFORE_VALIDATE => 'myBeforeValidate',
    Model::EVENT_AFTER_VALIDATE => 'myAfterValidate',
]
```

**Returns**

`array`: Events (array keys) and the corresponding event handler methods (array values).

### upgrade() <span id="method-upgrade"></span>

```php
public function upgrade(): mixed
```

Upgrades the version value by one and stores it to database.

```
$model->upgrade();
```

**Returns**

`mixed`

**Throws**

- [`yii\base\InvalidCallException`](/docs/api/yii/base/invalidcallexception/index.md): if owner is a new record.

**Since**

2.0.16

### getLockAttribute() <span id="method-getLockAttribute"></span>

```php
protected function getLockAttribute(): string
```

Returns the column name to hold the version value as defined in [optimisticLock()](/docs/api/yii/db/baseactiverecord/index.md#method-optimisticLock).

**Returns**

`string`: The property name.

**Throws**

- [`yii\base\InvalidCallException`](/docs/api/yii/base/invalidcallexception/index.md): if [optimisticLock()](/docs/api/yii/db/baseactiverecord/index.md#method-optimisticLock) is not properly configured.

**Since**

2.0.16

### getValue() <span id="method-getValue"></span>

```php
protected function getValue(mixed $event): mixed
```

Returns the value for the current attributes.

In case of `null`, value will be parsed from [getBodyParam()](/docs/api/yii/web/request/index.md#method-getBodyParam) or set to 0.

This method is called by [`evaluateAttributes()`](/docs/api/yii/behaviors/attributebehavior/index.md#method-evaluateAttributes). Its return value will be assigned
to the attributes corresponding to the triggering event.

**Parameters**

| Parameter | Type | Description |
| --- | --- | --- |
| `$event` | `mixed` | The event that triggers the current attribute updating. |

**Returns**

`mixed`: The attribute value