ZF2のコントローラーでサブ名前空間を使う

## 問題

コントローラー名で次のようにサブ名前空間を使いたい場合、

```php:Application/Controller/Admin/IndexController
<?php
namespace Application\Controller\Admin;

class IndexController extends \Zend\Mvc\Controller\AbstractActionController
{
    public function indexAction()
    {
        return [];
    }
}
```

次のようにルーティングするとテンプレートの名前が `application/index/index.phtml` となってしまいます。

```php:Application/config/module.config.php
return array(
    'router' => array(
        'routes' => array(
            'home' => array(
                'type' => 'literal',
                'options' => array(
                    'route' => '/',
                    'defaults' => array(
                        'controller' => 'Application\Controller\Index',
                        'action'     => 'index',
                    ),
                ),
            ),
            'admin' => array(
                'type' => 'literal',
                'options' => array(
                    'route' => '/admin',
                    'defaults' => array(
                        'controller' => 'Application\Controller\Admin\Index',
                        'action'     => 'index',
                    ),
                ),
            ),
        ),
    ),

    // ...
);
```

[`Zend\Mvc\View\Http\InjectTemplateListener`](https://github.com/zendframework/zf2/blob/release-2.3.1/library/Zend/Mvc/View/Http/InjectTemplateListener.php#L52) でテンプレート名を解決するときに下記の２つが連結されてテンプレート名になるためです。

 1. コントローラーの先頭の名前空間（モジュール名）
 2. コントローラーの名前空間を除くクラス名からサフィックスの `Controller` を除いたもの

そのため、次の２つのコントローラーは同じテンプレート名になってしまいます。

```
Application\Controller\Index
 -> application/index/{action}
Application\Controller\Admin\Index
 -> application/index/{action}
```

## 解決方法

モジュールのブートストラップで `Zend\Mvc\ModuleRouteListener` をアタッチします。

```php:Application/Module.php
<?php
namespace Application;

use Zend\EventManager\EventInterface;
use Zend\Mvc\MvcEvent;
use Zend\ModuleManager\Feature\BootstrapListenerInterface;
use Zend\Mvc\ModuleRouteListener;

class Module implements BootstrapListenerInterface
{
    public function onBootstrap(EventInterface $ev)
    {
        if ($ev instanceof MvcEvent) {
            $ev->getApplication()->getEventManager()->attach(new ModuleRouteListener());
        }
    }

    // ...
}
```

次のように `__NAMESPACE__` を使ってルーティングを書きます。

```php:Application/config/module.config.php
return array(
    'router' => array(
        'routes' => array(
            'home' => array(
                'type' => 'literal',
                'options' => array(
                    'route' => '/',
                    'defaults' => array(
                        '__NAMESPACE__' => 'Application\Controller',
                        'controller' => 'Index',
                        'action'     => 'index',
                    ),
                ),
            ),
            'admin' => array(
                'type' => 'literal',
                'options' => array(
                    'route' => '/admin',
                    'defaults' => array(
                        '__NAMESPACE__' => 'Application\Controller\Admin',
                        'controller' => 'Index',
                        'action'     => 'index',
                    ),
                ),
            ),
        ),
    ),

    // ...
```

すると、テンプレート名の解決方法が次の３つを連結したものに変わります。

 1. コントローラーの先頭の名前空間（モジュール名）
 2. `__NAMESPACE__` で指定された名前空間の先頭２つを除いたもの
 3. コントローラーの名前空間を除くクラス名からサフィックスの `Controller` を除いたもの

よって、次の２つも別々のテンプレートになります。

```
Application\Controller\Index
 -> application/index/{action}
Application\Controller\Admin\Index
 -> application/admin/index/{action}
```