スライドショースライドショー

【CakePHP入門】関連するテーブルデータを検索する方法(contain)

こんにちは!フリーエンジニアのせきです。

CakePHPには、テーブルデータを検索する時に、関連するテーブルデータも一緒に取得する方法があります。

この記事では、

・containとは何か知りたい
・containで関連するテーブルデータを検索する方法を知りたい

という基本的な内容から、

・containで条件を指定して検索する方法を知りたい

といった応用的な内容に関しても解説していきます。

今回はそんな関連するテーブルデータを検索する方法について、わかりやすく解説します!

containとは

containとは、テーブルデータを検索する時に、関連するテーブルデータも一緒に取得することができる機能です。

ただデータが取得できるだけでなく、取得する列を指定したり、条件を指定したりすることもできます。

今回は、book_categoriesテーブルbooksテーブルの2つのテーブルを使ってcontainの動きを確認していきます。

booksテーブルはカテゴリIDをデータに持ち、そのカテゴリはbook_categoriesテーブルで管理されているものとします。

book_categoriesテーブルのテーブル定義

create table book_categories
(
    id int not null auto_increment, -- カテゴリID
    name varchar(32), -- カテゴリ名
    insert_date date, -- 登録日時
    primary key (ID)
);

book_categoriesテーブルの初期データ

idnameinsert_date
1数学2015-01-20
2物理2016-01-01
3プログラミング2017-12-20

booksテーブルのテーブル定義

create table books
(
    id int not null auto_increment, -- 本ID
    title varchar(32), -- タイトル
    book_category_id int, -- カテゴリID
     primary key (ID)
);

booksテーブルの初期データ

idtitlebook_category_id
1線形代数入門1
2力学2
3量子論2
4PHP入門3
5Javaプログラミング3

それぞれのModelを作成しておきます。

book_categoriesテーブルのModel

src\Model\Entity\BookCategory.php

<?php
namespace App\Model\Entity;

use Cake\ORM\Entity;

class BookCategory extends Entity
{
}

src\Model\Table\BookCategoriesTable.php

<?php
namespace App\Model\Table;

use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;

class BookCategoriesTable extends Table
{
    public function initialize(array $config)
    {
    }
}

booksテーブルのModel

src\Model\Entity\Book.php

<?php
namespace App\Model\Entity;

use Cake\ORM\Entity;

class Book extends Entity
{
}

src\Model\Table\BooksTable.php

<?php
namespace App\Model\Table;

use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;

class BooksTable extends Table
{
    public function initialize(array $config)
    {
        $this->belongsTo('BookCategories');
    }
}

booksテーブルとbook_categoriesテーブルは、1つのカテゴリIDに対し複数のbooksデータが存在するので、「多対1」という関係になります。

「多対1」の関連はbelongsToで定義できるので、BooksTableには「$this->belongsTo('BookCategories');」の記述が必要になります。

containの基本的な使い方

全列を取得する

booksテーブルと、それに関連するbook_categoriesテーブルのデータをcontainを使って検索します。

containは、検索するfindメソッドのオプションとして指定する方法と、クエリオブジェクト(SQLを実行するためのオブジェクト)のメソッドとして記述する方法があります。

findメソッドのオプションとして指定する場合は、BooksのControllerに以下のように記述します。

$query = $this->Books->find('all', ['contain' => 'BookCategories']);

クエリオブジェクトのメソッドとして記述する場合は、BooksのControllerに以下のように記述します。

$query = $this->Books->find('all')->contain('BookCategories');

ControllerTemplateを作成し、確認してみます。

Controllerです。

containをメソッドとして記述する方法を使っています。

src\Controller\BooksController.php

<?php
namespace App\Controller;

use App\Controller\AppController;

class BooksController extends AppController
{
    public function index()
    {
        $query = $this->Books->find('all')->contain(['BookCategories']);
        $this->set('books', $query);
    }
}

Templateです。

src\Template\Books\index.ctp

<table>
    <thead>
        <tr>
            <th>ID</th>
            <th>タイトル</th>
            <th>カテゴリID</th>
            <th>カテゴリ名</th>
            <th>カテゴリ登録日</th>
        </tr>
    </thead>
    <tbody>
        <?php foreach ($books as $book): ?>
        <tr>
            <td><?= $book->id ?></td>
            <td><?= $book->title ?></td>
            <td><?= $book->book_category->id ?></td>
            <td><?= $book->book_category->name ?></td>
            <td><?= $book->book_category->insert_date ?></td>
        </tr>
        <?php endforeach; ?>
    </tbody>
</table>

表示してみます。

http://[サーバ名]/[プロジェクト名]/books/
001

book_categoriesテーブルのすべての列が取得できています。

列を指定して取得する

containを使って他のテーブルデータを取得する時、必要な列だけ取得することもできます。

以下は、id列とname列を取得する記述方法です。

$query = $this->Books->find()->contain(['BookCategories' => function ($q) {
    return $q->select(['id', 'name']);
}]);

containの引数に渡す配列に「'テーブル名' => function($q){}」のように関数を指定すると、$qでcontain先のテーブルのクエリオブジェクトを使うことができます

そのため、「$q->select(['id', 'name'])」でid列とname列が取得されます。

BooksControllerを以下のように修正し、表示してみます。

<?php
namespace App\Controller;

use App\Controller\AppController;

class BooksController extends AppController
{
    public function index()
    {
        $query = $this->Books->find()->contain(['BookCategories' => function ($q) {
            return $q->select(['id', 'name']);
        }]);
        $this->set('books', $query);
    }
}

002

カテゴリIDとカテゴリ名は取得しているので表示され、カテゴリ登録日は表示されていません。

containの応用的な使い方

条件を指定して検索する

containを使って取得した他のテーブルデータを、元のテーブルの検索条件に指定することができます

カテゴリ登録日が'2016-01-01'であるBooksテーブルのデータを取得します。

<?php
namespace App\Controller;

use App\Controller\AppController;

class BooksController extends AppController
{
    public function index()
    {
        $query = $this->Books->find()->contain('BookCategories')->where(['insert_date' => '2016-01-01']);
        $this->set('books', $query);
    }
}

whereメソッドでBookCategoriesテーブルの'insert_date'を使用することができます。

表示するとinsert_dateが'2016-01-01'であるデータが表示されます。

003

'id'のように2つのテーブルで同じカラム名がある場合は、「テーブル名.カラム名」の形で指定してください。

以下は、BookCategoriesのidが3のデータを取得します。

$query = $this->Books->find()->contain('BookCategories')->where(['BookCategories.id' => '3']);

BookCategoriesのid列を「BookCategories.id」と記述しています。

表示するとBookCategoriesのidが3のデータが表示されます。

004

まとめ

今回は関連するテーブルデータを検索する方法について解説しました。

複数のテーブルを使用するシステム開発では、関連データの取得は必須です。

関連するテーブルデータを検索する方法を忘れてしまったら、この記事を思い出して下さい!

LINEで送る
Pocket

無料でSEからWebエンジニアへ転職しませんか?



侍エンジニア塾では、完全未経験の方から現在SEだけどプログラミングはやっていないという経験者まで、幅広い方々の人生を好転させるプログラミング指導を行ってきました。SEの方とお話していくなかで、

  • システムエンジニアという職業だけどコードが書けない
  • 事務作業が多くスキルがないため将来が不安
  • スクールに通うと完全未経験者と同じスタートになるからレベルが合わない
という、すでに知識があるSEならではのお悩みがあることに気づきました。そんな方におすすめなのが、弊社の「転職コース 」です。

弊社では、マンツーマンでレッスンを行いますので、現在お持ちの知識レベルからカリキュラムを作成いたします。さらにこちらの転職コースは無料で受講を始められて転職成功でそのまま卒業できるというとてもお得なコースとなっています。

既に知識のあるSEといっても転職は年齢が若いほど受かりやすいため、まずは無料体験レッスンで今の現状や理想の働き方について一緒に考えていきましょう。

まずは無料体験レッスンを予約する

書いた人

せき

せき

フリーランスでWebシステム開発やゲーム開発をしています。
読者の方にプログラミングの面白さをお伝えしたいです。

おすすめコンテンツ

あなたにぴったりなプログラミング学習プランを無料で診断!

プログラミング学習の効率を劇的に上げる学習メソッドを解説