エス技研

WordPress、CakePHP、PHP、baserCMSなどの Web系システムを中心に情報を提供します!


CakePHP4の規約外のカラムをキーにアソシエーション(テーブル連結)する方法

      2024/06/21

CakePHPの規約外のカラムをキーにアソシエーション(テーブル連結)する方法

 
CakePHP4で CakePHPの規定から外れることでデフォルトではアソシエーション(テーブルの関連付け)されないカラム(項目)をキーとしてアソシエーションする方法を解説します。
 
 

前提:存在するテーブルのイメージ

 
解説する環境には下記の 3つのテーブルがあるとします。
 

 
 

Bakeで自動生成されるアソシエーション

 
これらのテーブルに対して、CakePHPの Bakeを使用して「company_details」の Modelを生成してみます。
「company_details.company_id」は、CakePHPの規約に従ってカラム名が指定されていますので、デフォルトでカラム「company_details.company_id」をキーとしてテーブル「companies」とアソシエーション(連結)する処理が生成されます。
 
具体的には、「/src/Model/Table/CompanyDetailsTable.php」に下記の記述が生成されますが、11~14行目がそれにあたります。
 

 
 

「created_user_id」「modified_user_id」をキーに「Users」とアソシエーションする

 
「created_user_id」「modified_user_id」は、各テーブルのレコードを登録、更新した際に、それを実行したユーザの IDを保存するカラムで、カラム「users.id」の情報が入っています。
そのため、「created_user_id」「modified_user_id」をテーブル「Users」とアソシエーションしたいと思いますが、CakePHPの規定に則っていないカラム名ですので、自動的にはアソシエーションの処理はしてくれません。
 
では、「created_user_id」「modified_user_id」をテーブル「Users」とアソシエーション(関連付け)するにはどうすればいいでしょうか?
と言う対応をしていきます。
 
 
「created_user_id」「modified_user_id」はすべてのテーブルにありますので、どのテーブルでもいいのですが、「company_details」への対応をサンプルとします。
 
 

Modelにアソシエーションの情報を記述

 
まず初めに、「/src/Model/Table/CompanyDetailsTable.php」に下記の記述を追記します。
先に紹介した 14行目に続けて追記するといいでしょう。
 

 
 

アソシエーション情報の各項目の解説

 
$this->hasOne('ModifiedUser', [」の「ModifiedUser」はアソシエーションの名称です。
この名称を使用して Controllerで containします。
記述はアッパーキャメルケース(最初の文字も大文字のキャメルケース)です。
また、後述しますがここの名称は単数形の単語をした方がよさそうです。
 
「className」は、アソシエーションする先の Model名です。
 
「foreignKey」は、アソシエーションする先のカラム名です。「ID」で連結することが多いと思いますが、「foreignKey」を指定する事で「ID」以外も連結できます。
(未検証ですが、複数のキーを指定する方法もあるようです。)
 
「bindingKey」は、アソシエーション元のカラム名です。
 
「joinType」は、アソシエーションのタイプで「LEFT」と「INNER」があります。デフォルトは「LEFT」。
 
 

「joinType」の「LEFT」と「INNER」について

 
「joinType」は、連結するレコードがない場合にどう処理するのか、を指定する区分です。
「LEFT」は、連結先のレコードがない場合は「null」の値を持つレコードがあるものとして処理をします。
「INNER」は、連結先のレコードがない場合は連結元のレコードもないものとして処理します。
 
今回のように「company_details」から「companies」の情報を見に行く場合は、「companies」がない状況は存在しないので、「INNER」でも問題は起こらないでしょう。
 
ですが、「companies」から「company_details」の情報を見る場合、「company_details」のレコードは存在しない場合もあるかもしれません。
この時「joinType」に「INNER」を指定していると、「companies」のレコードもないものとして取得することができません。
 
 

Controllerにアソシエーションを読み込む情報を記述

次に、Controllerの対応です。

今回はサンプルとして「view」アクションに追加する処理です。
「/src/Controller/CompanyDetailsController.php」ファイルの「view」アクションに下記の処理を追記します。
 
Bakeするとデフォルトでは「contain句」には「Companies」が記述されていますが、これに、「Model」に追記したアソシエーション名を追記します。
 
 

 
 

Viewテンプレートに値を取得する処理を記述

 
最後に viewテンプレートでの対応です。
「/templates/CompanyDetails/view.php」に記述します。
 
viewテンプレートでは「$companyDetail->created_user」で取得することができます。
「created_user」は、Modelに記述したアソシエーション名をスネークケース(アンダースコアで単語をつなぐ記述方法)で記述します。
 
$companyDetail->created_user」には、「Users」の情報がオブジェクトとして取得していますので、必要に応じて値を取得します。
 
 

 
 

Viewテンプレートで呼び出す際の注意点

 
「created_user_id」では問題は発生しませんが、カラム名によっては Viewテンプレートで値を取得した際にエラーが発生する場合があります。
 
具体的には「user_sales_id」の「sales」のように最後が「s」で終わる単語を使う場合は気を付けましょう。
 
 
例えば、先のテーブル「company_details」に「user_sales_id(担当営業)」と言う項目があり、これにアソシエーションの設定をするとします。
この場合、モデルの「/src/Model/Table/CompanyDetailsTable.php」には下記のように記述するとします。
カラム名が「user_sales_id」ですのでアソシエーション名は「UserSales」とします。
 

 
 
「/src/Controller/CompanyDetailsController.php」ファイルの「view」アクションの「contain句」には「UserSales」を追記します。
ここまでは、先に紹介した方法と何も違いがありません。
 

 
 
そして、Viewテンプレート「/templates/CompanyDetails/view.php」では「user_sale」で取得します!!
 

 
ここが非常に重要なポイントです。
モデルで指定したアソシエーション名は「UserSales」ですので、Viewテンプレートで取得する際は「user_sales」だと思ってしまいますが、なんと「user_sale」なのです!!
 
「営業」と言う意味で「sales」を使っているので「UserSales」の「Sales」を複数形だという認識は全くないわけなんですが、CakePHPは複数形だと認識して勝手に単数形にしてくれちゃうんです!
 
 
と言うわけで、アソシエーション名は単数形で指定する方が無難です。
ただ、「Sales」と「Sale」では意味が違うので、「UserSales」のように最後が「s」で終わる単語を使用する場合は Viewテンプレートで値を取得する際に注意しましょう。
 
デフォルトとは異なる処理をしているので、Viewテンプレートでエラーが発生しても Modelや Controllerの方の記述のミスじゃないかと思ってそちらばかり見てしまいますが、実は、Viewテンプレートの記述の方だった、ということでなかなか気づけない不具合かと思います。
 
 
最後に。
あわせて、オフィシャルサイトの Cakebookも参照してください。
https://book.cakephp.org/4/ja/orm/associations.html
 
 

CakePHP4の関連記事

CakePHP4でロギングスコープやログレベルを使用してログを出し分ける方法を解説
CakePHP2、CakePHP3、CakePHP4、CakePHP5のバージョンを調べる 2つの方法
Windows上のXAMPP環境のCakePHPのコマンド実行時に環境変数を指定する方法
CakePHP4で複数の引数(パラメータ)を付与してコマンドを実行する方法
CakePHP4 のコマンドプログラムからコンポーネントを読み込む方法解説
CakePHP4 でコマンドプログラム(シェルプログラム)を作成する方法解説
Windows環境の XAMPPを利用して CakePHPの開発する際の注意点
CakePHP4の規約外のカラムをキーにアソシエーション(テーブル連結)する方法
CakePHPで Auto Incrementを外すと Duplicate entry '0' for keyのエラーが出るかも
CakePHPのFlashエラーは出るが入力項目ごとのメッセージが出ないエラーの原因
 
その他の「CakePHP4」に関する記事一覧
 
 

 - CakePHP 3.x 4.x

GoogleAdwords

GoogleAdwords

最後までお読みいただきましてありがとうございます。
この記事が参考になったと思いましたらソーシャルメディアで共有していただけると嬉しいです!

Message

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

下記の空欄を埋めてください。 * Time limit is exhausted. Please reload CAPTCHA.

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

※入力いただいたコメントは管理者の承認後に掲載されます。

  関連記事

CakePHP4でロギングスコープやログレベルを使用してログを出し分ける方法を解説
CakePHP4でロギングスコープやログレベルを使用してログを出し分ける方法を解説

CakePHPのログ出力方法の解説。app.phpにログ設定をし、スコープやレベルを指定してログ出力を振り分ける方法、CakePHP4で配列出力にはvar_exportが必要なことなどを解説。

CakePHP 2.3で saveの便利な使い方・サンプルソース付き

CakePHPのレコードを保存、更新する際に使う Saveを詳細解説します。

CakePHP 2.3 コマンドラインからPHPのシェル実行の方法解説

CakePHP 2.3でコマンドラインから CakePHPで記述した処理を実行する方法を解説します。

CakePHP 2.3 ID以外のカラムでアソシエーション(連携)をさせる場合の詳細ページの注意点

ID以外のカラムでアソシエーション(連携)させて詳細ページを表示させる際の考え方と注意点をサンプルソースを用いて解説しています。

CakePHPで同一テーブル内の値を比較する条件でレコードを取得する方法
CakePHPで同一テーブル内の値を比較する条件でレコードを取得する方法

CakePHPの同一テーブルにある項目の値を比較し条件に合致するレコードを取得する方法を解説。[”項目名”=>”値”]ではなく[”項目名 = 項目名”]と書くところがポイント。

CakePHP 2.3でファイルのアップロード処理を作る

CakePHPでプラグインを使わないファイルアップロード処理を解説します。簡単です。DBにファイルを格納する方法も。

CakePHP3で生の SQLの実行はConnectionManagerを使う
CakePHP3で生の SQLの実行はConnectionManagerを使う

CakePHP3で生の SQL文を実行する方法を解説。クリエビルダーを使う場合は TableRegistryを利用するが、SQLを実行する場合は ConnectionManagerを使う。プリペアードステートメントの使用方法も解説。

CakePHP 2.3で確認画面付きのお問い合わせフォームの作り方

CakePHPで確認画面付きのお問い合わせフォーム、メールフォームの作り方をサンプルを提示しながら解説。

CakePHP4で定数の設定と呼び出し方法の解説(defineとConfigure)
CakePHP4で定数の設定と呼び出し方法の解説(defineとConfigure)

CakePHP4で定数を設定、使用する方法を解説。定数定義はdefineとConfigureを使用する方法を解説。また、bootstrap.phpに直接記述する方法と別のファイルにする方法を解説。

CakePHP3でアソシエーション先のカラムでデータをソートして取得したい
CakePHP3でアソシエーション先のカラムでデータをソートして取得したい

アソシエーション先のテーブルのカラムをキーにソートをしたデータを取得したい!ときの記述方法を解説。「orderAsc()」ではなく「contain()」の中にSort条件を記述する。