5

yii のモデルにデフォルト スコープを適用する方法に関するドキュメントがあまり見つかりません。誰かが説明してくれたり、正しい方向に向けてくれるのではないかと思っていました。

私の質問の簡単なバージョン:

リレーションをデフォルト スコープに追加したり、モデルのすべての AR 検索にデフォルトで「with」基準を追加したりすることは可能ですか?

私の質問の長いバージョン:

私のアプリの簡単な要約:

私は2つのモデルを持っていproviderますitem. プロバイダーは多くのアイテムを持つことができますが、各アイテムは 1 つのプロバイダーしか持つことができない am:1 関係があります。

これまでのところ、次の関係があります。

class Provider extends CActiveRecord
{
    ...
    public function relations()
    {
        return array(
            'items' => array(self::HAS_MANY, 'Item', 'id_provider', 'order'=>'rank DESC'),
        );
    }
    ...
}

class Item extends CActiveRecord
{
    ...
    public function relations()
    {
        return array(
            'provider' => array(self::BELONGS_TO, 'Provider', 'id_provider'),
        );
    }
    ...
}

私のアイテム モデル内では、すべてのオフライン アイテムを除外する defaultScope を既に取得しています (つまり、 に設定されているアイテムのみを表示しますoffline = false)。

public function defaultScope()
{
    $alias = $this->getTableAlias(false,false);
    return array(
        'condition'=>"`$alias`.`offline` = false",
    );
}

私が今やりたいことは、プロバイダーがオフラインに設定されているアイテムを除外することです (つまりprovider.offline = false、現在の と並んでいるアイテムのみを表示しますitem.offline = false)。

私は defaultScope で providers テーブルに参加しようとしました:

public function defaultScope()
{
    $alias = $this->getTableAlias(false,false);
    return array(
        'join'=>"JOIN `provider` AS `provider` ON `provider`.`id` = `$alias`.`id_provider`",
        'condition'=>"`$alias`.`offline` = false AND `provider`.`offline` = false",
    );
}

ただし、JOIN は ON ステートメントの後に適用され、エラーが発生します ( CDbCommand failed to execute the SQL statement: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'provider.offline' in 'on clause')。

また、defaultScope に with 基準を追加しようとしました。

public function defaultScope()
{
    $alias = $this->getTableAlias(false,false);
    return array(
        'with'=>"provider",
        'condition'=>"`$alias`.`offline` = false AND `provider`.`offline` = false",
    );
}

しかし、同じエラーが発生します: SQLSTATE[42S22]: 列が見つかりません: 1054 不明な列 'provider.offline' in 'on clause'`).

助言がありますか?

4

2 に答える 2

7

私が試みることがいくつかあります:

まず、条件を変更してすべてに適用します(プロバイダーのアイテムがない場合、プロバイダーは返されません)。

public function defaultScope()
{
    return array(
        'with'=> array("provider" => array(
            'condition'=> "t.offline = false AND provider.offline = false",
        )
    );
}

次に、モデルにスコープを追加してから、次のようにデフォルトのスコープでスコープを参照してみてください。

public function defaultScope()
{
    return array(
        'scopes'=> array('default'),
    );
}

class Provider extends CActiveRecord
{
    ...
    public function scopes()
    {
        ...
    }
    ...
}

class Item extends CActiveRecord
{
    ...
    public function scopes()
    {
        ...
    }
    ...
}
于 2012-08-15T17:08:27.140 に答える
1

ちょうど同様の問題がありました。Benjamin の最初の提案は正しい方向を示してくれましたが (非常に感謝しています!)、'condition' と 'with' を使用して予期しない問題に遭遇しました。

結合先のテーブル (例では「provider」) に独自の defaultScope がある場合、「with」を使用すると SQL ON 句の一部としてこれが適用され、返される行が制限されるようです。

外部結合が使用されているため、プライマリ テーブル ('item') のすべての行に対してレコードが返されますが、プロバイダーの defaultScope によってそれらの行が返されない場合、一部の行で 'provider' フィールドが null になることがあります。

これらのプロバイダ フィールドの 1 つを含む「条件」を適用しようとするまで、これは問題を引き起こしません。これは、結合後に処理される WHERE 句の一部として行われますが、そのフィールドが null であるため、条件は失敗し、レコードは返されません。

場合によっては、これが望ましい動作になることもありますが、onオプションを使用して「provider」フィールドのテストを結合内に移動したい場合もあります。

public function defaultScope()
{
return array(
    'with'=> array("provider" => array(
        'condition'=> "t.offline = false",
        'on'=>"provider.offline = false",
    )
);
}
于 2013-11-19T08:24:37.067 に答える