2

たとえば、私はこの関係を持っています:

UserContact hasMany Contact
Contact hasOne Info
Contact hasMany Response

また、Contact をページ付けする必要があるため、Containable を使用します。

$this->paginate = array(
            'limit'=>50,
            'page'=>$page,
            'conditions' =>array('Contact.id'=>$id),
            'contain'=>array(
                'Response',
                'Info'
                )
            );

Info.name と Response.description による検索を追加したいと考えています。Info.nameには最適ですが、 Response.descriptionを使用しようとすると、列が存在しないというエラーがスローされます。

さらに、リレーションシップを Contact hasOne Response に変更しようとしたところ、正しくフィルター処理されましたが、最初の応答のみが返され、これは正しいリレーションシップではありません。

たとえば、検索キー$filterがある場合、一致するInfo.nameまたは少なくとも 1 つの一致するResponse.descriptionを持つ連絡先のみを返したいとします。

4

2 に答える 2

3

hasOneCakePHP がどのように SQL クエリを構築するかを見ると、含まれる「単一の」リレーションシップ ( and belongsTo) をメイン クエリの結合句として生成し、含まれる「複数の」リレーションシップに対して別のクエリを追加することがわかります。

これにより、関連するモデルのテーブルがメイン クエリで既に結合されているため、単一のリレーションシップによるフィルタリングが簡単になります。

複数の関係でフィルタリングするには、サブクエリを作成する必要があります。

// in contacts_controller.php:
$conditionsSubQuery = array(
  'Response.contact_id = Contact.id',
  'Response.description LIKE' => '%'.$filter.'%'
);
$dbo = $this->Contact->getDataSource();
$subQuery = $dbo->buildStatement(array(
    'fields' => array('Response.id'),
    'table' => $dbo->fullTableName($this->Contact->Response),
    'alias' => 'Response',
    'conditions' => $conditionsSubQuery
), $this->Contact->Response);
$subQuery = ' EXISTS (' . $subQuery . ') ';

$records = $this->paginate(array(
    'Contact.id' => $id,
    $dbo->expression($subQuery)
));

Responseただし、フィールドでフィルタリングする必要がある場合にのみ、サブクエリを生成する必要があります。そうしないと、応答のない連絡先が除外されます。

PS。このコードは大きすぎて見苦しく、コントローラーに表示できません。私のプロジェクトではapp_model.php、各モデルが独自のサブクエリを生成できるように、それを にリファクタリングしました。

function makeSubQuery($wrap, $options) {
    if (!is_array($options))
        return trigger_error('$options is expected to be an array, instead it is:'.print_r($options, true), E_USER_WARNING);
    if (!is_string($wrap) || strstr($wrap, '%s') === FALSE)
        return trigger_error('$wrap is expected to be a string with a placeholder (%s) for the subquery. instead it is:'.print_r($wrap, true), E_USER_WARNING);

    $ds = $this->getDataSource();

    $subQuery_opts = array_merge(array(
        'fields' => array($this->alias.'.'.$this->primaryKey),        
        'table' => $ds->fullTableName($this),        
        'alias' => $this->alias,   
        'conditions' => array(),     
        'order' => null, 
        'limit' => null,
        'index' => null, 
        'group' => null
    ), $options);

    $subQuery_stm = $ds->buildStatement($subQuery_opts, $this);
    $subQuery = sprintf($wrap, $subQuery_stm);
    $subQuery_expr = $ds->expression($subQuery);
    return $subQuery_expr;
}

次に、コントローラーのコードは次のようになります。

$conditionsSubQuery = array(
    'Response.contact_id = Contact.id',
    'Response.description LIKE' => '%'.$filter.'%'
);
$records = $this->paginate(array(
    'Contact.id' => $id,
    $this->Contact->Response->makeSubQuery('EXISTS (%s)', array('conditions' => $conditionsSubQuery))
));
于 2012-01-08T21:29:11.637 に答える
0

今は試すことができませんが、Contactモデルの代わりにResponseモデルをページ付けすれば機能するはずです。

于 2012-01-06T22:51:20.750 に答える