CakePHP リダイレクトした先でのバリデーションメッセージの表示

PHP 5.5.31
CakePHP 2.8.0

CakePHPでバリデーションメッセージを表示する方法をまとめます。この方法はCakePHPにおいてスタンダードでないバリデーション表示方法です。
今回は例として、アカウント作成に失敗したらバリデーションメッセージを出力します。
ページのリダイレクトには`redirect()`を使用します。
ユーザ作成の入力項目は、名前、メールアドレス、パスワードとします。
ユーザ編集の入力項目は、名前、メールアドレスとします。
バリデーションの内容は、名前入力必須、メールアドレス必須、有効なメールアドレスか確認、メールアドレスの重複確認、パスワードの文字数6文字以上とします。

参考サイトは以下
http://skgckj.hateblo.jp/entry/2014/02/09/005111

# 例で使用するコントローラー名など
## 新規作成画面、詳細画面
  |  名前
--- | :-:
コントローラー | HogesController.php
追加画面のアクション | create()
追加処理のアクション | add() <br> 成功時：create()にリダイレクト <br> 失敗時：create()にリダイレクトしてエラー表示
詳細画面のアクション | show()
編集処理のアクション | update() <br> 成功時：show()にリダイレクト <br> 失敗時：show()にリダイレクトしてエラー表示
アカウント新規作成画面 | create.ctp
アカウント編集画面 | show.ctp
モデル | Hoge.php

## Hogeモデルのカラム

  |  カラム名
--- | :-:
名前 | name
メールアドレス | mail
パスワード | password

# バリデーション
`Hoge.php`にバリデーション内容を書く。
公式ドキュメントを参考に記述した。
http://book.cakephp.org/2.0/ja/models/data-validation.html

```Hoge.php
class Hoge extends AppModel {

	public $validate = [
		'name' => [
			[
				'rule' => 'notBlank',
				'message' => '名前は必須入力の項目です。',
			],
		],
		'mail' => [
			[
				'rule' => 'notBlank',
				'message' => 'メールアドレスは必須入力の項目です。',
			],
			[
				'rule' => ['email', true],
				'message' => '有効なメールアドレスを入力してください。',
			],
			[
				'rule' => 'isUnique',
				'message' => '入力されたメールアドレスは既に登録されています。',
			],
		],
		'password' => [
			[
				'rule' => ['minLength', 6],
				'message' => 'パスワードは6文字以上です。',
			],
		],
	];

}
```

# Sessionにログを書き込む処理
リダイレクトで破棄されるバリデーションメッセージを一時的に保存する。
`HogesController.php`に記述する。

```HogesController.php
class HogesController extends Controller {

	public function beforeFilter() {
		parent::beforeFilter();
		if($this->Session->read('errors')) {
			foreach($this->Session->read('errors') as $model => $errors) {
				$this->loadModel($model);
				$this->$model->validationErrors = $errors;
			}
			$this->Session->delete('errors');
		}
	}

}
```

# アカウント新規作成画面
## create()アクション
今回は引き渡すデータが特に無いので記述は特に無し。

```HogesController.php
public function create() {

}
```

## ビュー(create.ctp)
```create.ctp
<?=$this->Form->create('Hoge', ['url' => ['action' => 'add']])?>
	<?=$this->Form->input('name', ['placeholder' => 'ユーザ名を入力してください', 'label' => 'ユーザ名'])?>
	<?=$this->Form->input('password', ['placeholder' => 'パスワードを入力してください', 'label' => 'パスワード'])?>
	<?=$this->Form->input('mail', ['placeholder' => 'メールアドレスを入力してください', 'label' => 'メールアドレス'])?>
	<?=$this->Form->submit('登録', ['onclick' => 'return confirm("登録してよろしいですか？");'])?>
<?=$this->Form->end()?>
```

## 表示例
![スクリーンショット 2016-04-28 17.15.17.png](https://qiita-image-store.s3.amazonaws.com/0/42625/27b9b05f-56cd-02b0-31b1-21247aef0fc1.png)


# アカウント新規作成処理
## コントローラー(HogesController.php)

```HogesController.php
public function add() {

	$user = $this->request->data('Hoge');

	if ($this->Hoge->save($user) === false) {
		// セッションにバリデーションメッセージを保存する
		$this->Session->write('errors.Hoge', $this->Hoge->validationErrors);
		return $this->redirect($this->referer());
	}

	$this->setFlashInfo('ユーザーを新規登録しました');
	// 処理が成功した時にリダイレクトするアクション
	return $this->redirect(['action' => 'create']);

}
```

# バリデーションメッセージの表示例
メールアドレスの形式が間違ってる場合
![スクリーンショット 2016-04-28 17.19.45.png](https://qiita-image-store.s3.amazonaws.com/0/42625/96e53198-6302-0ece-c2b5-910400d83238.png)

パスワードの文字数が少ない場合
![スクリーンショット 2016-04-28 17.20.59.png](https://qiita-image-store.s3.amazonaws.com/0/42625/386f1739-5d50-575e-5c6d-314d587ca4d4.png)

# アカウント詳細画面(編集)
## 編集するユーザの例
カラム  | 値
--- | :-:
name | HogeFuga
mail | hoge@gmail.com
## show()アクション
IDで登録されたユーザの詳細画面を見られるものとする。

```HogesController.php
/**
 * 管理ユーザー編集画面
 */
public function show($id) {
	// 選択されたユーザ情報
	$user = $this->Hoge->findById($id)['Hoge'];
	// ユーザーが見つからなかった時のエラー処理
	if (empty($user)) {
		if (empty($this->referer())) {
			return $this->redirect('/');
		}
		return $this->redirect($this->refere());
	}

	$this->set([
		'name' => $user['name'],
		'mail' => $user['mail'],
	]);
}
```

## ビュー(show.ctp)
```HogesController.php
<?=$this->Form->create('Hoge', ['url' => ['action' => 'update', $id]])?>

	<?=$this->Form->input('name', ['default' => $name, 'label' => 'ユーザ名'])?>
	<?=$this->Form->input('mail', ['default' => $mail, 'label' => 'メールアドレス'])?>
	<?=$this->Form->submit('更新', ['onclick' => 'return confirm("変更してよろしいですか？");'])?>

<?=$this->Form->end()?>
```

## 表示例
![スクリーンショット 2016-04-29 11.47.14.png](https://qiita-image-store.s3.amazonaws.com/0/42625/141a3e88-302a-2b05-f5a3-4e649549c49a.png)

# アカウント編集処理
```HogesController.php
public function update($id) {

	$user = $this->request->data('Hoge');
	$user['id'] = $id;

	if ($this->Hoge->save($user) === false) {
		$this->setFlashWarning('ユーザーの編集に失敗しました');
		// 処理が失敗した時にリダイレクトするアクション
		return $this->redirect($this->referer());
	}
	$this->setFlashInfo('ユーザーを編集しました');
	// 処理が成功した時にリダイレクトするアクション
	return $this->redirect(['action' => 'show']);

}
```

# バリデーションメッセージの表示例
メールアドレスの形式が間違っている場合
![スクリーンショット 2016-05-02 21.48.49.png](https://qiita-image-store.s3.amazonaws.com/0/42625/f2affbae-cda5-299b-daa6-691b459d0cd6.png)

# メリット
[CakePHPのスタンダードなバリデーション方法を使った場合](http://qiita.com/qiita_taro/items/39d3cc554cafca530d8c)は、失敗時に`render()`などを使ってビューファイルを指定するため、描画するビューファイルに合わせてコントローラーから値を渡さなければならないことが多いが、リダイレクトの場合はそれを考慮する必要がない。

# デメリット
バリデーションメッセージやフォームの入力内容をバリデーション失敗時に毎回セッションなどにセットする必要がある。（なお読み込みは`AppController`の`beforeFilter()`に1度書くだけ）
CakePHPにおいて、スタンダードなやり方ではないため、複数人で開発するときや引き継ぎをするときはやり方を伝える必要がある。