2024年2月8日木曜日

CakePHP でアソシエーションを含めたレコードの読込み

containを使え

あちこちのサイトを見ると、contain を使った方法がたくさん書いてありますね。
たとえば、products テーブルに取引先のIDである partner_id が含まれているとき
$product_id で示されるレコードを取得するには、次のように書きます。

  // コントローラの initialize() で
  $this->loadModel('Products');
  // レコードの取り込み処理で
  $record = $this->Products->get($product_id, ['contain' => ['Partners']]);

cakePHP を書きなれている人なら、同じみでしょう。
QueryBuilder を使った find() などでもアソシエーションとともに読み込みできますね。

  $record = $this->Products->find()
    contain(['Partners'])
    ->first();

どんだけ書くねん!

『こう書いておけば動く』から、なんでしょうか・・・
たぶん、世界中の人が、さまざまなプロダクトのテーブル参照を『とっても便利な』QueryBuilder を使って読み込んでいるのでしょうね。

おおきなプロダクトになってくると、それぞれのテーブルごとにレコード参照のコントローラ.phpファイルが増えて、手に負えなくなってしまいますねぇ

簡単にしちゃいましょう

レコードが _id で示されるインデックス指定のフィールドを持っているとき、contain でアソシエーションを『含めずに』読み込む、なんてことは逆に少ないはずです。
少なくとも、私の担当するプロダクトではレコード読込でアソシエーション不要、なんてことは皆無に近いですね。
そこで、こんなコードを共通コンポーネントに書き加えました。

/**
 * 指定テーブルのアソシエーション(BelongsTo/BelongsToMany)を含めて
 * レコードを取得する
 */
function LoadRecordWithBelongs($table, $id)
{
  $record = false;
  $contains = [];
  $associations = $table->associations();
  $items = $associations->getByType(['BelongsTo', 'BelongsToMany']);
  foreach($items as $item)
  {
    $name = $item->getName();
    $contains[] = $name;
  }
  $record = $table->get($id, ['contain' => $contains]);
  return $record;
}
ようするに、belongsTo, belongsToMany のアソシエーション定義されているテーブルなら、そいつをまとめて読み込んでくれよ、というコードです。

まとめ

共通化することで、たくさんのソースを削除することができるようになりますが。
それは、これからやり始めようとしてるところです・・・w

めでたしめでたし。

0 件のコメント:

コメントを投稿