どーも!marusukeです!
前回の記事(【Laminas】ブログモジュールのModelを作る!)の続きで、作成したModelをControllerに取り込みましょう!そのために必要なファクトリークラスの作成、そしてファクトリークラスに必要なオブジェクトをServiceManagerに知らせる設定をしていきます!
ModelをControllerに取り込むとは?
“Dependency Injection” (DI)のことです。依存性注入という日本語訳になりますが、簡単にいうと、今回はモデルオブジェクトをコントローラに入れます、ということです。
コンストラクタインジェクションをします。(コンストラクタに注入します。)
ListControllerに前の記事で作成したPostRepositoryInterfaceを注入しましょう!
namespace Blog\Controller;
use Blog\Model\PostRepositoryInterface; //追記します
use Laminas\Mvc\Controller\AbstractActionController;
class ListController extends AbstractActionController
{
/**
* @var PostRepositoryInterface
*/
private $postRepository;
public function __construct(PostRepositoryInterface $postRepository)
{
$this->postRepository = $postRepository;
}
}
PostRepositoryInterfaceのオブジェクト型でなければ注入できないようにしています。
でも、これだけでは、このコントローラーはインスタンスを作ることができません。もう一つ変更する部分があります。
それは、ModuleManagerにListControllerはPostRepositoryオブジェクトの引数をとることを伝えなければなりません。
以下の設定変更が必要になります。
In module/Blog/config/module.config.php
namespace Blog;
use Laminas\ServiceManager\Factory\InvokableFactory;
return [
'controllers' => [
'factories' => [
Controller\ListController::class => InvokableFactory::class, // ここを変更します
],
],
'router' => [ /** Router Config */ ]
'view_manager' => [ /** ViewManager Config */ ],
);
InvokableFactory::classは、引数のないコントローラー呼び出しの際に使われるクラスです。
以下のように書き換えます。
namespace Blog;
// InvokableFactoryのuse文を削除します
return [
'controllers' => [
'factories' => [
// Update the following line:
Controller\ListController::class => Factory\ListControllerFactory::class,
],
],
'router' => [ /** Router Config */ ]
'view_manager' => [ /** ViewManager Config */ ],
);
Factory\ListControllerFactory::classはこれから実装します。
内容は、ファクトリーというデザインパターンでコントローラーをインスタンス化していきます。
その時に、引数であるPostRepositoryInterfaceを注入します。
ファクトリーを作る
インスタンスを製造する工場(ファクトリー)を作っていきましょう!
ちなみにファクトリーというデザインパターンについてはこちらです。
以下のフォルダを作り、ListControllerFactoryファイルを作りましょう。
/module/Blog/src/Factory/ListControllerFactory.php
namespace Blog\Factory;
use Blog\Controller\ListController;
use Blog\Model\PostRepositoryInterface;
use Interop\Container\ContainerInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;
class ListControllerFactory implements FactoryInterface
{
/**
* @param ContainerInterface $container
* @param string $requestedName
* @param null|array $options
* @return ListController
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
return new ListController($container->get(PostRepositoryInterface::class));
}
}
ListControllerFactoryの内容を説明します。
Factoryクラスは決まりがあります。
- FactoryクラスはFactoryInterfaceをimplementsすること
- メソッドはマジックメソッド__invokeを使用すること(引数も上記の通りです。)
- クラス内のメソッドのパラメータに$container->get()に入れること
- returnは、コントローラーのインスタンス化したものになること
です。
アプリケーションコンテナ(ServiceManager=$containerのこと)にPostRepositoryInterfaceを渡し、invokeメソッド内のインスタンス化したListControllerに注入しています。
ServiceManagerについての説明は、別の記事(作成中です!^^;)でします。
PostRepositoryクラスをServiceManagerに知らせる
ファクトリークラスが完成した現在の状態で、http://localhost:8080/blogをブラウザで開くと以下のようなエラーが表示されるはずです。
An error occurred
An error occurred during execution; please try again later.
Additional information:
Laminas\ServiceManager\Exception\ServiceNotFoundException
File:
{projectPath}/vendor/laminas/laminas-servicemanager/src/ServiceManager.php:{lineNumber}
Message:
Unable to resolve service "Blog\Model\PostRepositoryInterface" to a factory; are
you certain you provided it during configuration?
Message:の以下の部分には、「Blog\Model\PostRepositoryInterfaceサービスが解決されません。PostRepositoryInterfaceサービスを構成に追加しましたか?」と言われています。
まだ、ファクトリークラスのパラメーターとなっているPostRepositoryInterfaceの扱いについてServiceManagerが知りません。
module/Blog/config/module.config.phpに以下を追記します。
namespace Blog;
// InvokableFactoryを再度追記します:
use Laminas\ServiceManager\Factory\InvokableFactory;
return [
// service_manager部分を追記します。:
'service_manager' => [
'aliases' => [
Model\PostRepositoryInterface::class => Model\PostRepository::class,
],
'factories' => [
Model\PostRepository::class => InvokableFactory::class,
],
],
'controllers' => [ /** Controller Config(割愛します) */ ],
'router' => [ /** Router Config (割愛します)*/ ],
'view_manager' => [ /** View Manager Config (割愛します)*/ ],
];
‘service_manager’の中身について説明します。
‘aliases’についてです。
'aliases' => [
Model\PostRepositoryInterface::class => Model\PostRepository::class,
],
PostRepositoryInterfaceが呼び出された時は、PostRepositoryを呼び出します。
‘factories’についてです。
'factories' => [
Model\PostRepository::class => InvokableFactory::class,
],
PostRepositoryクラスは、InvokableFactoryクラスというファクトリーによってインスタンス化されます。
InvokableFactoryクラスは、パラメータを持たないクラスをインスタンス化します。
これで、コントローラーにモデルを取り込むことが出来ました!
次は、ListControllerのindexActionメソッドを実装します。
コメント