HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

Zend FrameworkからLaminasに移行する話(4)

はじめに

お仕事で、Zend Frameworkのバージョンアップをしなければならなくなった・・と思ったら、Zend Frameworkはもうなくて、Laminas Projectに移って新たなフレームワークとして公開されている。

いちから勉強しないといけないじゃん、ということで、必要な要件を満たせるかどうかを一歩ずつ調査していく。

要件(4)

4つ目の要件は、「複数のモジュール間で行き来ができること」。

前回、同一モジュール内でのforward/redirectはできることを確認したが、複数モジュール間でできるのかなど、その辺りも含めて確認していく。

検証ポイントは以下の通り。

  • 複数モジュール間でforwardができるかどうか
    • その際、渡されたパラメータは引き継げるか(当然できるよね、のテンションで)
  • 複数モジュール間でredirectができるかどうか
    • その際、パラメータは引き継げないことの確認(これはその性質から当然だよね、のテンションで)

導入

こちらでセットアップした環境を(コピーして)使っていく。

hhelibex.hatenablog.jp

私は以下のようにコピーを作成。

cp -pr laminas-setup-3-forward-redirect laminas-setup-4-multiple-modules
cd laminas-setup-4-multiple-modules

設定・実装

新たなモジュールAnotherModuleの追加

新たに作るモジュール名をAnotherModuleとする。

composer.jsonを以下のように修正する。

    "autoload": {
        "psr-4": {
            "Application\\": "module/Application/src/",
        }
    },

    "autoload": {
        "psr-4": {
            "Application\\": "module/Application/src/",
            "AnotherModule\\": "module/AnotherModule/src/"
        }
    },

とする。 修正が済んだら、以下のコマンドを実行。

composer dump-autoload

config/modules.config.phpAnotherModuleを追加する。

<?php

/**
 * List of enabled modules for this application.
 *
 * This should be an array of module namespaces used in the application.
 */
return [
    'Laminas\Router',
    'Laminas\Validator',
    'Application',
    'AnotherModule',
    'Smarty',
];

続いて、AnotherModuleを作成していく。

mkdir module/AnotherModule
mkdir module/AnotherModule/config
mkdir -p module/AnotherModule/src/Controller
mkdir -p module/AnotherModule/view/another-module
mkdir module/AnotherModule/view/another-module/index
mkdir module/AnotherModule/view/another-module/forwarded
mkdir module/AnotherModule/view/another-module/redirected

module/AnotherModule/config/module.config.phpを以下の内容で作成する。

<?php

declare(strict_types=1);

namespace AnotherModule;

use Laminas\Router\Http\Literal;
use Laminas\Router\Http\Segment;
use Laminas\ServiceManager\Factory\InvokableFactory;

return [
    'router' => [
        'routes' => [
            'another-module' => [
                'type'    => Segment::class,
                'options' => [
                    'route'    => '/another-module[/:action]',
                    'defaults' => [
                        'controller' => Controller\IndexController::class,
                        'action'     => 'index',
                    ],
                ],
            ],
            'forwarded2' => [
                'type'    => Segment::class,
                'options' => [
                    'route'    => '/another-module/forwarded[/:action]',
                    'defaults' => [
                        'controller' => Controller\ForwardedController::class,
                        'action'     => 'index',
                    ],
                ],
            ],
            'redirected2' => [
                'type'    => Segment::class,
                'options' => [
                    'route'    => '/another-module/redirected[/:action]',
                    'defaults' => [
                        'controller' => Controller\RedirectedController::class,
                        'action'     => 'index',
                    ],
                ],
            ],
        ],
    ],
    'controllers' => [
        'factories' => [
            Controller\IndexController::class => InvokableFactory::class,
            Controller\ForwardedController::class => InvokableFactory::class,
            Controller\RedirectedController::class => InvokableFactory::class,
        ],
    ],
    'view_manager' => [
        'display_not_found_reason' => true,
        'display_exceptions'       => true,
        'doctype'                  => 'HTML5',
        'not_found_template'       => 'error/404',
        'exception_template'       => 'error/index',
        'template_map' => [
            'another-module/index/index' => __DIR__ . '/../view/another-module/index/index.tpl',
            'another-module/index/chrome' => __DIR__ . '/../view/another-module/index/chrome.tpl',
            'another-module/index/firefox' => __DIR__ . '/../view/another-module/index/firefox.tpl',
        ],
        'template_path_stack' => [
            __DIR__ . '/../view',
        ],
        'strategies' => [
            'Smarty\\View\\Strategy',
        ],
    ],
];

module/AnotherModule/src/Controller/IndexController.phpを以下の内容で作成する。

<?php

declare(strict_types=1);

namespace AnotherModule\Controller;

use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;

class IndexController extends AbstractActionController
{
    public function indexAction()
    {
        $timeStr = 'AnotherModule' . date(' [Y/m/d H:i:s]');
        $isFirefox = preg_match('/Firefox/', $_SERVER['HTTP_USER_AGENT']);
        return new ViewModel([
                'time_str' => $timeStr,
                'user_agent' => $_SERVER['HTTP_USER_AGENT'],
                'is_firefox' => $isFirefox,
        ]);
    }
}

module/AnotherModule/src/Controller/ForwardedController.phpを以下の内容で作成する。

<?php

declare(strict_types=1);

namespace AnotherModule\Controller;

use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;

class ForwardedController extends AbstractActionController
{
    public function chromeAction()
    {
        $a = isset($_GET['a']) ? $_GET['a'] : 'N/A';
        $c = isset($_GET['c']) ? $_GET['c'] : 'N/A';
        return new ViewModel(['a' => $a, 'c' => $c]);
    }
    public function firefoxAction()
    {
        $a = isset($_GET['a']) ? $_GET['a'] : 'N/A';
        $c = isset($_GET['c']) ? $_GET['c'] : 'N/A';
        return new ViewModel(['a' => $a, 'c' => $c]);
    }
}

module/AnotherModule/src/Controller/RedirectedController.phpを以下の内容で作成する。

<?php

declare(strict_types=1);

namespace AnotherModule\Controller;

use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;

class RedirectedController extends AbstractActionController
{
    public function chromeAction()
    {
        $a = isset($_GET['a']) ? $_GET['a'] : 'N/A';
        $c = isset($_GET['c']) ? $_GET['c'] : 'N/A';
        return new ViewModel(['a' => $a, 'c' => $c]);
    }
    public function firefoxAction()
    {
        $a = isset($_GET['a']) ? $_GET['a'] : 'N/A';
        $c = isset($_GET['c']) ? $_GET['c'] : 'N/A';
        return new ViewModel(['a' => $a, 'c' => $c]);
    }
}

module/AnotherModule/src/Module.phpを以下の内容で作成する。

<?php

declare(strict_types=1);

namespace AnotherModule;

class Module
{
    public function getConfig(): array
    {
        /** @var array $config */
        $config = include __DIR__ . '/../config/module.config.php';
        return $config;
    }
}

module/AnotherModule/view/another-module/index/index.tplを以下の内容で作成する。

Index view (AnotherModule)
<br />
PHP version: {$smarty.const.PHP_VERSION}
<br />
Time: {$time_str|escape:"html"}
<br />
Firefox: {$is_firefox}
<br />
User-Agent: {$user_agent|escape:"html"}

module/AnotherModule/view/another-module/forwarded/chrome.tplを以下の内容で作成する。

AnotherModule<br>
Forwarded Chrome view
<br>
a={$a}, c={$c}

module/AnotherModule/view/another-module/forwarded/firefox.tplを以下の内容で作成する。

AnotherModule<br>
Forwarded Firefox view
<br>
a={$a}, c={$c}

module/AnotherModule/view/another-module/redirected/chrome.tplを以下の内容で作成する。

AnotherModule<br>
Redirected Chrome view
<br>
a={$a}, c={$c}

module/AnotherModule/view/another-module/redirected/firefox.tplを以下の内容で作成する。

AnotherModule<br>
Redirected Firefox view
<br>
a={$a}, c={$c}

既存モジュールApplicationの修正

module/Application/src/Controller/IndexController.phpを以下のように修正する。

変更点は、以下のメソッドの追加。AnotherModuleへforward/redirectするためのメソッドとなる。

    public function redirect2Action()
    {
        $isFirefox = preg_match('/Firefox/', $_SERVER['HTTP_USER_AGENT']);
        if ($isFirefox) {
            return $this->redirect()->toRoute('redirected2', ['action' => 'firefox']);
        } else {
            return $this->redirect()->toRoute('redirected2', ['action' => 'chrome']);
        }
    }
    public function forward2Action()
    {
        $isFirefox = preg_match('/Firefox/', $_SERVER['HTTP_USER_AGENT']);
        if ($isFirefox) {
            $forward = $this->forward()->dispatch(\AnotherModule\Controller\ForwardedController::class, ['action' => 'firefox']);
        } else {
            $forward = $this->forward()->dispatch(\AnotherModule\Controller\ForwardedController::class, ['action' => 'chrome']);
        }
        return $forward;
    }

変更後の内容は以下の通り。

<?php

declare(strict_types=1);

namespace Application\Controller;

use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;

class IndexController extends AbstractActionController
{
    public function indexAction()
    {
        $timeStr = date('Y/m/d H:i:s');
        $isFirefox = preg_match('/Firefox/', $_SERVER['HTTP_USER_AGENT']);
        return new ViewModel([
                'time_str' => $timeStr,
                'user_agent' => $_SERVER['HTTP_USER_AGENT'],
                'is_firefox' => $isFirefox,
        ]);
    }
    public function redirectAction()
    {
        $isFirefox = preg_match('/Firefox/', $_SERVER['HTTP_USER_AGENT']);
        if ($isFirefox) {
            return $this->redirect()->toRoute('redirected', ['action' => 'firefox']);
        } else {
            return $this->redirect()->toRoute('redirected', ['action' => 'chrome']);
        }
    }
    public function forwardAction()
    {
        $isFirefox = preg_match('/Firefox/', $_SERVER['HTTP_USER_AGENT']);
        if ($isFirefox) {
            $forward = $this->forward()->dispatch(ForwardedController::class, ['action' => 'firefox']);
        } else {
            $forward = $this->forward()->dispatch(ForwardedController::class, ['action' => 'chrome']);
        }
        return $forward;
    }
    public function redirect2Action()
    {
        $isFirefox = preg_match('/Firefox/', $_SERVER['HTTP_USER_AGENT']);
        if ($isFirefox) {
            return $this->redirect()->toRoute('redirected2', ['action' => 'firefox']);
        } else {
            return $this->redirect()->toRoute('redirected2', ['action' => 'chrome']);
        }
    }
    public function forward2Action()
    {
        $isFirefox = preg_match('/Firefox/', $_SERVER['HTTP_USER_AGENT']);
        if ($isFirefox) {
            $forward = $this->forward()->dispatch(\AnotherModule\Controller\ForwardedController::class, ['action' => 'firefox']);
        } else {
            $forward = $this->forward()->dispatch(\AnotherModule\Controller\ForwardedController::class, ['action' => 'chrome']);
        }
        return $forward;
    }
}

module/Application/src/Controller/ForwardedController.phpを以下のように修正する。

         return new ViewModel();

         $a = isset($_GET['a']) ? $_GET['a'] : 'N/A';
         $c = isset($_GET['c']) ? $_GET['c'] : 'N/A';
         return new ViewModel(['a' => $a, 'c' => $c]);

に修正。 修正後の内容は以下のようになる。

<?php

declare(strict_types=1);

namespace Application\Controller;

use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;

class ForwardedController extends AbstractActionController
{
    public function indexAction()
    {
        $timeStr = date('Y/m/d H:i:s');
        $isFirefox = preg_match('/Firefox/', $_SERVER['HTTP_USER_AGENT']);
        return new ViewModel([
                'time_str' => $timeStr,
                'user_agent' => $_SERVER['HTTP_USER_AGENT'],
                'is_firefox' => $isFirefox,
        ]);
    }
    public function chromeAction()
    {
        $a = isset($_GET['a']) ? $_GET['a'] : 'N/A';
        $c = isset($_GET['c']) ? $_GET['c'] : 'N/A';
        return new ViewModel(['a' => $a, 'c' => $c]);
    }
    public function firefoxAction()
    {
        $a = isset($_GET['a']) ? $_GET['a'] : 'N/A';
        $c = isset($_GET['c']) ? $_GET['c'] : 'N/A';
        return new ViewModel(['a' => $a, 'c' => $c]);
    }
}

module/Application/src/Controller/RedirectedController.phpを以下のように修正する。

         return new ViewModel();

         $a = isset($_GET['a']) ? $_GET['a'] : 'N/A';
         $c = isset($_GET['c']) ? $_GET['c'] : 'N/A';
         return new ViewModel(['a' => $a, 'c' => $c]);

に修正。 修正後の内容は以下のようになる。

<?php

declare(strict_types=1);

namespace Application\Controller;

use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;

class RedirectedController extends AbstractActionController
{
    public function indexAction()
    {
        $timeStr = date('Y/m/d H:i:s');
        $isFirefox = preg_match('/Firefox/', $_SERVER['HTTP_USER_AGENT']);
        return new ViewModel([
                'time_str' => $timeStr,
                'user_agent' => $_SERVER['HTTP_USER_AGENT'],
                'is_firefox' => $isFirefox,
        ]);
    }
    public function chromeAction()
    {
        $a = isset($_GET['a']) ? $_GET['a'] : 'N/A';
        $c = isset($_GET['c']) ? $_GET['c'] : 'N/A';
        return new ViewModel(['a' => $a, 'c' => $c]);
    }
    public function firefoxAction()
    {
        $a = isset($_GET['a']) ? $_GET['a'] : 'N/A';
        $c = isset($_GET['c']) ? $_GET['c'] : 'N/A';
        return new ViewModel(['a' => $a, 'c' => $c]);
    }
}

以下のファイルを修正する。

  • module/Application/view/application/forwarded/chrome.tpl
  • module/Application/view/application/forwarded/firefox.tpl
  • module/Application/view/application/redirected/chrome.tpl
  • module/Application/view/application/redirected/firefox.tpl

修正内容は、以下の記述の追加。ファイルの末尾に追加する。

<br>
a={$a}, c={$c}

動作確認

http://192.168.56.xxx/laminas-setup-4-multiple-modules/public/application/forward?a=b&c=dへアクセスする

Applicationモジュールへのforward

Firefoxの場合

laminas-setup-4-multiple-modules-1

Google Chromeの場合

laminas-setup-4-multiple-modules-5

http://192.168.56.xxx/laminas-setup-4-multiple-modules/public/application/forward2?a=b&c=dへアクセスする

AnotherModuleモジュールへのforward

Firefoxの場合

laminas-setup-4-multiple-modules-2

Google Chromeの場合

laminas-setup-4-multiple-modules-6

http://192.168.56.xxx/laminas-setup-4-multiple-modules/public/application/redirect?a=b&c=dへアクセスする

Applicationモジュールへのredirect

Firefoxの場合

laminas-setup-4-multiple-modules-3

Google Chromeの場合

laminas-setup-4-multiple-modules-7

http://192.168.56.xxx/laminas-setup-4-multiple-modules/public/application/redirect2?a=b&c=dへアクセスする

AnotherModuleへのredirect

Firefoxの場合

laminas-setup-4-multiple-modules-4

Google Chromeの場合

laminas-setup-4-multiple-modules-8

まとめ

  • 複数モジュール間でも、forwardやredirectができることが確認できた
  • forwardは、module/*/config/module.config.phpに記述したコントローラーのクラス名を記述する
  • redirectは、module/*/config/module.config.phpに記述したrouteの名前を記述する