CakePHP 2.x ちょっとしたコーディングTips

よく使うコーディング方法などを備忘録的に書いていきます。

# **可読性向上?**
## **find()の第二引数にcompact()を使う**

例文などで以下のような書き方をよく見ますが
find()の第二引数に渡すパラメータは、ゴチャゴチャした多次元配列になりがちです。

```php
$articles = $this->Article->find('all', array(
    'conditions' => array(
        'Article.status !=' => 'pending',
        'Article.date >='   => '2016-02-01',
        'Article.date <='   => '2016-02-28',
    ),
    'fields' => array(
        'Article.id',
        'Article.title',
        'Article.date',
    ),
    'order' => array('Article.date' => 'desc'),
    'limit' => 10,
));
```

好みの問題ですが、これだと少し可読性が悪い気がするので
(僕は関数の引数に配列をずらずら書くのが好きではないため)
以下のように各パラメータを一旦変数に代入してから、PHP標準関数のcompact()を使ってfind()に渡します。

```php
$conditions = array(
    'Article.status !=' => 'pending',
    'Article.date >='   => '2016-02-01',
    'Article.date <='   => '2016-02-28',
);
$fields = array(
    'Article.id',
    'Article.title',
    'Article.date',
);
$order = array('Article.date' => 'asc');
$limit = 10;
$articles = $this->Article->find('all', compact('conditions', 'fields', 'order', 'limit'));
```

※変数名がそのまま配列のキーになるので、find()のパラメータで指定可能な変数名を付けます。

[compact関数]
http://php.net/manual/ja/function.compact.php
[findに指定可能なパラメータ]
http://book.cakephp.org/2.0/ja/models/retrieving-your-data.html

突っ込みどころはありそうですが、それぞれのパラメータが独立して見分けやすく、こちらの方がスッキリして好きです。


# **Hashクラスでarray地獄を脱出**

CakePHP2.xのfind('all')では、モデル名を含む連想配列を返します。

例) 結果をprint_rで出力したもの

```
Array
(
    [0] => Array
        (
            [Article] => Array
                (
                    [id] => 385
                    [title] => 円急騰 企業業績や株価に逆風写真
                    [date] => 2016-02-11 22:23:00
                )

        )
    [1] => Array
        (
            [Article] => Array
                (
                    [id] => 526
                    [title] => 重力波を初観測 ノーベル賞級
                    [date] => 2016-02-12 01:07:00
                )

        )
    [2] => Array
        (
            [Article] => Array
                (
                    [id] => 692
                    [title] => 大谷を絶賛「5億ドルの価値」
                    [date] => 2016-02-12 05:49:00
                )

        )
)
```

この配列をforeachで回して自分が望む形式に加工したりしますが
CakePHP2.xにはHashという配列を扱うユーティリティクラスがあるので
これを使うと簡単に配列操作できたり、コードがスッキリして幸せになれます。

[Hashクラス]
http://book.cakephp.org/2.0/ja/core-utility-libraries/hash.html


## **Hash::extractで必要なデータだけ取り出す**

```php
// findでデータ取得 (上記例の配列が返る)
$articles = $this->Article->find('all', compact('conditions'));

// idだけのリストを作成したい場合
$id_list = Hash::extract($articles, '{n}.Article.id');

print_r($id_list);
/*
Array
(
    [0] => 385
    [1] => 526
    [2] => 692
)
*/

// titleだけのリストを作成したい場合
$title_list = Hash::extract($articles, '{n}.Article.title');

print_r($title_list);
/*
Array
(
    [0] => 円急騰 企業業績や株価に逆風写真
    [1] => 重力波を初観測 ノーベル賞級
    [2] => 大谷を絶賛「5億ドルの価値」
)
*/

// 1行にまとめるとスッキリ
$id_list = Hash::extract($this->Article->find('all', compact('conditions')), '{n}.Article.id');
```


## **Hash::combineで連想配列を作る**

```php
// findでデータ取得 (上記例の配列が返る)
$articles = $this->Article->find('all', compact('conditions'));

// idとtitleの連想配列を作成したい場合
$id_title = Hash::combine($articles, '{n}.Article.id', '{n}.Article.title');

print_r($id_title);
/*
Array
(
    [385] => 円急騰 企業業績や株価に逆風写真
    [526] => 重力波を初観測 ノーベル賞級
    [692] => 大谷を絶賛「5億ドルの価値」
)
*/

// 1行にまとめるとスッキリ
$id_title = Hash::combine($this->Article->find('all', compact('conditions')), '{n}.Article.id', '{n}.Article.title');
```


## **結果からモデル名を除去する**

```php
// findでデータ取得 (上記例の配列が返る)
$articles = $this->Article->find('all', compact('conditions'));

// モデル名を除去したい場合
$ext = Hash::extract($articles, '{n}.Article');

print_r($ext);
/*
Array
(
    [0] => Array
        (
            [id] => 385
            [title] => 円急騰 企業業績や株価に逆風写真
            [date] => 2016-02-11 22:23:00
        )
    [1] => Array
        (
            [id] => 526
            [title] => 重力波を初観測 ノーベル賞級
            [date] => 2016-02-12 01:07:00
        )
    [2] => Array
        (
            [id] => 692
            [title] => 大谷を絶賛「5億ドルの価値」
            [date] => 2016-02-12 05:49:00
        )
)
*/
```

AppModelのafterFind()に書いておいても良いかも。