エス技研

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のFrozenDateで1ヵ月前、先月、今月1日、来月末の日付などを算出する方法
CakePHP4のcake cache clear_allでPermission deniedはパーミッションの変更が必要
CakePHP4のクリエビルダーを使用してOR条件をAND条件でつなぐSQL文を作る方法
CakePHP4のController内でViewテンプレート、レイアウトの変更設定を記述する方法
CakePHP4から外部のデータベースにアクセスする方法解説
CakePHP4の数値項目は「like %10%」の部分一致検索(find select)はできない
CakePHP4でロギングスコープやログレベルを使用してログを出し分ける方法を解説
CakePHP2、CakePHP3、CakePHP4、CakePHP5のバージョンを調べる 2つの方法
Windows上のXAMPP環境のCakePHPのコマンド実行時に環境変数を指定する方法
CakePHP4で複数の引数(パラメータ)を付与してコマンドを実行する方法
 
その他の「CakePHP4」に関する記事一覧
 
 

 - CakePHP 3.x 4.x

GoogleAdwords

GoogleAdwords

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

Message

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

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

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

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

  関連記事

CakePHP 2.3 Search Pluginで検索処理 その5入力項目に複数項目入力した場合の AND検索、OR検索

CakePHPの検索プラグイン Search Pluginの検索処理の中で複数項目を入力した場合の AND検索、OR検索についての解説です。

CakePHP 2.3で PDFを作成する方法を調査「mpdf」「TCPDF」「FPDF」

CakePHPで PDFを編集、出力するには「mpdf」「TCPDF」「FPDF」といったプラグインがあり、使い勝手を比較検討しました。TCPDFが一番良さそうでした。

CakePHP3のForm Helperの使い方のまとめ

CakePHP3になりフォームヘルパーの使い方も大きく変わりましたので、使い方をまとめました。基本的な使い方からプラスアルファの便利な使い方まで紹介。

CakePHP 2.3 連携先のテーブルの項目で条件抽出する場合

アソシエーション(連携)している先のテーブルの項目で条件抽出する際の考え方と注意点をサンプルソースを用いて説明しています。

CakePHP3のルーティング(routes.php)の変更が反映されない時はキャッシュのクリアを
CakePHP3のルーティング(routes.php)の変更が反映されない時はキャッシュのクリアを

CakePHP3でルーティングの設定変更をしたけど反映されない!そんなときは慌てず騒がずキャッシュをクリアしよう!ルーティングの設定もキャッシュされることがあるらしい。

CakePHP3にデイトピッカー jQuery UI DatePickerを実装する手順の解説
CakePHP3にデイトピッカー jQuery UI DatePickerを実装する手順の解説

CakePHP3にjQuery UIのDatePickerを実装する手順を説明。併せて、デイトピッカーを設置に関連するCakePHP3の解説と、テーマを変更したり、表記を変更するカスタマイズする方法なども紹介。

CakePHP3チュートリアルで日付と時刻のDateTimeでエラーが出たときの対処方法
CakePHP3チュートリアルで日付と時刻のDateTimeでエラーが出たときの対処方法

CakePHP3のブックマークチュートリアルには記載ミスもあり、そのまま動かない個所もある。CakePHP3では namespaceを使うようになったので、classを呼び出すときに¥を追加する必要が!

CakePHPのバリデーションを入力値・項目の条件によって変える方法を解説
CakePHPのバリデーションを入力値・項目の条件によって変える方法を解説

入力された値によってバリデーション(入力チェック)の内容を切り替える。その処理をCakePHPで実装する方法を解説。条件ごとに unset関数を使ってバリデーションを削除する、という方法を採る。

CakePHP2の検索Plugin CakeDC/Searchで重複を省くgroup by(distinct)の実装方法
CakePHP2の検索Plugin CakeDC/Searchで重複を省くgroup by(distinct)の実装方法

CakePHP2の検索プラグイン「CakeDC/Search」で、重複レコードを省くgroup by、distinctを使う方法についての解説。設定する場所はpaginatorの条件とするので、find()関数と同じ。

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

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