【Laminas】ModelをControllerに取り込む

Laminas

どーも!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メソッドを実装します。

コメント

タイトルとURLをコピーしました