ギジュログ

FlashとかPHPとかiOSとかJavaとか。関東でフリーランスやってる人の気まぐれな技術録。

CakePHP3 もくもく会 #2 に参加してきました 続き

遅くなりましたが、前回の続きです。

前回は投稿の一覧が表示できるようになったところまでをやりました。

投稿の詳細画面を作る

一覧のタイトルをクリックしたらその詳細が確認できるようにします。まずは一覧のタイトルにリンクをつけます。action は view とします。

タイトルを echo してた箇所を下記のように変更します。

-		<td><?php echo $post->title; ?></td>
+		<td><?php echo $this->Html->link($post->title, array('controller' => 'posts', 'action' => 'view', $post->id)); ?></td>

そして、詳細ページのビューを作ります。

<!-- App/Template/Posts/view.ctp -->
<h1><?php echo h($post->title); ?></h1>
<p><small>Created: <?php echo $post->created->format('Y-m-d H:i:s'); ?></small></p>
<p><?php echo h($post->body); ?></p>

コントローラーに view アクションを追加します。このとき、ビューで Html ヘルパーを利用したので、ヘルパーを追加しておきます。このへんの作法は 2 と変わっていません。

// App/Controller/PostsController.php
<?php
// 中略
	
	// ヘルパー追加
	public $helpers = array('Html');

// 中略

	public function view($id = null) {
		if (!$id) {
			throw new NotFoundException(__('Invalid post'));
		}

		$posts = TableRegistry::get('Posts');
		$post = $posts->get($id);
		if (!$id) {
			throw new NotFoundException(__('Invalid post'));
		}
		$this->set('post', $post);
	}

ここまでは前回やった内容とあまり変わりません。

新規エントリーを投稿する

次はエントリーを追加できるようにします。
まずは上記の流れでコントローラー/ビューを作ってしまいます。action は add とします。

ビュー

<!-- App/Template/Posts/add.ctp -->
<h1>Add Post</h1>
<?php
echo $this->Form->create('Post');
echo $this->Form->input('Post.title');
echo $this->Form->input('Post.body', array('rows' => '3'));
echo $this->Form->submit('Save Post');
echo $this->Form->end();
?>

Form ヘルパーは若干挙動が変わっています。 create すると以下のインプットのname属性にはデフォルトで data[モデル名] みたいなプレフィックスが付いていましたが、モデル名はつかなくなっています。Post に関するものは $request->data['Post'] みたいな感じで取れると嬉しいので、とりあえず各要素名の頭に Post. をつけておきました。

それからコントローラーに add アクションを追加します。

// App/Controller/PostsController.php
<?php
// 中略

	// Form 使ったので追加
	public $helpers = array('Html', 'Form');
	// Session コンポーネントを使うので追加
	public $components = array('Session');
	
// 中略

	public function add() {
		if ($this->request->is('post')) {
			$posts = TableRegistry::get('Posts');
			$post = new Post($this->request->data('Post'));
			if ($posts->save($post)) {
				$this->Session->setFlash(__('Your post has been updated.'));
				return $this->redirect(array('action' => 'index'));
			}
			$message = __('Unable to update your post.');
			$this->Session->setFlash($message);
		}
	}

コンポーネントまわりの使い方もとくに変わりはありません。デフォルトのレイアウトにはflashメッセージがあればそれを表示する、みたいな内容が組み込まれているので、Session->setFlash にメッセージをいれると自動的に表示されて便利です。

次はバリデーションを追加します。バリデーションは Table クラスの中で行います。

// App/Model/Table/PostsTable.php
<?php
// 中略

// Validator というクラスを利用します
use Cake\Validation\Validator;

// 中略
	public function validationDefault(Validator $validator) {
		$validator
			->add('title', 'notEmpty', [
				'rule' => 'notEmpty',
				'message' => 'You need to provide a title',
			])
			->add('body', 'notEmpty', [
				'rule' => 'notEmpty',
				'message' => 'A body is required',
			]);
		return $validator;
	}

2系ではモデルのプロパティとして書いていましたが、3系ではコールバックメソッドでバリデーションするようです。コールバックメソッドは validationXXX という形式になります。デフォルトでは validationDefault というコールバックになりますが、保存のときだけ動作して欲しい場合は validationUpdate というコールバックになります。
Table Objects — CakePHP Cookbook 3.x documentation このへんに書いてありました。

これでバリデーションがかかるようになりました。一応補足しておくと、controller で Table->validate() を行っていないのは、デフォルトで save メソッドにてバリデーションが行われていたからです。バリデーションせずに保存するには第二引数に配列で array('validation' => false) を渡すことで可能です。また、設定したエラーメッセージを取得するには、$posts->errors() でメッセージの配列が受け取ることができます。


とりあえず、ここまでがもくもくした内容でした。