PHP

CakePHP2で複数のテーブルをJoinしてデータを取得・更新する際の基本

美しくないjoin

Cookbookより:
テーブルを結合するには、Model::find() の 「モダン」 な構文を使います。

CakePHP2さんの主張するモダン

$options['joins'] = array(
    array('table' => 'channels',
        'alias' => 'Channel',
        'type' => 'LEFT',
        'conditions' => array(
            'Channel.id = Item.channel_id',
        )
    )
);

$Item->find('all', $options);

URL:
https://book.cakephp.org/2.0/ja/models/associations-linking-models-together.html#joining-tables
SQLに恨みでもあるのかもしれないけど、SQLのjoinほうがずっと美しいと思います。

調べてみるとjoinしなくてもテーブルを結合できるみたいなので、そのの方法を記載します。関係ないですがCakeをCookするってどこか和みます。

joinを使わない方法

ベースにする処理
Cookbookの入門プログラム
URL:https://book.cakephp.org/2.0/ja/getting-started.html

ブログの記事(Post)を登録するプログラムに、執筆者(User)を追加します。
執筆者(User)とブログの記事(Post)は1対Nの関係です。

テーブル定義

usersテーブル作成

SET NAMES utf8;
SET time_zone = '+00:00';
SET foreign_key_checks = 0;
SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO';

CREATE TABLE `users` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `users` (`id`, `username`, `password`, `created`, `modified`) VALUES
(1, 'user1',    'pass', '2018-05-09 19:19:07',  '2018-05-09 19:19:07'),
(2, 'user2',    'pass2',    '2018-05-09 19:19:26',  '2018-05-09 19:19:26');

postsテーブル変更
テーブルusersの主キーidを外部制約にもつ項目、user_idを追加します。

ALTER TABLE `posts`
ADD `user_id` int(10) unsigned NULL AFTER `id`,
ADD FOREIGN KEY (`user_id`) REFERENCES `users` (`id`);

Model

Post.php
PostにbelongsToを追加します。

<?php
  class Post extends AppModel {
    public $belongsTo = 'User';
  }
?>

User.php
UserにhasManyを設定します。

<?php
  class User extends AppModel {
    public $hasMany = array(
        'Post' => array(
            'className' => 'Post'
        )
    );
  }
?>

View

edit.php
変更用のviewにuser_idの項目を追加します。

<!-- File: /app/View/Posts/edit.ctp -->

<h1>Edit Post</h1>
<?php
echo $this->Form->create('Post');

//add start
echo $this->Form->input('user_id', array('label' => 'UserId'));
//add end

echo $this->Form->input('title');
echo $this->Form->input('body', array('rows' => '3'));
echo $this->Form->input('id', array('type' => 'hidden'));
echo $this->Form->end('Save Post');
?>

Controller

function editにuser_idの取得処理を追加します。

    public function edit($id = null) {
      if (!$id) {
          throw new NotFoundException(__('Invalid post'));
      }

      $post = $this->Post->findById($id);

      //add start
      //Userテーブルからのデータ取得処理
      $this->set('users', $this->Post->User->find('list'));
      //add end

      

変更後の画面

cake2.JPG

参考にした記事

Qiita
CakePHP 1.x/2.x でJOINを超簡単に書く方法
URL:https://qiita.com/mpyw/items/a0e7b99a8582195f0108

Cookbook

belongsTo や hasOne 関係を使うケースで select 項目を生成したい場合、
 Users コントローラーに以下のコードを追加します
(User は Group に belongsTo していると仮定しています):

URL:https://book.cakephp.org/2.0/ja/core-libraries/helpers/form.html#automagic-form-elements

追記

編集画面でユーザーidに紐づく値(名前)を表示する場合には、Controllerの以下の部分を変更します。

    public function edit($id = null) {
      if (!$id) {
          throw new NotFoundException(__('Invalid post'));
      }

      $post = $this->Post->findById($id);

      //add start
      //Userテーブルからのデータ取得処理
      //idを表示する
      //$this->set('users', $this->Post->User->find('list'));
      //idに紐づく値(名前)を表示する
      $this->set('users', $this->Post->User->find('list',array('fields' => array('User.username'))));
      //add end

      

変更結果

change.JPG

参考にした記事

Cookbook
URL:https://book.cakephp.org/2.0/ja/models/retrieving-your-data.html#find-list