ZF3多模块和多个布局

时间:2018-01-11 23:48:03

标签: zend-framework3

我正在使用Zend Framework 3工作一个多模块站点大约6个月,随着我的学习。在大多数情况下,我已经非常成功,但我遇到了一个问题,我将在下面介绍。有大约20个模块,我已经确定在每个模块module.config.php中我应该为这个布局定义一个唯一的名称。

  • 命名空间示例
  • 控制器名称:SampleController.php
  • 模块/样品/视图/ sam_layout.phtml

在Sample modules module.config.php

'view_manager' => [
    'display_not_found_reason' => true,
    'display_exceptions'       => true,
    'doctype'                  => 'HTML5',
    'template_map' => [
    'layout/layout' => _DIR__ . '/../view/layout/sam_layout.phtml',
    'sample/sample/index' => __DIR__ . '/../view/sample/sample/index.phtml',
    ],
    'template_path_stack' => [
    'Sample' =>  __DIR__ . '/../view',

如果我调用布局文件'layout.phtml',即使我注意到命名空间,也不确定预期的视图是否出现或仅部分正确。我注意到如果我重新排列composer.json和modules.config.php中的模块名称然后运行composer dump-autoload我得到一组不同的混合布局,无论我是否给layout.phtml文件一个唯一的前缀。< / p>

唯一可以清除这一点的是做一些事情,比如清除composer.json和modules.config.php,除了Application模块然后重新运行composer dump-autoload或更改模块名称添加到composer.json&amp; modules.config重新运行dump-autoload,然后把模块名称放回去。基本上震动了配置,以强制看起来似乎是保持视图扰乱放手并重新映射一切。请注意,当这个问题神奇地清除时,它就消失了,我们可以继续开发代码,好像什么都没有错。

我应该注意,我们从开发模式中的skeleton-application开始。我实际上删除了data / cache文件夹中的所有文件。不同模块中的大多数视图共享Nav Bar,但是多个模块可以选择特定模块Nav Bar视图,并且很难清除。

所以描述了上面我有一些问题。其他开发人员是否有同样的问题为什么我不能给布局脚本一个唯一的名称并期望视图得到尊重?随着我们的进一步发展,我确信每个模块都有更多的布局,当然样本/示例文件夹中的更多.phtml文件(以上面的例子为例)我们会继续看到这种行为吗? Apache Web Server或PHP7是否可以缓存导致此问题的文件和路径,而ZF3与它无关?注意:我没有启用opcache。

请怜悯:如果你把我埋在OO代码中,它可能无法帮助我理解正在发生的事情。

1 个答案:

答案 0 :(得分:4)

如果您是ZF2 / 3新手,这是合法的问题。

您应该知道的一件事是,所有配置(application.config.phpmodules.config.php和每个模块module.config.php以及您定义的任何其他配置文件都应包含在Module.php类中),它们都被合并到单个配置数组中。

因此,如果每个模块中都有以下位,则只有最后一个模块在使用array_merge_recursive进行合并时才有效,如果使用array_merge则只有第一个有效。

'view_manager' => [
    // ... others
    'template_map' => [
        'layout/layout' => _DIR__ . '/../view/layout/sam_layout.phtml',
        // ... others
    ],
],

因此,请确保:

  • 定义关联数组键
  • 请确保您在扩展模块中覆盖该值

就个人而言,我使用这两个规则。定义一次并在需要时覆盖。但是,要小心后者,很容易犯错误。

其中一个错误是在layout/layout模块中定义Application,然后在User模块中再次定义,再在另一个模块中定义。 不要这样做,;)

首先修复配置问题

要为您提供一些清理过的配置,以便您不会迷失方向,请使用AbstractModule.php课程。我已经从某人的片段中复制了我的(不记得是谁,否则会信​​用)。

namespace Your\Core\Or\Mvc\Module\Namespace;

use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
use Zend\ModuleManager\Feature\ConfigProviderInterface;

/**
 * Class AbstractModule
 * @package Your\Core\Or\Mvc\Module\Namespace
 */
abstract class AbstractModule implements ConfigProviderInterface, AutoloaderProviderInterface
{
    /**
     * @var String Path of current module
     */
    protected $path;

    /**
     * @var String Namespace of current module
     */
    protected $namespace;

    /**
     * This is to be called by descendant classes with:
     * parent::__construct(__DIR__, __NAMESPACE__)
     *
     * @param $path      string Module path
     * @param $namespace string Module namespace
     */
    public function __construct($path, $namespace)
    {
        $this->path = $path;
        $this->namespace = $namespace;
    }

    /**
     * @return array
     */
    public function getConfig()
    {
        $config = [];

        foreach (glob($this->path . '/config/*.php') as $filename) {
            $config = array_merge_recursive($config, include $filename);
        }

        return $config;
    }

    /**
     * @return array
     */
    public function getAutoloaderConfig()
    {
        return [
            'Zend\Loader\StandardAutoloader' => [
                'namespaces' => [
                    $this->namespace => $this->path . DIRECTORY_SEPARATOR . 'src',
                ],
            ],
        ];
    }
}

在每个模块中使用以下Module.php

namespace Your\Module\Namespace;

use Your\Core\Or\Mvc\Module\Namespace\AbstractModule;

/**
 * Class Module
 * @package Your\Module\Namespace
 */
class Module extends AbstractModule
{
    /**
     * Module constructor.
     */
    public function __construct()
    {
        parent::__construct(__DIR__, __NAMESPACE__);
    }
}

为什么我会使用所有这些OO渣土?

好吧,如果您有此代码,则可以按主题分隔模块中的所有配置文件。因此,在APP_DIR/module/MODULE_NAME/config/文件夹中,您现在可以放置一堆配置文件,例如:

  • module.config.php
  • routes.config.php
  • custom.config.php

所有这些都会加载。

介意:这并未解决您的布局被其他人覆盖的问题。这是因为您为所有配置使用了相同的配置密钥名称(layout/layout)。

第二次设置配置以允许不同的布局

接下来,您希望每个模块使用不同的布局。这没有问题,但是,您需要确保允许进行设置的配置。因此,我们使用一小段代码。

如果您有专门针对主题的模块,请将此功能添加到其Module.php。否则,您可能希望将其添加到Module.php模块中的Application类。

/**
 * @param MvcEvent $e
 */
public function onBootstrap(MvcEvent $e)
{
    $eventManager = $e->getApplication()->getEventManager();
    $moduleRouteListener = new ModuleRouteListener();
    $moduleRouteListener->attach($eventManager);

    /**
     * Source: https://github.com/Hounddog/HdRouteLayouts/blob/master/Module.php
     * Add below AND route_layouts => [ %route% => %template/layout% ] to a module to allow route based layout
     *
     * Below example applies layout in [layout/admin => [ %path/to/layout.phtml% ] to all routes starting with
     * "admin*" as defined in the "route_layouts => []" array.
     *
     *  'view_manager' => [
     *      'template_map' => [
     *          'layout/admin' => __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'view'
     *          . DIRECTORY_SEPARATOR . 'layout' . DIRECTORY_SEPARATOR . 'layout.phtml',
     *      ],
     *  ],
     *
     *  'route_layouts' => [
     *      'admin*' => 'layout/admin',
     *  ],
     */
    $e->getApplication()->getEventManager()->getSharedManager()
        ->attach(AbstractActionController::class, MvcEvent::EVENT_DISPATCH, function (MvcEvent $e) {
            $controller = $e->getTarget();
            $routeName = $e->getRouteMatch()->getMatchedRouteName();
            $config = $e->getApplication()->getServiceManager()->get('config');
            $layoutConfig = isset($config['route_layouts']) ? $config['route_layouts'] : [];

            if (isset($layoutConfig) && count($layoutConfig) > 0) {
                if (isset($layoutConfig[$routeName])) {
                    $controller->layout($layoutConfig[$routeName]);
                } else {
                    $rules = array_keys($layoutConfig);
                    foreach ($rules as $routeRule) {
                        if (fnmatch($routeRule, $routeName, FNM_CASEFOLD)) {
                            $controller->layout($layoutConfig[$routeRule]);
                            break;
                        }
                    }
                }
            }
        }, 100);
}

我们现在可以添加特定的路线布局了!

我们通过在配置中注册它们来添加新布局。从我的一个项目中,我们添加了一些布局,这里添加了配置,以根据路线使用不同的布局。

// 'route_layouts' is a new "top-level" config array key
// Here you define: route -> template_name
'route_layouts' => [
    '*'           => 'layout/layout', 
    'login'       => 'layout/login',
    'register'    => 'layout/login',
    'error*'      => 'error/error',
    'error/404'   => 'error/404',
    'error/index' => 'error/index',
],
'view_manager' => [
    'template_map' => [
        // Here you define: template_name -> location
        'layout/layout'   => __DIR__ . '/../view/layout/layout.phtml',
        'layout/login'    => __DIR__ . '/../view/layout/login.phtml',
        'layout/register' => __DIR__ . '/../view/layout/register.phtml',
        'error/error'     => __DIR__ . '/../view/error/error.phtml',
        'error/404'       => __DIR__ . '/../view/error/404.phtml',
        'error/index'     => __DIR__ . '/../view/error/index.phtml',
    ],
    // ... other config
],

希望您在配置和布局问题上为您解决了很多问题。如果您无法使用这些示例,请随意对相关问题发表评论。