エス技研

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


CakePHP3でassociatedを使って関連データをまとめて保存する方法(hasOne、hasMany、belongsTo)

      2017/10/28

CakePHP3でassociatedを使って関連データをまとめて保存

 

関連データの想定イメージ

 
 EntryDatas ─┬─ JobDatas1
        ├─ JobDatas2
        └─ JobDatas3
 
求人情報サイトで、1回のエントリー(EntryDatas)で複数の求人(JobDatas)に応募するようなことを想定していまして、1つのエントリーに関連付けて、複数の求人情報もまとめて保存する方法を解説します。
 
 

想定のテーブルイメージ

 
テーブル名は「entry_datas」「job_datas」で、それぞれ以下のような構造を想定しています。
 

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」です。
 

    public function initialize(array $config)
    {
          :
          :
        $this->hasMany('JobDatas', [
            'foreignKey' => 'entry_datas_id'
        ]);
    }

 
bakeをしただけでは、「EntryDatasTable.php」ファイルには、テーブルの連携(アソシエーション)の情報が記載されませんので、上記の通り、「hasMany」の記述を追加します。
この際、連携先の「JobDatas」のテーブル名の指定は、「JobDatas」でも「job_datas」のどちらでも動きます。
が、規約に則った記述方法は「JobDatas」であろうと思います。
 
 


 

テンプレートファイルの生成

 
続いて、入力のフォームを生成します。
対象ファイルは、「EntryDatas」側の「add.ctp」です。
 

<?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」です。
 

$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の関連記事

CakePHPのpostlinkで生成した削除リンクをクリックしても処理が実行されない対処法
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」に関する記事一覧
 
 

 - CakePHP 3.x 4.x 5.x

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

Message

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

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

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

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

  関連記事

CakePHP4のcake cache clear_allでPermission deniedはパーミッションの変更が必要
CakePHP4のcake cache clear_allでPermission deniedはパーミッションの変更が必要

CakePHP4でキャッシュをクリアするコマンドcake cache clear_allでPermission deniedのエラーが出るのはcakeにパーミッションが足りないとき。その対処方法を解説。

CakePHP3でシェルを作成しコマンドラインから実行・CakePHP2との違い
CakePHP3でシェルを作成しコマンドラインから実行・CakePHP2との違い

CakePHP3のシェルスクリプトを作成し、コマンドラインから実行する方法を解説。複数単語をつなげる場合の対応方法がCakePHP2より制限が厳しくなったのでCakePHP3の命名規則の確認が必要だ。

CakePHP4のCakeDC/Usersの Usersへの接続、バリデーションのカスタマイズ方法解説
CakePHP4のCakeDC/Usersの Usersへの接続、バリデーションのカスタマイズ方法解説

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

CakePHP5系でDeprecatedを回避しfindListでキーと値のカラムを指定して取得する方法
CakePHP5系でDeprecatedを回避しfindListでキーと値のカラムを指定して取得する方法

CakePHP4のfindListでキーと値のカラムを指定してテーブルにアクセスする方法がCakePHP5では「Deprecated(非推奨)」となった。推奨の記述方法を解説。

CakePHP3で環境変数を設定して本番環境と開発環境を分けて処理をする場合
CakePHP3で環境変数を設定して本番環境と開発環境を分けて処理をする場合

CakePHP3で開発環境と本番環境とで違う設定ファイルを読み込ませて環境ごとに定数を切り替える方法を解説。Apacheのhttpd.confに環境変数を設定し、それを読み込み判別する。

CakePHP 2.3でOn Duplicate Key構文を実装

CakePHPで On Duplicate Key構文を Queryを利用して実装する方法をサンプルソース付きで解説します。

CakePHPで Auto Incrementを外すと Duplicate entry '0' for keyのエラーが出るかも
CakePHPで Auto Incrementを外すと Duplicate entry ‘0’ for keyのエラーが出るかも

CakePHPでAuto Incrementの設定を変更したときに「Duplicate entry ‘0’ for key」のエラーが出た。原因はModel内で IDを編集する処理の追加を忘れていたからだった。

CakePHPのFlashエラーは出るが入力項目ごとのメッセージが出ないエラーの原因
CakePHPのFlashエラーは出るが入力項目ごとのメッセージが出ないエラーの原因

Bakeして自動生成した入力フォーム処理を元に少し処理を追加したら、入力エラーがあってもエラーメッセージが表示されなくなった。原因はリダイレクトの処理にあった。

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

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

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

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


Warning: Trying to access array offset on null in /home/ss-giken/s-giken.net/public_html/blog/wp-content/plugins/amazonjs/amazonjs.php on line 637