忍者ブログ
[PR]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。



2017/05/01 15:14 |
CakePHP-03:CakePHPで複数のテーブルを結合

http://yuubiseiharukana.blog.shinobi.jp/Entry/158/の続き?

CakePHPの基本は、ひとつのコントローラにひとつのテーブルです。
つまり、その状態ではリレーショナルをまともに扱うことができません。
複数のテーブルを扱いたい場合、実現には幾つかの手段があります。

単純に結合で話が済む場合は、モデルを記述することで解決されます。

とりあえず結合を使うようなテーブルを作成。
 

CREATE TABLE `books` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(128) NOT NULL,
 `author_id` int(8) NOT NULL DEFAULT '1',
 `publisher_id` int(8) NOT NULL,
 `price` int(10) DEFAULT '1',
 `isbn` varchar(16) DEFAULT NULL,
 `date` date DEFAULT NULL,
 `created` datetime NOT NULL,
 `modified` datetime DEFAULT NULL,
 PRIMARY KEY (`id`),
 KEY `index_name` (`name`),
 KEY `author_id` (`author_id`),
 KEY `publisher_id` (`publisher_id`),
 CONSTRAINT `books_ibfk_1` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`),
 CONSTRAINT `books_ibfk_2` FOREIGN KEY (`publisher_id`) REFERENCES `publishers` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

CREATE TABLE `authors` (
 `id` int(8) NOT NULL AUTO_INCREMENT,
 `name` varchar(128) NOT NULL,
 `comment` varchar(128) NOT NULL,
 `created` datetime NOT NULL,
 `modified` datetime DEFAULT NULL,
 PRIMARY KEY (`id`),
 KEY `index_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

CREATE TABLE `publishers` (
 `id` int(8) NOT NULL AUTO_INCREMENT,
 `name` varchar(32) NOT NULL,
 `comment` text NOT NULL,
 `created` datetime NOT NULL,
 `modified` datetime DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

CREATE TABLE `books_supplementations` (
 `id` int(8) NOT NULL AUTO_INCREMENT,
 `book_id` int(8) NOT NULL,
 `supplementation` text NOT NULL,
 `created` datetime NOT NULL,
 `modified` datetime NOT NULL,
 PRIMARY KEY (`id`),
 KEY `book_id` (`book_id`),
 CONSTRAINT `books_supplementations_ibfk_1`
  FOREIGN KEY (`book_id`) REFERENCES `books` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8


とりあえず適当に作っただけなので各テーブルにはあまり意味はありません。
各テーブルに何件か適当にデータを入れておきます。

モデルに、他のモデルとの関係を記述していきます。
モデルとして読み込もうとしているBooksモデルの記述は必要ですが、そこからリンクされているAuthorsモデルやBooks_supplementationsモデルはとりあえず記述する必要はありません。

app/models/book.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
    
    class Book extends AppModel {
        
        //自分の名前
            var $name = 'Book';
        
        //books.author_idはauthors.idに外部キー
        //books.publisher_idはpublishers.idに外部キー
        //books.idはbooks_supplementations.book_idから外部キー
        //といった関係を記述しておくとfind等で自動的に結合する
            var $belongsTo = array(
                 'Author' =>array(
                    'className' => 'Author',
                    'foreignKey'=> 'author_id' 
                )
                ,'Publisher' =>array(
                    'className' => 'Publisher',
                    'foreignKey'=> 'publisher_id' 
                )
            );
            var $hasMany = array(
                 'Books_supplementation' =>
                    array(
                        'className' => 'Books_supplementation',
                        'foreignKey'=> 'book_id' 
                    )
            );
    }

記述がめんどくさいんですが、簡単に言うとhasは相手側テーブルから自分に対して外部キーが張ってある、belongsToは自分から相手側に外部キーが張ってあるということです。
Bookモデルの場合、authorsテーブルとpublishersテーブルに対して外部キーが張ってあり、books_supplementationsテーブルから外部キーを張られています。

その後コントローラ内で
$this->Book->find(array('Book.id <>'=>'2'));
などとすると、Bookモデル内の結合条件を勝手に読み取って勝手にJOINなんかを付け加えてSELECTしてきます。

結果のSQLはこんな感じに。
見事に表示できま…一件しか出てこない。

SELECT (略) FROM `books` AS `Book`
 LEFT JOIN `authors` AS `Author` ON (`Book`.`author_id` = `Author`.`id`)
 LEFT JOIN `publishers` AS `Publisher` ON (`Book`.`publisher_id` = `Publisher`.`id`)
  WHERE `Book`.`id` <> 2
   LIMIT 1


そのLIMIT 1は何処から出てきたんだ?

CakePHPの記事一覧


2009/10/30追記

findは結果セットを1件だけ取得するメソッドで、全件取得したい場合はfindAllを使用します。
詳細は次の記事を参照。
コメントでの指摘ありがとうございます。
PR


2009/10/05 20:01 | Comments(2) | TrackBack(1) | PHP

トラックバック

トラックバックURL:
前回のでbooksテーブルと直接繋がっているテーブルは結合できましたが、更に連鎖した先のテーブルを結合することも出来ます。 とりあえず前回のテーブル群にレーベルテーブル追加。   CREATE TABLE `labels` (  `id` int(8) NOT NULL AUTO_INCREMENT,  `publisher_id` int(8) N...
弱小PHPerの憂鬱 | 2009/10/30 19:19

コメント

$this->Book->find(array('Book.id <>'=>'2'));

$this->Book->findAll(array('Book.id <>'=>'2'));
posted by 名無しさん必死だな URL at 2009/10/14 15:24 [ コメントを修正する ]
>>$this->Book->findAll(array('Book.id <>'=>'2'));

これのせいだったんだね。さんくす。
そのうち修正しておきます。
posted by NurseAngel at 2009/10/16 22:29 [ コメントを修正する ]

コメントを投稿する






Vodafone絵文字 i-mode絵文字 Ezweb絵文字 (絵文字)



<<ZF-04:Zend_Feed | HOME | ZF-03:Zend_Db_Select>>
忍者ブログ[PR]