どーも!marusukeです!
前回の記事で、WriteControllerの雛形を作成したので、このコントローラーをインスタンス化するためのファクトリー(WriteControllerFactory.php)と、ルートを作成していきます!
作成の流れとしては、
- Formクラスを作成する。
- コントローラーを作る。
- コントローラーのインスタンス化のためのFactoryとルートを作る。<= 現在ここです!
- モデル(repositoryクラス)を作成する。
- view側を作る。
WriteControllerFactoryを作成する!
WriteControllerクラスをインスタンス化するための、WriteControllerFactoryを作成します。
以下のようになります。
module/Blog/src/Factory/WriteControllerFactory.php
<?php
// ①
namespace Blog\Factory;
// ②
use Blog\Controller\WriteController;
use Blog\Form\PostForm;
use Blog\Model\PostCommandInterface;
use Interop\Container\ContainerInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;
// ③
class WriteControllerFactory implements FactoryInterface
{
/**
* @param ContainerInterface $container
* @param string $requestedName
* @param null|array $options
* @return WriteController
*/
// ④
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$formManager = $container->get('FormElementManager');
return new WriteController(
$container->get(PostCommandInterface::class),
$formManager->get(PostForm::class)
);
}
}
上から簡単に説明していきます。
// ①「namespace Blog\Factory;」について
namespaceをBlogディレクトリ内のFactoryディレクトリを指定しています。今後Factoryクラスを追加する場合は、このFactoryディレクトリ内に追加していきます。
// ② 各use文について
use Blog\Controller\WriteController;
use Blog\Form\PostForm;
use Blog\Model\PostCommandInterface;
use Interop\Container\ContainerInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;
ここにこのWriteControllerFactoryクラスで使用するその他のクラスを読み込んでいきます。
// ③「class WriteControllerFactory implements FactoryInterface」について
FactoryInterfaceをimplementsし、WriteControllerFactoryクラスを定義しています。
ちなみにFactoryInterface.phpは、
vendor/laminas/laminas-servicemanager/src/Factory/FactoryInterface.phpにあり、
以下のような内容になっています。
<?php
declare(strict_types=1);
namespace Laminas\ServiceManager\Factory;
use Interop\Container\ContainerInterface;
use Interop\Container\Exception\ContainerException;
use Laminas\ServiceManager\Exception\ServiceNotCreatedException;
use Laminas\ServiceManager\Exception\ServiceNotFoundException;
/**
* Interface for a factory
*
* A factory is an callable object that is able to create an object. It is
* given the instance of the service locator, the requested name of the class
* you want to create, and any additional options that could be used to
* configure the instance state.
*/
interface FactoryInterface
{
/**
* Create an object
*
* @param string $requestedName
* @param null|array<mixed> $options
* @return object
* @throws ServiceNotFoundException If unable to resolve the service.
* @throws ServiceNotCreatedException If an exception is raised when creating a service.
* @throws ContainerException If any other error occurs.
*/
public function __invoke(ContainerInterface $container, $requestedName, ?array $options = null);
}
// ④ __invokeメソッドについて
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$formManager = $container->get('FormElementManager');
return new WriteController(
$container->get(PostCommandInterface::class),
$formManager->get(PostForm::class)
);
}
この__invokeメソッドを簡単に解説していきます。
__invokeメソッドは、マジックメソッドと呼ばれるもので、既にPHPによって動作が決まっているメソッドです。詳細はこちらです。PHPマニュアル マジックメソッド
以下の部分で、__invokeメソッドを定義しています。これはこれによって、このFactoryクラスは、クラスをインスタンス化し、メソッドを呼び出すことなく、インスタンスの呼び出しのみで__invokeメソッド内の処理を実行できます。
引数について
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
第1引数の「ContainerInterface $container」は、アプリケーションのコンテナです。PSR-11に準拠しています。詳しくはこちらです。PHP-FIG PSR-11: Container interface
第2引数の「$requestedName」は、FactoryInterfaceを自作した場合、そのインスタンスを呼び出す時の名前を設定します。
第3引数の「array $options = null」は、コントローラーマネージャーがインスタンス作成する時の任意のオプションです。これは使用しないので、このままで良いです。
次に__invokeメソッド内の実装について簡単に説明していきます!
__invokeメソッド内の実装について
$formManager = $container->get('FormElementManager');
return new WriteController(
$container->get(PostCommandInterface::class),
$formManager->get(PostForm::class)
);
上から1行ずつ簡単に説明していきます。
$container->get(‘FormElementManager’);について
この部分で、新たにFormElementManagerというものが現れました。これはフォーム専用のプラグインマネージャーです。便利な機能があります。
- コンテナインスタンスのgetメソッドで、作成したフォームクラスやフィールドセットクラスを取得すると、initメソッドを実行し、作成したフォームやフィールドセットを呼び出してくれます(全ての依存関係が注入された後にinitメソッドが実行されます)。
- フォームへの入力内容の検証に関するプラグインマネージャーなどもインスタンスと共有されるようになります。
ここまででFactoryが完成しました!
次にこのFactoryをmodule.config.phpに追記し、WriteControllerのルートを作成します。
WriteControllerのルートを作成する!
まずは、WriteControllerのインスタンス化するFactoryを指定するために、module.config.phpに以下を追記します。ルートについては公式ドキュメントはこちらです。Components laminas-router
module/Blog/config/module.config.php内のcontrollers構成部分内に追記します。
<?php
namespace Blog;
use Laminas\Router\Http\Literal;
use Laminas\Router\Http\Segment;
use Laminas\ServiceManager\Factory\InvokableFactory;
return [
'controllers' => [
'factories' => [
Controller\ListController::class => Factory\ListControllerFactory::class,
// 以下の部分を追加します
Controller\WriteController::class => Factory\WriteControllerFactory::class,
],
]
'service_manager' => [/* ... */]
'router' => [/* ... */]
'view_manager' => [/* ... */]
];
これで、WriteControllerをインスタンス化するFactoryをModuleManagerに知らせることが出来ます。
次にWriteControllerのルートを作成します。同様にmodule.config.phpのrouter構成部分に、以下の内容を追記します。
module/Blog/config/module.config.php
router構成部分に新たに「add」というルートを追加します。
<?php
namespace Blog;
use Laminas\Router\Http\Literal;
use Laminas\Router\Http\Segment;
use Laminas\ServiceManager\Factory\InvokableFactory;
return [
'service_manager' => [ /* ... */ ],
'controllers' => [ /* ... */ ],
'router' => [
'routes' => [
'blog' => [
'type' => Literal::class,
'options' => [
'route' => '/blog',
'defaults' => [
'controller' => Controller\ListController::class,
'action' => 'index',
],
],
'may_terminate' => true,
'child_routes' => [
'detail' => [
'type' => Segment::class,
'options' => [
'route' => '/:id',
'defaults' => [
'action' => 'detail',
],
'constraints' => [
'id' => '\d+',
],
],
],
// 追記箇所です。
'add' => [
'type' => Literal::class,
'options' => [
'route' => '/add',
'defaults' => [
'controller' => Controller\WriteController::class,
'action' => 'add',
],
],
],
],
],
],
],
'view_manager' => [ /* ... */ ],
];
追記箇所のみを抜き出して簡単に説明していきます。
'add' => [
'type' => Literal::class,
'options' => [
'route' => '/add',
'defaults' => [
'controller' => Controller\WriteController::class,
'action' => 'add',
],
],
],
このルートは、
「http://ドメイン/blog/add」をブラウザからリクエストすると、WriteControllerのaddActionメソッドが呼び出され、そのメソッドの処理結果が、addビュースクリプトを経由してレスポンスとして返ってくる
という設定です。
ルートの記述内容について簡単に説明します。
‘add’について
このルートは、/blogの子ルートです。
ブラウザで「http://ドメイン/blog/add」にリクエストすると、WriteControllerのaddActionメソッドが実行され、そのメソッドによって処理されたデータが、add.phtmlというviewscriptに渡され、ブラウザ上に表示されます。
つまり「http://ドメイン/add」でリクエストしても、そのようなルートは見つからないというエラーが返ってきます。
‘type’について
このルートのタイプは、Literal(リテラル)タイプで、‘options’内の‘route’で指定したものに完全一致した場合、リクエストが成功するタイプです。
つまり今回は、‘route’ => ‘/add’なので、/addに完全一致する場合がリクエスト成功となります。
‘options’について
‘options’には、‘route’と‘defaults’を含み、以下のような意味を持っています。
- ‘route’ はリクエストが成功するときのURI(サブディレクトリ部分)
- ‘defaults’ はリクエストが来たときに実行するコントローラーとそのアクションメソッドを指定します。
今回の場合は、
- ‘route’ は /addを指定します。(サブディレクトリ部分)
- ‘defaults’ は、WriteControllerのaddActionメソッドを指定します。
ここまでで、ルートの作成が完了しました!
お疲れ様でした!
次は、PostCommandリポジトリの雛形の作成をします!
コメント