5丁目通信(仮称)

とある5丁目で活動する還暦を過ぎたWebプログラマーの覚え書きです。それとかかってくる迷惑電話や、家業のアパート経営について。

昨日のCakePHPでhasManyでの検索の続きの話し


昨日のCakePHPでhasManyでの検索の続きです。うまくいったと思いましたが、検索結果に重複項目があります。hasManyのモデルにまともにSQLを実行したら重複するのは当たり前ですね。

そこで、pagenate()でページングの処理をしているので、コントローラーのメンバー$pagenateのfieldsに、キーとなる項目にDISTINCTを付けてみる。これで、重複されなくなった。

しかし、新たな問題。検索個数が合わない。こちらもcount(*)になっているところをcount(DISTINCT キー項目)にすればいいのだけど、$pagenateのfieldsからは影響されないようでした。

いろいろ調べてみると、やはりありました。ここです。モデルにpaginateCount()を定義してあげればいいのでした。pagenate()のソースを見ると、モデルにpaginateCount()があるかどうかをチェックして、あればpaginateCount()を実行してくれます。無ければfindCount()を実行します。ここはSQLをゴリゴリ書いて、該当する条件でレコード数を返してあげるようにしました。配列に格納されている条件は次のようにWHERE句に変換できます。

$Db = ConnectionManager::getDataSource($this->useDbConfig);
$where = $Db->conditions($conditions);

これで、重複せずに検索結果を表示できました。

いまいち具体的な説明ではないので、もしご興味ある方はコメントに入れてください。

著:山田祥寛
¥3,366 (2024/11/21 16:43時点 | Amazon調べ)
著:松浦 健一郎, 著:司 ゆき
¥2,574 (2024/11/21 16:43時点 | Amazon調べ)
著:谷藤賢一, 著:徳丸浩
¥2,750 (2024/11/21 16:43時点 | Amazon調べ)
,

“昨日のCakePHPでhasManyでの検索の続きの話し” への6件のフィードバック

  1. necoのアバター
    neco

    ぜひ、さらに詳しいお話お聞きしたいです。
    hasManyの値を検索する方法を調べて、このページにたどり着きました。paginateのオプション設定に’joins’の要素をつけたすことによって、hasManyの検索が出来るようになり、’fields’の一意にしたい項目に’DISTINCT **.id’をつけたすことによって、表示もタブらなくなりました。ここまでは、この記事によって順調に解決することが出来ました、有難う御座います。

    ですが、この記事にもかかれている、表示のカウント数については今だ解決しておらず、よければどのようにpaginateCountを設定するのか聞けたらと思って下ります。

    宜しくお願い致します。

  2. necoのアバター
    neco

    たびたび失礼します。英文のサイトにある以下を使用するモデルに貼り付けたら出来ました!

    function paginateCount($conditions, $recursive) {
    if (isset($this->forcePaginateCount)) {
    $count = $this->forcePaginateCount;
    unset($this->forcePaginateCount);
    } else {
    $count = $this->find(‘count’, compact(‘conditions’, ‘recursive’));
    }
    return $count;
    }

  3. necoのアバター
    neco

    うーん・・

    やはり、だめでした。
    検索が出来なくなってしまったので、あてずっぽうはダメですね。

  4. mune andoのアバター
    mune ando

    necoさん

    コメントありがとうございました。

    paginateCount()は、ページングで表示する件数を返す必要があります。したがって、条件が1番目の$conditionsにパラメータで入ってきますので、このように書いています。

    function paginateCount($conditions, $recursive) {
    $Db = ConnectionManager::getDataSource($this->useDbConfig);

    $query = “SELECT “; //= ページングで表示する件数を取得するSQLを自力で書く。
    $query .= ‘COUNT(DISTINCT “Model”.”id”) AS “count” ‘;
    $query .= ‘FROM “models” AS “Model” ‘;
    $query .= ‘INNER JOIN ・・・・・’ //= 条件で必要なテーブルを関係づける。
    $query .= ‘LEFT JOIN ・・・・・’ //=

    $query .= $Db->conditions($conditions); //= 抽出するためのwhere句が生成されるはずです。
    $ret_list = $this->query($query);

    $count = $ret_list[0][0][‘count’];

    return($count);

    }

    一度、$conditionsに何が入っているか、また$queryがどのように生成されたをダンプされているかを確認したほうがよろしいかと思います。

  5. necoのアバター
    neco

    お返事有難う御座います。
    参考どうり表示件数が正しく表示されました!
    いくら検索で調べても答えにたどり着かなかったのですが
    この記事はとても分かりやすく、きっと多くの人を助けると思います。

    今後も勉強させて頂きます!

  6. mune andoのアバター
    mune ando

    お役に立てて、よかったです。

    本件は、私もとても悩んだ箇所で、結局はCakePHPのソースを読んでしまいました。この辺りは、サイトや解説書にもあまり書かれていないようで、自分の覚え書きとしてして記事を書きました。

    今後ともよろしくお願いします。