20

これは些細な質問のように思えるかもしれませんが、私が考えることができる明白な解決策にはすべて、独自の欠陥があります。

私たちが望むのは、新しいレコードのみにデフォルトの ActiveRecord 属性値を設定できるようにすることです。これは、検証前および検証中に読み取り可能になり、検索に使用される派生クラスに干渉しないようにするためです。

クラスをインスタンス化したらすぐにデフォルト値を設定して準備する必要があるため(new MyModel)->attr、デフォルト値が返されますattr

いくつかの可能性と問題点を次に示します。

  • A)MyModelメソッドをオーバーライドし、trueのinit()場合にデフォルト値を割り当てます:isNewRecord

    public function init() {
        if ($this->isNewRecord) {
            $this->attr = 'defaultValue';
        }
        parent::init();
    }
    

    問題: 検索。デフォルトの属性を明示的に設定解除しない限りMySearchModel(忘れやすいため、非常にエラーが発生しやすくなります)、search()派生MySearchModelクラスで呼び出す前に値が設定され、検索が妨げられます (attr属性は既に設定されているため、検索が返されます)。間違った結果)。Yii1.1 では、これは を呼び出すunsetAttributes()前に を呼び出すことで解決されてsearch()いましたが、Yii2 にはそのようなメソッドはありません。

  • B)メソッドを次のようにオーバーライドMyModelします。beforeSave()

    public function beforeSave($insert) {
        if ($insert) {
            $this->attr = 'defaultValue';
        }
        return parent::beforeSave();
    }
    

    問題: 保存されていないレコードに属性が設定されていません。(new MyModel)->attrですnullさらに悪いことに、この値に依存する他の検証ルールでさえ、検証後にbeforeSave()呼び出されるため、この値にアクセスできません。

  • C)検証中に値が使用可能であることを確認するには、代わりにbeforeValidate()メソッドをオーバーライドして、次のようにデフォルト値を設定します。

    public function beforeValidate() {
        if ($this->isNewRecord) {
            $this->attr = 'defaultValue';
        }
        return parent::beforeValidate();
    }
    

    問題: 保存されていない (検証されていない) レコードに属性がまだ設定されていません。$model->validate()デフォルト値を取得したい場合は、少なくとも呼び出す必要があります。

  • D)DefaultValidator inを使用しrules()て、検証中にデフォルトの属性値を次のように設定します。

    public function rules() {
        return [
            [
                'attr', 'default',
                'value' => 'defaultValue',
                'on' => 'insert', // instantiate model with this scenario
            ],
            // ...
        ];
    }
    

    問題: B) および C) と同じ。実際にレコードを保存または検証するまで、値は設定されません。

では、デフォルトの属性値を設定する正しい方法何でしょうか? 概説された問題のない他の方法はありますか?

4

7 に答える 7