CakePHP のバリデーションの基本を勉強します。 | oki2a24 の次の投稿となります。
以前ひとつのテーブルからのデータ取得を行いました。それも、モデルなしで。今回はモデルをしっかり使って、そしてテーブルは複数を連携させて、という例となります。2つのテーブルを使用しますが、連携のさせ方を網羅させて、しらみつぶしに動きを調べようと思います。
今回は、hasAndBelongsToMany を除いた hasOne、belongTo、hasMany の3パターンを取り扱います。
ポイント
- モデルに連携したい相手のモデルを書く。書き方は、hasOne、belongTo、hasMany、hasAndBelongsToMany の4種類ある。
- hasOne 1:1。相手テーブルに自テーブルの id 値を設定します。例、users テーブルの1つの行は、profiles テーブルの1つの行を持っている。
- belongTo n:1。自テーブルに相手テーブルの id 値を設定します。例、users テーブルの1行は、recipes テーブルの多くの行を持つことができる。
- hasMany 1:n。相手テーブルに自テーブルの id 値を設定します。例、recipes テーブルの多くの行は、users テーブルの1つの行に所属している。
- belongTo と hasMany はどちらも1つに対して複数の対応ですが、1:n ( hasMany )の場合は1つの行に対して複数の行が紐づいた状態でデータを取得できます。一方、n:1 ( belongTo ) の場合は1つの行に対して1つの行が紐づいた状態でデータを取得できます。
- モデルの連携は適当では駄目です。エラーとなります。または、変なデータが取れると思います。
前提
- CakePHP 2.1.3 導入済み。
- ドキュメントルート/cake/sample/(ここにCakePHP が入ってます。app ディレクトリとか、.travis.yml ファイルとか。)
連携のパターンとテーブル
personals テーブルと、boards テーブルの2つを例にとります。boards テーブルに、personal_id 列を設け、これで personals テーブルと連携します。3つの連携方法と組み合わせて、全部で次の6パターンを試しました。
結果も出てしまっていますけれども、パターンは次のとおりです。
No | 関係 | Personal モデル | Board モデル | Boards コントローラ index アクション | 正誤 |
---|---|---|---|---|---|
1 | Personal hasOne Board | public $hasOne = ‘Board’; | 無 | $this->Personal->find(‘all’); | 正 |
2 | Personal belongsTo Board | public $belongsTo = ‘Board’; | 無 | $this->Personal->find(‘all’); | 誤 |
3 | Personal hasMany Board | public $hasMany = ‘Board’; | 無 | $this->Personal->find(‘all’); | 正 |
4 | Board hasOne Personal | 無 | public $hasOne = ‘Personal’; | $this->Board->find(‘all’); | 誤 |
5 | Board belongsTo Personal | 無 | public $belongsTo = ‘Personal’; | $this->Board->find(‘all’); | 正 |
6 | Board hasMany Personal | 無 | $this->Board->find(‘all’); | 誤 |
テーブルは次の二つです。行データのSQL も載せておきます。
-- DB、ユーザ、の作成。パスワードの設定 GRANT ALL PRIVILEGES ON sampledb.* TO sampleuser@localhost IDENTIFIED BY 'samplepassword'; FLUSH PRIVILEGES; CREATE DATABASE sampledb CHARACTER SET utf8; -- -- テーブルの構造 `boards` -- CREATE TABLE IF NOT EXISTS `boards` ( `id` INT NOT NULL AUTO_INCREMENT, `personal_id` INT NOT NULL, `title` varchar(255) NOT NULL, `content` text NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ; -- -- テーブルのデータをダンプしています `boards` -- INSERT INTO `boards` (`id`, `personal_id`, `title`, `content`) VALUES (1, 1, 'はっけよーい', 'のこった!★のこった!★'), (2, 1, '位置について、よーい', 'ドン!ドン!ドン!ドドンガドン! ドン!ドン!ドン!ドドンガドン! '), (3, 1, 'こんにちは!', 'こんにちは!こんにちは!'), (4, 1, 'おはよう!', 'おはようっ!ぐっとモーニング!'), (5, 1, 'はっけはっけ', 'のこった!のこった!のこった!のこった!'), (6, 2, 'かかかかkっか', 'カッカッカッカッカッ!'), (7, 2, '佐藤佐藤!!', '佐藤佐藤佐藤佐藤'), (8, 2, 'あまいよ', 'あっま~い!甘い、砂糖だよ♪'), (9, 3, 'しましま', 'しまうましまうまサファリアフリカ'); -- -- テーブルの構造 `personals` -- CREATE TABLE IF NOT EXISTS `personals` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, `comment` varchar(255) DEFAULT NULL, `created` datetime DEFAULT NULL, `modified` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ; -- -- テーブルのデータをダンプしています `personals` -- INSERT INTO `personals` (`id`, `username`, `password`, `comment`, `created`, `modified`) VALUES (1, 'yamada', 'yamada', '山田', NULL, NULL), (2, 'sato', 'sato', '佐藤', NULL, NULL), (3, 'kato', 'kato', '加藤', NULL, NULL);
ソース
cake/sample/app/Model/Personal.php
<?php class Personal extends AppModel { public $name = 'Personal'; // public $hasOne = 'Board'; // public $belongsTo = 'Board'; // public $hasMany = 'Board'; } ?>
4、5、6行目のコメントパターンによって外して試します。
cake/sample/app/Model/Board.php
<?php class Board extends AppModel { public $name = 'Board'; // public $hasOne = 'Personal'; // public $belongsTo = 'Personal'; // public $hasMany = 'Personal'; } ?>
こちらも、4、5、6行目のコメントパターンによって外して試します。
cake/sample/app/Controller/BoardsController.php
<!--?php class BoardsController extends AppController { // The name of this controller. Controller names are plural, named after the model they manipulate. public $name = 'Boards'; // An array containing the class names of models this controller uses. public $uses = array('Board', 'Personal'); /** * 初期表示 */ public function index() { // Personal を取得。 // $data = $this--->Personal->find('all'); // Board を取得。 // $data = $this->Board->find('all'); // ビューで使えるように DB データをセット $this->set('data', $data); } } ?>
public $uses でこのコントローラーで使用するモデルを指定します。2つのテーブルの連携を試すので、2つのモデルを指定しています。
14、16行目で、どちらのモデルから find するかをパターンによって切り替えます。
cake/sample/app/View/Boards/index.ctp
<h1>複数テーブル連携サンプル</h1> <pre> <?php print_r($data); ?> </pre>
結果 1.Personal hasOne Board
以下、http://localhost/cake/sample/boards/ にアクセスしたときの結果となります。
その前に、テーブルの連携図を掲載します。
結果の要点です。
Array ( [0] => Array ( [Personal] => Array ( [id] => 1 [username] => yamada [password] => yamada [comment] => 山田 [created] => [modified] => ) [Board] => Array ( [id] => 1 [personal_id] => 1 [title] => はっけよーい [content] => のこった!★のこった!★ ) ) ・・・ )
発行された SQL です。
SELECT `Personal`.`id`, `Personal`.`username`, `Personal`.`password`, `Personal`.`comment`, `Personal`.`created`, `Personal`.`modified`, `Board`.`id`, `Board`.`personal_id`, `Board`.`title`, `Board`.`content` FROM `sampledb`.`personals` AS `Personal` LEFT JOIN `sampledb`.`boards` AS `Board` ON (`Board`.`personal_id` = `Personal`.`id`) WHERE 1 = 1
結果 2.Personal belongsTo Board
結果の要点です。
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Personal.board_id' in 'on clause'
発行された SQL です。
SELECT `Personal`.`id`, `Personal`.`username`, `Personal`.`password`, `Personal`.`comment`, `Personal`.`created`, `Personal`.`modified`, `Board`.`id`, `Board`.`personal_id`, `Board`.`title`, `Board`.`content` FROM `sampledb`.`personals` AS `Personal` LEFT JOIN `sampledb`.`boards` AS `Board` ON (`Personal`.`board_id` = `Board`.`id`) WHERE 1 = 1
結果 3.Personal hasMany Board
結果の要点です。
Array ( [0] => Array ( [Personal] => Array ( [id] => 1 [username] => yamada [password] => yamada [comment] => 山田 [created] => [modified] => ) [Board] => Array ( [0] => Array ( [id] => 1 [personal_id] => 1 [title] => はっけよーい [content] => のこった!★のこった!★ ) [1] => Array ( [id] => 2 [personal_id] => 1 [title] => 位置について、よーい [content] => ドン!ドン!ドン!ドドンガドン! ドン!ドン!ドン!ドドンガドン! ) [2] => Array ( [id] => 3 [personal_id] => 1 [title] => こんにちは! [content] => こんにちは!こんにちは! ) [3] => Array ( [id] => 4 [personal_id] => 1 [title] => おはよう! [content] => おはようっ!ぐっとモーニング! ) [4] => Array ( [id] => 5 [personal_id] => 1 [title] => はっけはっけ [content] => のこった!のこった!のこった!のこった! ) ) ) ・・・ )
発行された SQL です。
1 SELECT `Personal`.`id`, `Personal`.`username`, `Personal`.`password`, `Personal`.`comment`, `Personal`.`created`, `Personal`.`modified` FROM `sampledb`.`personals` AS `Personal` WHERE 1 = 1 2 SELECT `Board`.`id`, `Board`.`personal_id`, `Board`.`title`, `Board`.`content` FROM `sampledb`.`boards` AS `Board` WHERE `Board`.`personal_id` IN (1, 2, 3)
結果 4.Board hasOne Personal
結果の要点です。
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Personal.board_id' in 'on clause'
発行された SQL です。
SELECT `Board`.`id`, `Board`.`personal_id`, `Board`.`title`, `Board`.`content`, `Personal`.`id`, `Personal`.`username`, `Personal`.`password`, `Personal`.`comment`, `Personal`.`created`, `Personal`.`modified` FROM `sampledb`.`boards` AS `Board` LEFT JOIN `sampledb`.`personals` AS `Personal` ON (`Personal`.`board_id` = `Board`.`id`) WHERE 1 = 1
結果 5.Board belongsTo Personal
結果の要点です。
Array ( [0] => Array ( [Board] => Array ( [id] => 1 [personal_id] => 1 [title] => はっけよーい [content] => のこった!★のこった!★ ) [Personal] => Array ( [id] => 1 [username] => yamada [password] => yamada [comment] => 山田 [created] => [modified] => ) ) ・・・ )
発行された SQL です。
SELECT `Board`.`id`, `Board`.`personal_id`, `Board`.`title`, `Board`.`content`, `Personal`.`id`, `Personal`.`username`, `Personal`.`password`, `Personal`.`comment`, `Personal`.`created`, `Personal`.`modified` FROM `sampledb`.`boards` AS `Board` LEFT JOIN `sampledb`.`personals` AS `Personal` ON (`Board`.`personal_id` = `Personal`.`id`) WHERE 1 = 1
結果 6.Board hasMany Personal
結果の要点です。
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Personal.board_id' in 'field list'
発行された SQL です。
SELECT `Personal`.`id`, `Personal`.`username`, `Personal`.`password`, `Personal`.`comment`, `Personal`.`created`, `Personal`.`modified`, `Personal`.`board_id` FROM `sampledb`.`personals` AS `Personal` WHERE `Personal`.`board_id` IN (1, 2, 3, 4, 5, 6, 7, 8, 9)
おわりに
結果の画面をキャプチャしたものも載せておきます。すごく長い投稿となってしまいました!
1.ersonal hasOne Board
2.ersonal belongsTo Board
3.ersonal hasMany Board
4.oard hasOne Personal
5.oard belongsTo Personal
6.oard hasMany Personal
「CakePHP2 のアソシエーション!モデルを連携させて複数テーブルからデータを取得する勉強します!」への4件の返信
[…] CakePHP のアソシエーション!モデルを連携させて複数テーブルからデータを取得する勉強します! | oki2a24 の続きの投稿となります。 […]
[…] #8216;samplepassword’; FLUSH PRIVILEGES; CREATE DATABASE sampledb CHARACTER SE… >>CakePHP2 のアソシエーション!モデルを連携させて複数テーブルからデータを取得する勉強します! | oki2a24 Author: […]
大変参考になります。
原作本のフォローが中途半端で ちゃんと動作しないから
途方にくれていました。
コメントありがとう存じます。お役に立てましたら幸いです。