フォロワー 5

ビヘイビア

ビヘイビアは、yii\base\Behavior、またはその子クラスのインスタンスです。ビヘイビアは、ミックスインとも呼ばれ、既存のコンポーネントクラスの機能を、クラスの継承を変更することなく拡張することができます。コンポーネントにビヘイビアをアタッチすると、ビヘイビアのメソッドとプロパティがコンポーネントに「注入」され、コンポーネントクラス自体で定義されているかのように、それらのメソッドとプロパティにアクセスできるようになります。さらに、ビヘイビアは、コンポーネントによってトリガーされるイベントに応答することができ、これにより、ビヘイビアはコンポーネントの通常のコード実行をカスタマイズすることもできます。

ビヘイビアの定義

ビヘイビアを定義するには、yii\base\Behaviorを拡張するクラス、またはその子クラスを拡張するクラスを作成します。例えば

namespace app\components;

use yii\base\Behavior;

class MyBehavior extends Behavior
{
    public $prop1;

    private $_prop2;

    public function getProp2()
    {
        return $this->_prop2;
    }

    public function setProp2($value)
    {
        $this->_prop2 = $value;
    }

    public function foo()
    {
        // ...
    }
}

上記のコードは、2つのプロパティ`prop1`と`prop2`、そして1つのメソッド`foo()`を持つビヘイビアクラス`app\components\MyBehavior`を定義しています。プロパティ`prop2`は、ゲッター`getProp2()`とセッター`setProp2()`によって定義されていることに注意してください。これは、yii\base\Behavioryii\base\BaseObjectを拡張し、したがってゲッターとセッターによるプロパティの定義をサポートしているためです。

このクラスはビヘイビアであるため、コンポーネントにアタッチされると、そのコンポーネントにも`prop1`と`prop2`のプロパティと`foo()`メソッドが追加されます。

ヒント: ビヘイビア内では、yii\base\Behavior::$ownerプロパティを通じて、ビヘイビアがアタッチされているコンポーネントにアクセスできます。

注意: ビヘイビアのyii\base\Behavior::__get()メソッドまたはyii\base\Behavior::__set()メソッド(あるいはその両方)をオーバーライドする場合は、yii\base\Behavior::canGetProperty()メソッドまたはyii\base\Behavior::canSetProperty()メソッド(あるいはその両方)もオーバーライドする必要があります。

コンポーネントイベントの処理

ビヘイビアが、アタッチされているコンポーネントによってトリガーされるイベントに応答する必要がある場合は、yii\base\Behavior::events()メソッドをオーバーライドする必要があります。例えば

namespace app\components;

use yii\db\ActiveRecord;
use yii\base\Behavior;

class MyBehavior extends Behavior
{
    // ...

    public function events()
    {
        return [
            ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate',
        ];
    }

    public function beforeValidate($event)
    {
        // ...
    }
}

events() メソッドは、イベントとその対応するハンドラのリストを返すべきです。上記の例では、EVENT_BEFORE_VALIDATE イベントが存在し、そのハンドラとして beforeValidate() が定義されていることを宣言しています。イベントハンドラを指定する場合、以下のいずれかの形式を使用できます。

  • 上記の例のように、ビヘイビアクラスのメソッド名を参照する文字列
  • オブジェクトまたはクラス名と、メソッド名を文字列(括弧なし)で表す配列。例: [$object, 'methodName']
  • 無名関数

イベントハンドラのシグネチャは、以下のようになります。ここで、$event はイベントパラメータを参照します。イベントの詳細については、イベント のセクションを参照してください。

function ($event) {
}

ビヘイビアの追加

ビヘイビアは、コンポーネント に静的に、または動的に追加できます。実際には、静的な追加の方が一般的です。

ビヘイビアを静的に追加するには、ビヘイビアを追加するコンポーネントクラスの behaviors() メソッドをオーバーライドします。behaviors() メソッドは、ビヘイビアの 設定 のリストを返す必要があります。各ビヘイビアの設定は、ビヘイビアクラス名または設定配列のいずれかです。

namespace app\models;

use yii\db\ActiveRecord;
use app\components\MyBehavior;

class User extends ActiveRecord
{
    public function behaviors()
    {
        return [
            // anonymous behavior, behavior class name only
            MyBehavior::class,

            // named behavior, behavior class name only
            'myBehavior2' => MyBehavior::class,

            // anonymous behavior, configuration array
            [
                'class' => MyBehavior::class,
                'prop1' => 'value1',
                'prop2' => 'value2',
            ],

            // named behavior, configuration array
            'myBehavior4' => [
                'class' => MyBehavior::class,
                'prop1' => 'value1',
                'prop2' => 'value2',
            ]
        ];
    }
}

ビヘイビア設定に対応する配列キーを指定することで、ビヘイビアに名前を関連付けることができます。この場合、ビヘイビアは *名前付きビヘイビア* と呼ばれます。上記の例では、myBehavior2myBehavior4 の2つの名前付きビヘイビアがあります。ビヘイビアに名前が関連付けられていない場合、それは *匿名ビヘイビア* と呼ばれます。

ビヘイビアを動的に追加するには、ビヘイビアを追加するコンポーネントの yii\base\Component::attachBehavior() メソッドを呼び出します。

use app\components\MyBehavior;

// attach a behavior object
$component->attachBehavior('myBehavior1', new MyBehavior());

// attach a behavior class
$component->attachBehavior('myBehavior2', MyBehavior::class);

// attach a configuration array
$component->attachBehavior('myBehavior3', [
    'class' => MyBehavior::class,
    'prop1' => 'value1',
    'prop2' => 'value2',
]);

yii\base\Component::attachBehaviors() メソッドを使用して、複数のビヘイビアを一度に追加することもできます。

$component->attachBehaviors([
    'myBehavior1' => new MyBehavior(), // a named behavior
    MyBehavior::class,                 // an anonymous behavior
]);

以下のように、設定 を 통해 ビヘイビアを追加することもできます。

[
    'as myBehavior2' => MyBehavior::class,

    'as myBehavior3' => [
        'class' => MyBehavior::class,
        'prop1' => 'value1',
        'prop2' => 'value2',
    ],
]

詳細については、設定 のセクションを参照してください。

ビヘイビアの使用

ビヘイビアを使用するには、まず上記の手順に従って コンポーネント に追加します。ビヘイビアがコンポーネントに追加されると、その使用は簡単です。

ビヘイビアの *パブリック* メンバー変数、またはゲッターやセッターで定義された プロパティ には、それが追加されているコンポーネントを 통해 アクセスできます。

// "prop1" is a property defined in the behavior class
echo $component->prop1;
$component->prop1 = $value;

同様に、ビヘイビアの *パブリック* メソッドを呼び出すこともできます。

// foo() is a public method defined in the behavior class
$component->foo();

ご覧のとおり、$componentprop1foo() を定義していませんが、追加されたビヘイビアにより、コンポーネント定義の一部であるかのように使用できます。

2つのビヘイビアが同じプロパティまたはメソッドを定義し、両方が同じコンポーネントに追加されている場合、プロパティまたはメソッドにアクセスしたときに、コンポーネントに *先に* 追加されたビヘイビアが優先されます。

ビヘイビアは、コンポーネントに追加されるときに名前と関連付けることができます。この場合、名前を使用してビヘイビアオブジェクトにアクセスできます。

$behavior = $component->getBehavior('myBehavior');

コンポーネントに追加されているすべてのビヘイビアを取得することもできます。

$behaviors = $component->getBehaviors();

ビヘイビアの削除

ビヘイビアを削除するには、ビヘイビアに関連付けられた名前を指定して yii\base\Component::detachBehavior() を呼び出します。

$component->detachBehavior('myBehavior1');

*すべて* のビヘイビアを削除することもできます。

$component->detachBehaviors();

TimestampBehavior の使用

最後に、yii\behaviors\TimestampBehavior を見てみましょう。このビヘイビアは、insert()update()、または save() メソッドを 통해 モデルが保存されるたびに、アクティブレコード モデルのタイムスタンプ属性を自動的に更新することをサポートします。

まず、このビヘイビアを使用する予定の アクティブレコード クラスに追加します。

namespace app\models\User;

use yii\db\ActiveRecord;
use yii\behaviors\TimestampBehavior;

class User extends ActiveRecord
{
    // ...

    public function behaviors()
    {
        return [
            [
                'class' => TimestampBehavior::class,
                'attributes' => [
                    ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
                    ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
                ],
                // if you're using datetime instead of UNIX timestamp:
                // 'value' => new Expression('NOW()'),
            ],
        ];
    }
}

上記のビヘイビア設定では、レコードが

  • 挿入される場合、ビヘイビアは現在のUNIXタイムスタンプを created_at 属性と updated_at 属性に割り当てる必要があります。
  • 更新される場合、ビヘイビアは現在のUNIXタイムスタンプを updated_at 属性に割り当てる必要があります。

**注意:** 上記の実装をMySQLデータベースで動作させるには、UNIXタイムスタンプとするために、カラム(created_atupdated_at)をint(11)として宣言してください。

このコードを使用すると、User オブジェクトを保存しようとすると、その created_atupdated_at が現在のUNIXタイムスタンプで自動的に埋められます。

$user = new User;
$user->email = 'test@example.com';
$user->save();
echo $user->created_at;  // shows the current timestamp

TimestampBehavior は、指定された属性に現在のタイムスタンプを割り当て、データベースに保存する便利なメソッド touch() も提供しています。

$user->touch('login_time');

その他のビヘイビア

いくつかの組み込みおよび外部ビヘイビアが利用可能です。

  • yii\behaviors\BlameableBehavior - 指定された属性を現在のユーザーIDで自動的に埋めます。
  • yii\behaviors\SluggableBehavior - 指定された属性をURLでスラッグとして使用できる値で自動的に埋めます。
  • yii\behaviors\AttributeBehavior - 特定のイベントが発生したときに、ActiveRecordオブジェクトの1つまたは複数の属性に指定された値を自動的に割り当てます。
  • yii2tech\ar\softdelete\SoftDeleteBehavior - ActiveRecordを論理削除および論理復元するためのメソッドを提供します。つまり、レコードを削除済みとしてマークするフラグまたはステータスを設定します。
  • yii2tech\ar\position\PositionBehavior - 並べ替えメソッドを提供することにより、整数フィールドでのレコードの順序管理を可能にします。

ビヘイビアとトレイトの比較

ビヘイビアは、プロパティとメソッドをプライマリクラスに「注入」するという点で トレイト と似ていますが、多くの点で異なります。以下で説明するように、どちらも長所と短所があります。代替手段というよりは、互いに補完するものと言えます。

ビヘイビアを使用する理由

通常のクラスと同様に、ビヘイビアクラスは継承をサポートします。一方、トレイトは、言語でサポートされるコピーアンドペーストと考えることができます。トレイトは継承をサポートしていません。

ビヘイビアは、コンポーネントクラスを変更することなく、コンポーネントに動的に追加および削除できます。トレイトを使用するには、それを使用するクラスのコードを変更する必要があります。

ビヘイビアは設定可能ですが、トレイトは設定できません。

ビヘイビアは、コンポーネントのイベントに応答することで、コンポーネントのコード実行をカスタマイズできます。

同じコンポーネントに追加された異なるビヘイビア間で名前の競合が発生する可能性がある場合、コンポーネントに最初に追加されたビヘイビアを優先することで、競合は自動的に解決されます。異なるトレイトによって発生した名前の競合は、影響を受けるプロパティまたはメソッドの名前を変更することにより、手動で解決する必要があります。

トレイトを使用する理由

ビヘイビアはオブジェクトであり、時間とメモリの両方を使用するため、トレイトはビヘイビアよりもはるかに効率的です。

トレイトはネイティブ言語構造であるため、IDEはトレイトに対してよりフレンドリーです。

タイプミスを見つけたり、このページの改善が必要だと思いますか?
GitHubで編集してください !