クラス yii\behaviors\OptimisticLockBehavior
OptimisticLockBehavior は、optimisticLock() が返すカラム名を使用して、モデルのロックバージョンを自動的にアップグレードします。
楽観的ロックにより、複数のユーザーが同じレコードにアクセスして編集することができ、潜在的な競合を回避できます。あるユーザーが古いデータに基づいてレコードの保存を試みた場合(別のユーザーがデータを変更したため)、StaleObjectException 例外がスローされ、更新または削除はスキップされます。
このビヘイビアを使用するには、まず optimisticLock() に記載されている手順に従って楽観的ロックを有効にし、ロックバージョンを保持するカラム名を ActiveRecord クラスの rules() メソッドから削除し、以下のコードを追加します。
use yii\behaviors\OptimisticLockBehavior;
public function behaviors()
{
return [
OptimisticLockBehavior::class,
];
}
デフォルトでは、OptimisticLockBehavior は getBodyParam() を使用して送信された値を解析するか、失敗した場合に 0 に設定します。つまり、バージョン属性を持たないリクエストでは、エンティティへの最初の更新が成功する可能性がありますが、そこから先は、リクエストが期待されるバージョン番号を保持していない限り、それ以降の試行は失敗します。
getBodyParam() にバージョン番号が含まれていない場合、モデルクラスの内部使用でもレコードの保存は失敗します。親クラスで optimisticLock() をオーバーライドして楽観的ロックを有効にし、このビヘイビアを持つ子クラスにビヘイビアをアタッチすることで、親モデルを内部使用に結び付けながら、このビヘイビアを持つ子モデルをエンドユーザー入力を受信するコントローラーにリンクすることができます。あるいは、異なるロジックを実装するために、PHP の呼び出し可能オブジェクトで $value プロパティを構成することもできます。
OptimisticLockBehavior は、モデルのバージョンを 1 つ増やす upgrade() というメソッドも提供しています。これは、接続されたクライアント間でエンティティを古いものとしてマークし、クライアントが再度読み込むまで変更を回避する場合に役立ちます。
$model->upgrade();
楽観的ロックの有効化の詳細については、yii\db\BaseActiveRecord::optimisticLock() を参照してください。
公開プロパティ
プロパティ | 型 | 説明 | 定義元 |
---|---|---|---|
$attributes | array | $value を介して指定された値で自動的に埋められる属性のリスト。 | yii\behaviors\AttributeBehavior |
$owner | yii\base\Component|null | このビヘイビアの所有者 | yii\base\Behavior |
$preserveNonEmptyValues | boolean | 空でない属性値を保持するかどうか。 | yii\behaviors\AttributeBehavior |
$skipUpdateOnClean | boolean | $owner が変更されていない場合にこのビヘイビアをスキップするかどうか。 |
yii\behaviors\OptimisticLockBehavior |
$value | mixed | 現在の属性に割り当てられる値。 | yii\behaviors\OptimisticLockBehavior |
公開メソッド
保護されたメソッド
メソッド | 説明 | 定義元 |
---|---|---|
getLockAttribute() | optimisticLock() で定義されているように、バージョン値を保持するカラム名を返します。 | yii\behaviors\OptimisticLockBehavior |
getValue() | 現在の属性の値を返します。 | yii\behaviors\OptimisticLockBehavior |
プロパティの詳細
$owner
が変更されていない場合にこのビヘイビアをスキップするかどうか。
null
の値の場合、getBodyParam() から直接解析されるか、0 に設定されます。
現在の属性に割り当てられる値です。これは、無名関数、配列形式の呼び出し可能関数(例:[$this, 'methodName']
)、DB式を表すExpressionオブジェクト(例:new Expression('NOW()')
)、スカラー、文字列、または任意の値にすることができます。関数の場合は、関数の戻り値が属性に割り当てられます。関数のシグネチャは次のようになります。
function ($event)
{
// return value will be assigned to the attribute
}
メソッドの詳細
定義場所: yii\base\BaseObject::__call()
クラスメソッドではない名前付きメソッドを呼び出します。
これはPHPのマジックメソッドであり、未知のメソッドが呼び出された際に暗黙的に呼び出されるため、直接呼び出さないでください。
public mixed __call ( $name, $params ) | ||
$name | string |
メソッド名 |
$params | array |
メソッドパラメータ |
戻り値 | mixed |
メソッドの戻り値 |
---|---|---|
例外 | yii\base\UnknownMethodException |
未知のメソッドを呼び出した場合 |
public function __call($name, $params)
{
throw new UnknownMethodException('Calling unknown method: ' . get_class($this) . "::$name()");
}
定義場所: yii\base\BaseObject::__construct()
コンストラクタ。
デフォルトの実装では、次の2つのことを行います。
- 指定された設定
$config
を使用してオブジェクトを初期化します。 - init() を呼び出します。
このメソッドを子クラスでオーバーライドする場合は、
- コンストラクタの最後の引数を設定配列(ここの
$config
のように)にすることをお勧めします。 - コンストラクタの最後に親の実装を呼び出してください。
public void __construct ( $config = [] ) | ||
$config | array |
オブジェクトのプロパティを初期化するために使用される名前と値のペア |
public function __construct($config = [])
{
if (!empty($config)) {
Yii::configure($this, $config);
}
$this->init();
}
定義場所: yii\base\BaseObject::__get()
オブジェクトプロパティの値を返します。
これはPHPのマジックメソッドであり、$value = $object->property;
を実行した際に暗黙的に呼び出されるため、直接呼び出さないでください。
__set()も参照してください。
public mixed __get ( $name ) | ||
$name | string |
プロパティ名 |
戻り値 | mixed |
プロパティの値 |
---|---|---|
例外 | yii\base\UnknownPropertyException |
プロパティが定義されていない場合 |
例外 | yii\base\InvalidCallException |
プロパティが書き込み専用の場合 |
public function __get($name)
{
$getter = 'get' . $name;
if (method_exists($this, $getter)) {
return $this->$getter();
} elseif (method_exists($this, 'set' . $name)) {
throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name);
}
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
}
定義場所: yii\base\BaseObject::__isset()
プロパティが設定されているかどうか(つまり、定義されていて null でないかどうか)をチェックします。
これはPHPのマジックメソッドであり、isset($object->property)
を実行した際に暗黙的に呼び出されるため、直接呼び出さないでください。
プロパティが定義されていない場合は、falseが返されることに注意してください。
public boolean __isset ( $name ) | ||
$name | string |
プロパティ名またはイベント名 |
戻り値 | boolean |
指定されたプロパティが設定されているかどうか(nullではないか)。 |
---|
public function __isset($name)
{
$getter = 'get' . $name;
if (method_exists($this, $getter)) {
return $this->$getter() !== null;
}
return false;
}
定義場所: yii\base\BaseObject::__set()
オブジェクトプロパティの値を設定します。
これはPHPのマジックメソッドであり、$object->property = $value;
を実行した際に暗黙的に呼び出されるため、直接呼び出さないでください。
__get()も参照してください。
public void __set ( $name, $value ) | ||
$name | string |
プロパティ名またはイベント名 |
$value | mixed |
プロパティの値 |
例外 | yii\base\UnknownPropertyException |
プロパティが定義されていない場合 |
---|---|---|
例外 | yii\base\InvalidCallException |
プロパティが読み取り専用の場合 |
public function __set($name, $value)
{
$setter = 'set' . $name;
if (method_exists($this, $setter)) {
$this->$setter($value);
} elseif (method_exists($this, 'get' . $name)) {
throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
} else {
throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
}
}
定義場所: yii\base\BaseObject::__unset()
オブジェクトプロパティを null に設定します。
これはPHPのマジックメソッドであり、unset($object->property)
を実行した際に暗黙的に呼び出されるため、直接呼び出さないでください。
プロパティが定義されていない場合は、このメソッドは何もしません。プロパティが読み取り専用の場合は、例外をスローします。
public void __unset ( $name ) | ||
$name | string |
プロパティ名 |
例外 | yii\base\InvalidCallException |
プロパティが読み取り専用の場合。 |
---|
public function __unset($name)
{
$setter = 'set' . $name;
if (method_exists($this, $setter)) {
$this->$setter(null);
} elseif (method_exists($this, 'get' . $name)) {
throw new InvalidCallException('Unsetting read-only property: ' . get_class($this) . '::' . $name);
}
}
ビヘイビアオブジェクトをコンポーネントにアタッチします。
デフォルトの実装では、$ownerプロパティを設定し、events()で宣言されているイベントハンドラをアタッチします。このメソッドをオーバーライドする場合は、親の実装を必ず呼び出してください。
public void attach ( $owner ) | ||
$owner | yii\base\Component |
このビヘイビアをアタッチするコンポーネント。 |
public function attach($owner)
{
parent::attach($owner);
if (empty($this->attributes)) {
$lock = $this->getLockAttribute();
$this->attributes = array_fill_keys(array_keys($this->events()), $lock);
}
}
定義位置: yii\base\BaseObject::canGetProperty()
プロパティを読み取ることができるかどうかを示す値を返します。
プロパティは、以下の場合に読み取り可能です。
- 指定された名前と関連付けられたゲッターメソッドがクラスに存在する場合(この場合、プロパティ名はケースインセンシティブです)。
- 指定された名前のメンバ変数がクラスに存在する場合(
$checkVars
がtrueの場合)。
参照: canSetProperty().
public boolean canGetProperty ( $name, $checkVars = true ) | ||
$name | string |
プロパティ名 |
$checkVars | boolean |
メンバ変数をプロパティとして扱うかどうか |
戻り値 | boolean |
プロパティを読み取ることができるかどうか |
---|
public function canGetProperty($name, $checkVars = true)
{
return method_exists($this, 'get' . $name) || $checkVars && property_exists($this, $name);
}
定義位置: yii\base\BaseObject::canSetProperty()
プロパティを設定できるかどうかを示す値を返します。
プロパティは、以下の場合に書き込み可能です。
- 指定された名前と関連付けられたセッターメソッドがクラスに存在する場合(この場合、プロパティ名はケースインセンシティブです)。
- 指定された名前のメンバ変数がクラスに存在する場合(
$checkVars
がtrueの場合)。
参照: canGetProperty().
public boolean canSetProperty ( $name, $checkVars = true ) | ||
$name | string |
プロパティ名 |
$checkVars | boolean |
メンバ変数をプロパティとして扱うかどうか |
戻り値 | boolean |
プロパティを書き込むことができるかどうか |
---|
public function canSetProperty($name, $checkVars = true)
{
return method_exists($this, 'set' . $name) || $checkVars && property_exists($this, $name);
}
::class
を使用してください。
定義位置: yii\base\BaseObject::className()
このクラスの完全修飾名を返します。
public static string className ( ) | ||
戻り値 | string |
このクラスの完全修飾名。 |
---|
public static function className()
{
return get_called_class();
}
定義位置: yii\base\Behavior::detach()
ビヘイビアオブジェクトをコンポーネントからデタッチします。
デフォルトの実装では、$owner プロパティをアンセットし、events() で宣言されたイベントハンドラをデタッチします。このメソッドをオーバーライドする場合は、親の実装を必ず呼び出してください。
public void detach ( ) |
public function detach()
{
if ($this->owner) {
foreach ($this->_attachedEvents as $event => $handler) {
$this->owner->off($event, is_string($handler) ? [$this, $handler] : $handler);
}
$this->_attachedEvents = [];
$this->owner = null;
}
}
定義位置: yii\behaviors\AttributeBehavior::evaluateAttributes()
属性値を評価し、現在の属性に割り当てます。
public void evaluateAttributes ( $event ) | ||
$event | yii\base\Event |
public function evaluateAttributes($event)
{
if (
$this->skipUpdateOnClean
&& $event->name == ActiveRecord::EVENT_BEFORE_UPDATE
&& empty($this->owner->dirtyAttributes)
) {
return;
}
if (!empty($this->attributes[$event->name])) {
$attributes = (array) $this->attributes[$event->name];
$value = $this->getValue($event);
foreach ($attributes as $attribute) {
// ignore attribute names which are not string (e.g. when set by TimestampBehavior::updatedAtAttribute)
if (is_string($attribute)) {
if ($this->preserveNonEmptyValues && !empty($this->owner->$attribute)) {
continue;
}
$this->owner->$attribute = $value;
}
}
}
}
$owner のイベントのイベントハンドラーを宣言します。
子クラスは、このメソッドをオーバーライドして、$owner コンポーネントのイベントにどのPHPコールバックをアタッチするかを宣言できます。
コールバックは、ビヘイビアがオーナーにアタッチされると$ownerのイベントにアタッチされ、ビヘイビアがコンポーネントからデタッチされるとイベントからデタッチされます。
コールバックには、以下のいずれかを使用できます。
- このビヘイビアのメソッド:
'handleClick'
([$this, 'handleClick']
と同等) - オブジェクトメソッド:
[$object, 'handleClick']
- 静的メソッド:
['Page', 'handleClick']
- 無名関数:
function ($event) { ... }
例を以下に示します。
[
Model::EVENT_BEFORE_VALIDATE => 'myBeforeValidate',
Model::EVENT_AFTER_VALIDATE => 'myAfterValidate',
]
public array events ( ) | ||
戻り値 | array |
イベント(配列のキー)と対応するイベントハンドラメソッド(配列の値)。 |
---|
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',
] : [];
}
optimisticLock() で定義されているように、バージョン値を保持するカラム名を返します。
protected string getLockAttribute ( ) | ||
戻り値 | string |
プロパティ名。 |
---|---|---|
例外 | yii\base\InvalidCallException |
optimisticLock() が正しく設定されていない場合。 |
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;
}
現在の属性の値を返します。
null
の場合、値は getBodyParam() から解析されるか、0に設定されます。
このメソッドは、evaluateAttributes() によって呼び出されます。その戻り値は、トリガーイベントに対応する属性に代入されます。
protected mixed getValue ( $event ) | ||
$event | yii\base\Event |
現在の属性の更新をトリガーするイベント。 |
戻り値 | mixed |
属性値 |
---|
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);
}
定義位置: yii\base\BaseObject::hasMethod()
メソッドが定義されているかどうかを示す値を返します。
デフォルトの実装は、PHP関数method_exists()
を呼び出します。PHPマジックメソッド__call()
を実装した場合は、このメソッドをオーバーライドできます。
public boolean hasMethod ( $name ) | ||
$name | string |
メソッド名 |
戻り値 | boolean |
メソッドが定義されているかどうか |
---|
public function hasMethod($name)
{
return method_exists($this, $name);
}
定義先: yii\base\BaseObject::hasProperty()
プロパティが定義されているかどうかを示す値を返します。
プロパティは、以下の場合に定義されています。
- 指定された名前と関連付けられたゲッターまたはセッターメソッドがクラスに存在する場合(この場合、プロパティ名は大小文字を区別しません)。
- 指定された名前のメンバ変数がクラスに存在する場合(
$checkVars
がtrueの場合)。
参照
public boolean hasProperty ( $name, $checkVars = true ) | ||
$name | string |
プロパティ名 |
$checkVars | boolean |
メンバ変数をプロパティとして扱うかどうか |
戻り値 | boolean |
プロパティが定義されているかどうか |
---|
public function hasProperty($name, $checkVars = true)
{
return $this->canGetProperty($name, $checkVars) || $this->canSetProperty($name, false);
}
public void init ( ) |
public function init()
{
}
バージョン値を 1 つ増やし、データベースに保存します。
$model->upgrade();
public void upgrade ( ) | ||
例外 | yii\base\InvalidCallException |
オーナーが新規レコードの場合。 |
---|
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]);
}
コメントするにはサインアップまたはログインしてください。