どーも!marusukeです!
前回の記事で、blog追加ページが完成しましたが、laminas-hydratorコンポーネントを用いることでaddActionメソッドを少し改善できるので、修正していきます!
修正する箇所
修正部分は、WriteControllerのaddActionメソッドの以下の部分になります。
<?php
// namespaceやuse文は割愛します。
class WriteController extends AbstractActionController
{
private $command;
private $form;
public function __construct(PostCommandInterface $command, PostForm $form)
{
$this->command = $command;
$this->form = $form;
}
public function addAction()
{
$request = $this->getRequest();
$viewModel = new ViewModel(['form' => $this->form]);
if (! $request->isPost()) {
return $viewModel;
}
$this->form->setData($request->getPost());
if (! $this->form->isValid()) {
return $viewModel;
}
// 以下の2行を修正します。
$data = $this->form->getData()['post'];
$post = new Post($data['title'], $data['text']);
try {
$post = $this->command->insertPost($post);
} catch (\Exception $ex) {
// An exception occurred; we may want to log this later and/or
// report it to the user. For now, we'll just re-throw.
throw $ex;
}
return $this->redirect()->toRoute(
'blog/detail',
['id' => $post->getId()]
);
}
}
今のaddActionメソッドの処理の流れを簡単に説明すると、
- GET通信かPOST通信かを判別する
- GET通信の場合、追加ページのviewModelをview側に渡す
- POST通信の場合は、フォームから入力されたデータを取得する
- 3のデータを検証し、問題があれば、エラーメッセージと追加ページのviewModelをview側に渡す
- 4の検証で問題がなければ、データを生成したPostオブジェクトに渡し、DBに保存する
こちらの処理の流れの詳細は、以下の記事で説明しています。
【laminas】blogのview側を作成する!:addActionメソッドの処理ロジックについて
修正後の完成形
現状は、以下のようになっています。
//addActionメソッド内
...
// 以下の2行を修正します。
$data = $this->form->getData()['post'];
$post = new Post($data['title'], $data['text']);
...
修正後は、以下の形になります。
//addActionメソッド内
...
//修正後
$post = $this->form->getData();
...
この1行に修正するためにlaminasのコンポーネントを使用し、PostFieldsetクラスとPostFormクラスを修正します。(後ほど説明します)
なぜ修正するのか?
理由は、FormクラスとControllerクラスの分離です。簡単に説明します。
$data = $this->form->getData()['post'];
$post = new Post($data['title'], $data['text'])
この2行は、今のところ以下の流れになっています。
- 検証済みデータをPostFormオブジェクトから取得する
- Postオブジェクトを生成する
- その検証済みデータからtitleとtextを取り出し、Postオブジェクトに渡す
上記の中で、2つの問題があります。
- getDataメソッドで「post」を指定しているため、フォームの名前(PostFormクラス)が変更になるとエラーとなる
- date[‘title’]、date[‘text’]という部分で、データ内にtitleとtextがない場合エラーとなる
したがって、PostFormクラスが変更になった場合、上記のWriteControllerクラス内も変更しなければならず、とても手間です。
以下のように実装して上記2つの問題を解決することが今回の目的です。(ちなみに下記の変数$postに格納されるのは、検証済みデータの入ったPostオブジェクトです。)
$post = $this->form->getData();
上記の1行を実現するためにlaminas-hydratorコンポーネントを使って修正します。
どのように修正するのか?
修正箇所はPostFieldsetクラスとPostFormクラスを修正します。
PostFieldsetクラスの修正
以下の内容を追記します。
module/Blog/src/Form/PostFieldset.php
<?php
namespace Blog\Form;
use Laminas\Form\Fieldset;
// ① 2つのuse文を追加します
use Blog\Model\Post;
use Laminas\Hydrator\ReflectionHydrator;
class PostFieldset extends Fieldset
{
public function init()
{
// ② 以下の2行を追加します
$this->setHydrator(new ReflectionHydrator());
$this->setObject(new Post('', ''));
$this->add([
'type' => 'hidden',
'name' => 'id',
]);
$this->add([
'type' => 'text',
'name' => 'title',
'options' => [
'label' => 'Post Title',
],
]);
$this->add([
'type' => 'textarea',
'name' => 'text',
'options' => [
'label' => 'Post Text',
],
]);
}
}
追加部分の①と②を簡単に説明します。
① 追加した2つのuse文について
use Blog\Model\Post;
use Laminas\Hydrator\ReflectionHydrator;
このPostFieldsetクラスで、使用するPostクラスとReflectionHydratorクラスを読み込みます。
ちなみに今回使用するReflectionHydratorとは、
ReflectionHydratorはObjectPropertyHydratorに似ていますが、 PHPのReflection APIを使用して、任意の可視性のプロパティをハイドレートまたは抽出します。既存のプロパティにマッチする任意のデータキーがハイドレートされます。既存のプロパティは、データを抽出するために使用されます。
Components laminas-hydrator : ReflectionHydrator
ReflectionHydratorができることを簡単に説明すると、
- ハイドレート(hydrateメソッド) = 空のエンティティ(今回はPostクラス)に、データを入れ込むこと
- 抽出(extractメソッド) = データが入ったエンティティからデータを出すこと
です。
次の部分で、このReflectionHydratorクラスとPostエンティティクラスをPostFieldsetに入れ込みます。
② initメソッド内の追加した2行について
public function init()
{
// ② 以下の2行を追加します
$this->setHydrator(new ReflectionHydrator());
$this->setObject(new Post('', ''));
...
上記の2行を簡単に説明すると、
- setHydratorメソッドで、ReflectHydratorインスタンスを設定しています。
- setObjectメソッドで、Postオブジェクトを設定しています。
この上記2つを設定することで、ブラウザの入力フォームから入力されたデータは、自動でPostオブジェクトに渡される準備ができました。
次はPostFormクラスを修正していきます。
PostFormクラスの修正
以下の内容を追記します。
<?php
namespace Blog\Form;
use Laminas\Form\Form;
class PostForm extends Form
{
public function init()
{
$this->add([
'name' => 'post',
'type' => PostFieldset::class,
// 以下のoptionsを追加する
'options' => [
'use_as_base_fieldset' => true,
],
]);
$this->add([
'type' => 'submit',
'name' => 'submit',
'attributes' => [
'value' => 'Insert new Post',
],
]);
}
}
追記した’options’部分について
$this->add([
'name' => 'post',
'type' => PostFieldset::class,
// 以下のoptionsを追加する
'options' => [
'use_as_base_fieldset' => true,
],
]);
上記の’options’に’use_as_base_fieldset’をtrueで設定することで、このPostFieldsetをデフォルトで使用するベースフィールドセットとして設定します。
最後にWriteControllerのaddActionメソッドの修正
WriteControllerのaddActionメソッド内の以下の2行を
//WriteControllerのaddActionメソッド内
...
// 以下の2行を修正します。
$data = $this->form->getData()['post'];
$post = new Post($data['title'], $data['text']);
...
下記の1行に変更します。
$post = $this->form->getData();
これで、addActionメソッドの修正が完了しました!
お疲れ様でした!
次は、blog記事を編集する機能(コントローラー・ファクトリー・ルート・リポジトリ・画面)を作成していきます!
コメント