CakePHP 2.0

今だから書こう、CakePHP 2.0の世界
===

え？！いまさら？？？と驚きかと思うだろうが、現役でCakePHP 2.0が商用環境で動作しています。
それも、その辺の個人サイトではなく、日本国民なら半数近い国民が利用したことのあるであろう大企業の、とあるサービスで。

今どきCakePHPを使う人が初心者ではないと思うので、玄人向けの記事にしようかと思いましたが、初心者全振りで行こうかと思います。

# 開発者（デベロッパー）向けの機能

`$this->Log($this->request->params)` で、Errorログに `print_r` します。

`$this->request->params` に、ルーティングされた情報が格納されています。`slug` もここに格納されています。

# ルーティング



# GET と POST リクエストのパラメーターは？

GETは、URLの末尾に付与してサーバーに値を送信する方法で、開発では手軽にデバッグできる優れた機能です。URLクエリーと言います。

POSTは、フォームなどで送信する時に使うキーと値の組み合わせの送信方法で、HTTPプロトコルのBODY部にプレーンテキストで格納されてサーバーに送信されます。

プログラミングスクールでは、GETは危険で、POSTは安心だと、講師が教えていますが、そんなことはありません。

1. GETは簡単で、POSTは面倒くさい。
1. GETはURLで結果を共有できるが、POSTはURLで結果を共有できない。

CakePHPでは、GETもPOSTも透過的に（同じ方法で）取得できます。プロパティとメソッドの2つの取得方法があります。

`$this->request->query` プロパティには、`$_GET` や `$_POST` の値がエスケープされず、そのまま格納されています。
注意点としては、キーが初期化されていない（送信されていない）場合がありますので、NULL合体演算子を併用する必要があります。（存在しないと、PHPがエラーを表示します）

```php
// プロパティ
$hoge = $this->request->query['hoge'] ?? null;
```

メソッドの場合は、そのキーの値が送信されていないとnullを返してくれます。

```php
// メソッド
$hoge = $this->request->query('hoge');
```

どちらでも機能に差はないので、簡潔に書けるメソッドをお勧めします。
デフォルト値を設定したい場合は、次のように書きます。

```php
// hogeというキーの値がnullなら、文字列'fuga'を返す
$hoge = $this->request->query('hoge') ?? 'fuga';
```

## DELETE とか PUT とか

HTTPプロトコルのメソッドには、GETやPOSTの他に、DELETE や PUT などもあります。
それらは通常のWebプログラムでは必要ないので、使われていません。（使っているところを見たことがありません）

ところが、CakePHPのルーティングでは、同じURLで異なるメソッドをサポートします。（同じURLなのに、違うメソッドへルーティングする）これは個人的に悪い仕様だと思います。

# JSONで送信されたリクエストの取得

デフォルトはオブジェクトなので連想配列に変換すると使いやすいし速い。
オブジェクトである必要性は特にないので、デフォルトは連想配列にしておいて欲しい。

```php
$json = (array)$this->request->input('json_decode');
```

# Model

CakePHPでいうModelとは、データベースヘルパーのことである。[^model]
そしてバリデーターも含んでいる。

[^model]: 英語のネイティブ話者ですら字義を理解していない例。プログラマーに最も必要な能力は国語である例。

モデル（データベースヘルパー）は、コントローラーから呼び出せる

```php
// $thisはコントローラー
// usersテーブルにアクセス
$record = $this->User->find([
  'first',
  ['conditons' => [
    'id'=>1]
  ],
]);
```

## ハマりポイント：バリデーション

CakePHPのバリデーターは、フォームから送信された値のバリデーションを前提としているので、JSONなどで送信された値のバリデーションには使わない方が良いです。（苦労する）

もし、JSONなどにも使いたいのであれば、JSONのバリデーションをするバリデーター定義と、データベースヘルパーに使うバリデーター定義は、分けた方が良いでしょう。

共用していると、JSONで制限したバリデーション定義が理由で、INSERTやUPDATEに失敗する事があります。

もしバリデーションを無視したいのであれば、第二引数に `false` を設定します。

```
$this->User->save($condition, false); // バリデーションが実行されない
```

## Insert と Update

`id` を指定すると `Update` で、 `id` が未設定だと `Insert` になる。

```php
// Update
$this->User->save([
  'id'   => '1', // idを指定しているのでUpdate
  'name' => 'taro',
]);
```

```php
// Insert
$this->User->save([
  // idが未設定なのでInsertになる
  'name' => 'hanako',
]);
```

### ハマりポイント：連続インサートができない

インスタンス化されたオブジェクトで一度 `save()` すると、そのオブジェクトは既に `id` を持つことになるので、それ以降の `save()` は、 `Update` になる。

```php
// 1回目のsave。 `id` を指定してないので、 `Insert` になる
$this->User->save([
  'name' => 'taro',
]);

// 同じインスタンスで2回目のsaveを行う。
// そのインスタンスは内部的に `id` を持つことになるので、 `Update` になる。
$this->User->save([
  // idを指定していないのにupdateになる（インスタンス内にidが保存されているため）
  'name' => 'hanako',
]);
```

#### 回避策1:saveAll()

複数のレコードを `Insert` したい場合は、 `saveAll（）` を使う。

```php
$this->User->saveAll([
  ‘User’ => [
    ['name' => 'taro'],
    ['name' => 'jiro'],
    ['name' => 'hoge'],
  ]
]);
```

#### 回避策1:create()

create()すると、idがクリアされた状態に戻せる。
ただし、デフォルト値が代入されるとのこと。
http://bashalog.c-brains.jp/13/12/12-162507.php

```
$id = $this->User->save([
  'name' => 'taro',
]);


$this->User->create();
$id = $this->User->save([
  'name' => 'jiro',
]);
```

## Select


## Delete


# レイアウト（Layout）

レイアウトを無効にする。

```
$this->layout = '';
```

# ビュー（View）

ビューを無効にする。

```
$this->autoRender = false;
```