エス技研

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


CakePHP3の1対多での連携を中間テーブルを使った多対多の連携に変更するときの手順

   

CakePHP3で「1対多」から「多対多」の連携に変更する手順

 

「1対多」と中間テーブルを使った「多対多」連携について

 
CakePHP3で「1対多」のテーブル連携を、中間テーブルを利用した「多対多」のテーブル連携方式に変えるときの手順を紹介します。
 
CakePHP3の1対多での連携を中間テーブルを使った多対多の連携に変更するときの手順
 
 
どのような場合に必要になるか、というと
 
例えば、
Topics、Categoriesというテーブルがあるとします。
Topicsは Categoryによって分類されています。
 
当初は、Topicsの記事はそれぞれに 1つの Categoryが割り当てられていました。
ですが、運用を始めてみたら、Topicsの記事は複数の Categoryにまたがるものもあることが判明しました。
 
そのため、それまでは「1対多」だったテーブル構成を、中間テーブル作成して「多対多」に対応できるようにすることにしました。
 
その時の対応方法の手順の紹介です。
 
 
サンプルの「categories」と「topics」のテーブルは以下の想定です。
 

 
 
カテゴリは、下記の記事でも紹介していますが、CakePHP3のブログチュートリアルにあるツリービヘイビアの機能を利用したカテゴリの構造になっています。
CakePHP3のfriendsofcake/searchでツリーカテゴリーの子階層も含めて検索する方法
 
 

「1対多」から中間テーブルを使った「多対多」連携に変更する手順

 
先に、「例えば」と書いてしまいましたが、まさに、今回私が必要になった状況です。
最初は Topicsに対して 1つの Categoryで足りると思っていましたが、topicsの内容によっては複数の Categoryに属する場合があり、対応を迫られたのです。
 
 
CakePHP3で中間テーブルを利用した処理は下記の検索処理などで使っていました。
CakePHP3のfriendsofcake/searchでブックマークチュートリアルのタグ検索を実装
 
そのため、構築の仕方は理解していましたが、今回の対応を行うときに対応漏れがあり、うまく動かずに悩んだことがありました。
そのため、今後のためにも手順を記録しておくことにしました。
 
 

中間テーブルを作成する

 
まず最初に中間テーブルを作成します。
中間テーブルは、「topic_id」と「category_id」を持つテーブルです。
 

 
 

「category_id」カラムを削除

 
Topicsテーブルから不要になる「category_id」カラムを削除します。
(削除しなくても問題は発生しませんが、不要なカラムは削除する方が望ましいでしょう。)
 

 
 

TopicTable.phpの更新

 
続いて、Tableファイルの更新になりますが、「TopicTable.php」と「CategoriesTable.php」とそれぞれ変更する箇所があります。
 
 
まず初めに「TopicTable.php」は、下記の通り、「Categories」テーブルとの「belongsTo」を止めて「belongsToMany」に変更します。
 
/src/Model/Table/TopicTable.php

 
 

CategoriesTable.phpの更新

 
「CategoriesTable.php」は、下記の通り、「Topics」テーブルとの「belongsToMany」を追加します。
今回は設定がありませんでしたが「hasMany」の設定をしている場合は、その処理は削除します。
 
/src/Model/Table/CategoriesTable.php

 
 

inputTopics.phpの更新

 
カテゴリの選択する箇所のテンプレートを更新します。
ここでは、マルチセレクト(複数選択式)のセレクトボックスを設定しています。
 
/src/Template/Element/inputTopics.php

 
 

Entity/Topic.phpの更新

 
ここ以降の項目が対応忘れが発生しやすい箇所になります。
 
まず 1つ目が「Entity」です。
下記のように「category」は「categories」のように複数形になります。
コメントにも書いていますが、これを記述していないと値が保存されません。エラーは出ませんので原因を特定しにくいエラーです。
 
'*' => true,」で設定している場合は特に対応は必要ありません。
 
/src/Model/Entity/Topic.php

 
 

TopicsController.phpの変更

 
コントローラーの変更ポイントです。
get()や find()で値を取得する際に、関連テーブルとして「Categories」を指定する必要があります。
コメントに書いていますが、これがないと、テーブルには保存されたレコードがあるのにも関わらず、その情報が更新画面に出てこない、というエラーになります。これもエラーが出ないため、原因を特定しにくいエラーです。
 
 
/src/Contorller/TopicsController.php

 
 

中間テーブルを使った「多対多」の項目「category_id」を検索条件にする場合の TopicsController.phpの変更

 
単純に指定したレコードだけを get()で取得する場合は問題ありませんが、「category_id」を検索条件に検索する場合は記述する内容が大きく変わります。
 
/src/Contorller/TopicsController.phhp

 
細かなところですが、条件の「"category_id"=>$categoryId]」の「$categoryId」を変数とするなら「use($categoryId)」の記述が必要です。
$categoryId」を変数ではなく値を直接記述する場合は use句は記述する必要はありません。
 
 
CakePHP3の ORM matchingメソッドについて詳しく知りたい場合は、下記の記事などを参考にしてみてはいかがでしょうか?
https://s8a.jp/cakephp-3-matching
https://book.cakephp.org/3.0/ja/orm/query-builder.html#id17
 
 

view.ctpの変更

 
最後に、データの取り出しの際も変更の注意点があります。
「category」は複数入ることがあるためここも複数形の「categories」にする必要があります。
 
/src/Template/Topics/view.ctp

 
 

CakePHP3で中間テーブルを扱う場合の関連記事

 
中間テーブルはちょっとだけ仕組みの理解が必要なため、中間テーブルについてもう少し理解を深めたい、という場合もあるでしょう。
そういう場合は下記の記事なども参考になるかと思います。
 
CakePHP3のfriendsofcake/searchでブックマークチュートリアルのタグ検索を実装
 
CakePHP3 ブログチュートリアル
https://book.cakephp.org/3/ja/tutorials-and-examples/blog/blog.html
 
 

CakePHP3の関連記事

CakePHP3でPHP Simple HTML DOM Parserを使ってスクレイピングする方法
CakePHP3のInsert On Duplicate Key Update(upsert)構文を解説・バルク処理も
CakePHP3の1対多での連携を中間テーブルを使った多対多の連携に変更するときの手順
CakePHP3でデフォルトのソート条件を設定してユーザの選択肢たソート条件を有効にする方法
CakePHP3で Ajaxを使う方法の解説。3.6以降対応。Successとthenの両方を解説。
CakePHP3でパンくずの指定は HTMLヘルパーを使って指定する方法を解説
CakePHP3にOGPをfetch、asignを利用してテンプレートごとに指定する方法を解説
CakePHP3のOGPはHTMLヘルパーの$this->Html->meta()を使って設定
CakePHP3でkeywords、DescriptionをHTMLヘルパーを使って設定する
CakePHP3で環境変数を設定して本番環境と開発環境を分けて処理をする場合
 
その他の「CakePHP3」に関する記事一覧
 
 

 - CakePHP 2.x 3.x

GoogleAdwords

GoogleAdwords

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

Message

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

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

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

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

  関連記事

CakePHPで favicon.icoやapple-touch-icon-144-precomposed.pngが could not be foundのエラーが出るときの対処方法
CakePHPで favicon.icoやapple-touch-icon-144-precomposed.pngが could not be foundのエラーが出るときの対処方法

CakePHPで「CakeDC/Users」などルーティングを行うプラグインを利用するときに、favicon.icoやapple-touch-icon-144-precomposed.pngがNotFoundエラーになることがある。その対処方法の解説。

CakePHP 2.3 Search Pluginで検索処理 その3入力エリア一つで複数の項目を同時に検索する方法

CakePHPの検索プラグイン Search Pluginの検索処理の中で入力エリア一つで複数の項目を同時に検索する方法を解説。

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

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

CakePHP3でDocumentRootやwebroot、imgフォルダのURLやドメイン、パスを取得
CakePHP3でDocumentRootやwebroot、imgフォルダのURLやドメイン、パスを取得

URLやドメイン、フォルダへのパスの取得は、ビューではUrlHelperを使い、コントローラーではRouterクラスを使います。第2引数の指定でURLを取得することも可能。

CakePHP3で保存前にバリデーション結果を取得する2つの方法
CakePHP3で保存前にバリデーション結果を取得する2つの方法

CakePHP3でデータベースに値を保存する前にバリデーションを行い、その結果によって処理を振り分ける方法について解説。「$topic->errors()」と「$topic->hasErrors()」の2つの方法がある。

CakePHP3で Ajaxを使う方法の解説。3.6以降対応。Successとthenの両方を解説。
CakePHP3で Ajaxを使う方法の解説。3.6以降対応。Successとthenの両方を解説。

CakePHP3でajaxを利用する処理の実装方法を解説。プルダウンを変更するとデータベースの値を取得し検索結果の内容を変更するというような処理を想定。CakePHP3.6以降の CSRF対策対応済。

CakePHP3の更新画面でUpload Plugin 3.0を使う方法、viewで使う方法解説・その3
CakePHP3の更新画面でUpload Plugin 3.0を使う方法、viewで使う方法解説・その3

CakePHP3でファイル、画像をアップロードするプラグイン、upload plugin 3を導入する手順を解説した記事。3部作のその3で記事を更新する際のファイルの取り回しなどについてを解説。

CakePHP3のビューで受取ったテーブルのオブジェクトを連想配列に変換する方法
CakePHP3のビューで受取ったテーブルのオブジェクトを連想配列に変換する方法

コントローラーからビューに送ったテーブルのオブジェクトを連想配列に変換し、ビューの中で自由に使えるようにするメソッド「toArray()」の解説。連想配列に変換できれば利用度アップ!

CakePHP3のcontroller内でテンプレート、レイアウトを変更する際の指定方法

CakePHP3でテンプレートファイルやレイアウトファイルをデフォルトのものから別のものに変更したい場合の指定方法を解説。

CakePHP3のCakeDC/Usersのバリデーションのカスタマイズ方法解説
CakePHP3のCakeDC/Usersのバリデーションのカスタマイズ方法解説

CakeDC謹製Usersプラグインの紹介。Usersのカスタマイズとして入力項目のバリデーションの変更を、プラグインのファイルは触らずオーバーライドにより実装する方法を解説する。