CakePHP3でassociatedを使って関連データをまとめて保存する方法(hasOne、hasMany、belongsTo)
2017/10/28
CakePHP3でassociatedを使って関連データをまとめて保存
関連データの想定イメージ
EntryDatas ─┬─ JobDatas1
├─ JobDatas2
└─ JobDatas3
求人情報サイトで、1回のエントリー(EntryDatas)で複数の求人(JobDatas)に応募するようなことを想定していまして、1つのエントリーに関連付けて、複数の求人情報もまとめて保存する方法を解説します。
想定のテーブルイメージ
テーブル名は「entry_datas」「job_datas」で、それぞれ以下のような構造を想定しています。
1 2 3 4 5 6 7 8 9 10 11 12 |
CREATE TABLE `entry_datas` ( `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT, `title` text NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `job_datas` ( `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT, `entry_datas_id` int(11) NOT NULL, `rank` int(11) NOT NULL, `entry_message` text, `title` text DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
このテーブルを基にして、「bake all」で各種ファイルを生成したものをベースにします。
モデルのテーブルファイルの変更
まず、モデルのテーブルファイルを修正します。
対象ファイルは「EntryDatasTable.php」です。
1 2 3 4 5 6 7 8 |
public function initialize(array $config) { : : $this->hasMany('JobDatas', [ 'foreignKey' => 'entry_datas_id' ]); } |
bakeをしただけでは、「EntryDatasTable.php」ファイルには、テーブルの連携(アソシエーション)の情報が記載されませんので、上記の通り、「hasMany」の記述を追加します。
この際、連携先の「JobDatas」のテーブル名の指定は、「JobDatas」でも「job_datas」のどちらでも動きます。
が、規約に則った記述方法は「JobDatas」であろうと思います。
テンプレートファイルの生成
続いて、入力のフォームを生成します。
対象ファイルは、「EntryDatas」側の「add.ctp」です。
1 2 3 4 5 6 7 8 9 10 11 |
<?php echo $this->Form->input('title'); echo $this->Form->input("job_datas.0.rank"); echo $this->Form->input("job_datas.0.entry_message"); echo $this->Form->input("job_datas.0.title"); echo $this->Form->input("job_datas.1.rank"); echo $this->Form->input("job_datas.1.entry_message"); echo $this->Form->input("job_datas.1.title"); ?> |
「EntryDatas」側の入力フォームは変更しません。
「JobDatas」側の入力フォームを追加します。その際、「job_datas」のテーブル名を指定して記載します。
また、入力エリアを複数設ける場合は「0」「1」...と連番を振っていきます。
この際、テーブル名を追記するのは、「JobDatas」側だけです。
テーブル名を明記するため、「EntryDatas」側にも書いた方がいいような気もするのですが、「entry_datas.title」のように記述してしまうと、正しく保存されなくなります。
(記述してしまうと、save()関数を実行しても、エラーログは出力されず、falseの処理となるため、原因がよく分からず悩むことになります。)
コントローラーの変更
コントローラーの更新を行います。
対象ファイルは「EntryDatasController.php」です。
1 2 3 4 5 6 7 8 9 10 11 12 |
$entryData = $this->EntryDatas->newEntity(); if ($this->request->is('post')) { $entryData = $this->EntryDatas->patchEntity($entryData, $this->request->data, ['associated' => ['JobDatas']]); if ($this->EntryDatas->save($entryData)) { $this->Flash->success(__('The site name has been saved.')); return $this->redirect(['action' => 'index']); } else { $this->Flash->error(__('The entry data could not be saved. Please, try again.')); } } |
変更箇所は、3行目の一番後ろに「, ['associated' => ['JobDatas']]
」を追加するところです。
この記述の「JobDatas」の部分は、テーブルファイルに追記した「hasMany」で記述したテーブル名を指定します。
「JobDatas」なのか「job_datas」なのか、テーブルファイルと同じものを指定します。同じではない場合はエラーとなります。
CakePHP2の情報で CakePHP3でもそうなのか未確認の情報
下記の CakePHP2のマニュアルには、いくつか興味深い内容が記述されています。
CakePHP は1度に複数のモデルの バリデーションとデータ保存をしてくれる saveAssociated() という 便利なメソッドを提供しています。 また、 saveAssociated() はデータベースの整合性を確保するために トランザクションの機能もサポートしています。 (つまり、あるモデルがデータ保存に失敗した場合は、他のモデルのデータも保存されません)
https://book.cakephp.org/2.0/ja/models/saving-your-data.html#hasone-hasmany-belongsto より抜粋
つまりは、この「saveAssociated()」の処理を利用して保存することで、保存時に不具合が発生しても、一部のレコードだけが保存されて整合性が無くなるということはない、ということです。
おそらく、CakePHP3にもこの機能があるのだと思いますが、CakePHP3のマニュアルにはそのような明記がなく、具体的な検証は行っていません。
どなたかわかりますでしょうか?
また、このようなトランザクション処理を正常に処理するため、MySQLの場合は、データベースのエンジンは「InnoDB」の必要があるようです。
「MyISAM」はトランザクション処理をサポートしていないためです。
もし、データの保存がうまくいかない場合は、データベースのエンジンが「MyISAM」でないかを確認することも必要かもしれません。
CakePHP3の関連記事
CakePHP4のCSS、JavaScript、画像のブラウザへのキャッシュをコントロールするCakePHP3でレコードを保存(追加、更新、Insert、Update)する複数の方法を紹介
CakePHP3でモデルなしフォームからCSVをアップロードしレコードを更新する方法解説
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」に関する記事一覧
GoogleAdwords
GoogleAdwords
この記事が参考になったと思いましたらソーシャルメディアで共有していただけると嬉しいです!
関連記事
-
CakePHP 2.3 ID以外のカラムでアソシエーション(連携)をさせる場合の詳細ページの注意点
ID以外のカラムでアソシエーション(連携)させて詳細ページを表示させる際の考え方と注意点をサンプルソースを用いて解説しています。
-
CakePHP3のCakeDC/Users、Authでログインなしでもアクセスを許可する設定
CakePHP3の Authコンポーネントや CakeDC/Usersプラグインなどを利用したユーザ管理・認証システムにおいて、ログインしていなくても見ることができるページの設定方法を解説。
-
CakePHP 2.3 テーブルの項目を演算した結果を条件として抽出する方法
アソシエーション(連携)している先のテーブルの項目で演算をする場合の考え方と注意点をサンプルソースを用いて説明しています。分かってしまえば簡単です。
-
CakePHP3で /Layout/defult.ctpにある titleタグ、h1タグを編集する方法
CakePHP3でtitleタグ、h1タグのテキストをデフォルトから変更する方法を解説。テンプレートファイルに「$this->assign()」でテキストを指定して「/Layout/defult.ctp」で受け取る。
-
CakePHP3のメッセージ日本語化の設定(国際化と地域化の機能の使い方の解説)
CakePHP3の英語のメッセージを日本語化(多言語化)する手順を解説。オリジナルのメッセージを作成する方法やプログラムで文言を追加する場合の対応なども解説。
-
CakePHP3のアソシエーション機能を使い関連レコードをまとめて削除
CakePHP3でレコードを削除する際に関連するレコードをまとめて削除する機能の解説。フレームワークのメリットを存分に発揮し、コマンドを1行追加するだけで実装可能。
-
CakePHP3のインストールでURL rewriting……のエラーが!その解決方法解説
CakePHP3をインストールしたら URL rewriting is not properly configured.のエラーが。原因は.htaccessが有効になっていないこと。httpd.confに設定を追加すればOK。
-
CakePHP3で画像・ファイルのアップロード処理を自作・解説付き・その2
ファイルのアップロード機能の自作サンプルコードとその解説のその2。アップロード機能に関連するファイルの更新や削除の処理や画像、フォルダのパスの指定方法などを含めて解説。
-
CakePHP 2.3 bakeの超初心者向けフォロー講座
CakePHP 2.3 bakeの超初心者向けフォロー講座
-
CakePHP3にWYSIWYGエディタのCKEditor4を設置、カスタマイズ方法を解説
WYSIWYGエディタであるCKEditor4をCDNを利用して簡単にCakePHP3に導入する方法とカスタマイズする方法を解説。CakePHP3にはページごとの振り分けを行うブロック化を利用する。