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

# 読者対象

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

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

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

```php
$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](https://qiita-image-store.s3.amazonaws.com/0/25060/7874a93e-725a-45be-071c-27e92457c87a.png)

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

# オレオレ実装

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

```php
<?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,
        ];
    }
}
```

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

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

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