22
29

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

CakePHP 1.x/2.x でJOINを超簡単に書く方法

Last updated at Posted at 2017-02-02

読者対象

CakePHP 3.x や Laravel 5.x に移行したいと思いつつもなかなか脱却できずに古代のクソフレームワークを用いたプロジェクトの保守を強要されている哀れな開発者

CakePHPマニュアルに書いてある方法

クッソ冗長な配列の定義を要求される。なんでここフレームワークで吸収してくれないの?

$options['joins'] = array(
    array('table' => 'books_tags',
        'alias' => 'BooksTag',
        'type' => 'inner',
        'conditions' => array(
            'Book.id = BooksTag.book_id'
        )
    ),
    array('table' => 'tags',
        'alias' => 'Tag',
        'type' => 'inner',
        'conditions' => array(
            'BooksTag.tag_id = Tag.id'
        )
    )
);

$options['conditions'] = array(
    'Tag.tag' => 'Novel'
);

$books = $Book->find('all', $options);

スクリーンショット 2017-02-02 16.48.56.png

何がモダンじゃこの野郎。

オレオレ実装

こんなの毎回書いてられるわけがないので,全てのモデルの基底クラスであるAppModelに拡張メソッドを実装する。

<?php

App::uses('Model', 'Model');
App::uses('Inflector', 'Utility');

class AppModel extends Model
{
    /**
     * INNER JOIN 補助
     *
     * @author @mpyw
     * @param  string $targetModelName   JOINで取ってくるモデル
     * @param  array  $conditions        JOIN条件
     * @return array
     */
    public function belongsInnerJoin($targetModelName)
    {
        $foreignKey = Inflector::underscore($targetModelName) . '_id';
        return $this->join('INNER', $targetModelName, [
            "$this->name.$foreignKey = $targetModelName.id",
        ]);
    }
    public function hasInnerJoin($targetModelName)
    {
        $foreignKey = Inflector::underscore($this->name) . '_id';
        return $this->join('INNER', $targetModelName, [
            "$this->name.id = $targetModelName.$foreignKey",
        ]);
    }
    public function innerJoin($targetModelName, array $conditions)
    {
        return $this->join('INNER', $targetModelName, $conditions);
    }

    /**
     * LEFT JOIN 補助
     *
     * @author @mpyw
     * @param  string $targetModelName   JOINで取ってくるモデル
     * @param  array  $conditions        JOIN条件
     * @return array
     */
    public function belongsLeftJoin($targetModelName)
    {
        $foreignKey = Inflector::underscore($targetModelName) . '_id';
        return $this->join('LEFT', $targetModelName, [
            "$this->name.$foreignKey = $targetModelName.id",
        ]);
    }
    public function hasLeftJoin($targetModelName)
    {
        $foreignKey = Inflector::underscore($this->name) . '_id';
        return $this->join('LEFT', $targetModelName, [
            "$this->name.id = $targetModelName.$foreignKey",
        ]);
    }
    public function leftJoin($targetModelName, array $conditions)
    {
        return $this->join('LEFT', $targetModelName, $conditions);
    }

    /**
     * JOIN 補助
     *
     * @author @mpyw
     * @param  string $type              JOINの種類
     * @param  string $targetModelName   JOINで取ってくるモデル
     * @param  array  $conditions        JOIN条件
     * @return array
     */
    public function join($type, $targetModelName, array $conditions)
    {
        return [
            'type' => $type,
            'table' => Inflector::tableize($targetModelName),
            'alias' => $targetModelName,
            'conditions' => $conditions,
        ];
    }
}

これを使うとさっきの例はこのように書ける。

$books = $Book->find('all', [
    'joins' => [
        $Book->hasInnerJoin('BooksTag'),
        $Book->belongsInnerJoin('Tag'),
    ],
    'conditions' => [
        'Tag.tag' => 'Novel',
    ],
]);

これでちょっとでも保守が楽になりますように…

22
29
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
29

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?