如何在Zend Framework 2中更改控制器中的布局?

时间:2014-05-15 23:09:17

标签: zend-framework2

我找到了这个主题并回答:Change layout in the controller of Zend Framework 2.0 :: Answer

我正在尝试这样做:

public function loginAction() {
    if ($this->zfcUserAuthentication()->hasIdentity()) {
        return $this->redirect()->toRoute('zfcadmin');
    }
    $this->layout('layout/login');
    return new ViewModel();
}

但它不起作用。

当然我有档案MODULE_DIR/view/layout/login.phtml

我在设置布局之前尝试var_dump($this->layout());,然后在显示之后,$this->layout('layout/login');行之后更改了布局。但事实并非如此。

如何在控制器中设置不同的布局?

另外,如果布局发生变化,我为什么不收到任何消息为什么标签布局已加载,而不是错误

我想,我必须在某处设置布局(比如我设置路线)。可能在配置['view_manager']['template_map']中添加如下内容:

$config = array(
    'view_manager' => array(
        'template_path_stack' => array(
            __DIR__ . '/../view'
        ),        
        'template_map' => array(
            'layout/login'           => __DIR__ . '/../view/layout/login.phtml',
        ),
    ),
);

- 就像说there

  

当然你也需要定义那些布局......只需检查   应用程序模块module.config.php,以了解如何定义布局。

那对我没有帮助:(

更新1

试过这个:

public function loginAction() {
    if ($this->zfcUserAuthentication()->hasIdentity()) {
        return $this->redirect()->toRoute('zfcadmin');
    }
    $layout = $this->layout();
    $layout->setTemplate('layout/login');
    return new ViewModel();
}

建议为@alex。不起作用:'(。没有return new ViewModel();行的结果相同。

您自己查看文件:

更新2

我按照你的建议尝试调试。

我更新了__invoke功能:

public function __invoke($template = null)
{
    var_dump($template);
    die();
    if (null === $template) {
        return $this->getViewModel();
    }
    return $this->setTemplate($template);
}

有些情况:

使用代码,您建议:

$layout = $this->layout();
$layout->setTemplate('layout/login');

它显示NULL。所以调用方法,但$template是空变量。

代码来自post,我在帖子的开头给出了:

$this->layout('layout/login');
return new ViewModel();

显示string(12) "layout/login"

没有任何代码(因此加载了布局layout/admin(默认为ZfcAdmin),它会显示:string(12) "layout/admin"

如果我加载了我的网站的/,那么该网页就会加载标准布局(在两种情况下,模块配置中都有layout/layout

更新3

我试过了:

$layout = $this->layout();
var_dump($layout->getTemplate());
$layout->setTemplate('layout/login');
var_dump($layout->getTemplate());
die();

在控制器中。它显示:string(13) "layout/layout" string(12) "layout/login"。所以布局改变了。但标准布局layout/layout已呈现,而不是layout/login。 :(

2 个答案:

答案 0 :(得分:2)

由于您正在使用ZfcAdmin ,因此在该模块中启用了use_admin_layout选项您的登录路线是'重新尝试设置布局是ZfcAdmin的子路由,管理布局监听器正在开始并覆盖您尝试在控制器操作中设置的模板。

最简单的方法是禁用zfcadmin布局,编写自己的监听器并处理登录布局的具体情况。您可以使用与ZfcAdmin在Module.php中使用的方法基本相同的方法,使用一两个调整...

请务必禁用ZfcAdmin布局

'zfcadmin' => array(
    'use_admin_layout' => false,
),

然后,使用您的模块名称作为配置密钥,设置您自己的相同配置版本...

'myzfcadmin' => array(
    'use_admin_layout' => true,
    'admin_layout_template' => 'layout/admin',
    // you could even define a login layout template here
    'login_layout_template' => 'layout/login',
),

接下来在MyZfcAdmin/Module.php添加一个监听器,几乎与ZfcAdmin中的监听器一样,只检查你的myzfcadmin配置值...

public function onBootstrap(MvcEvent $e)
{
    $app = $e->getParam('application');
    $em = $app->getEventManager();

    $em->attach(MvcEvent::EVENT_DISPATCH, array($this, 'selectLayoutBasedOnRoute'));
}

public function selectLayoutBasedOnRoute(MvcEvent $e)
{
    $app = $e->getParam('application');
    $sm = $app->getServiceManager();
    $config = $sm->get('config');

    if (false === $config['myzfcadmin']['use_admin_layout']) {
        return;
    }

    $match = $e->getRouteMatch();
    $controller = $e->getTarget();

    if (!$match instanceof \Zend\Mvc\Router\RouteMatch
        || 0 !== strpos($match->getMatchedRouteName(), 'zfcadmin')
        || $controller->getEvent()->getResult()->terminate()
    ) {
        return;
    }

    if ($controller instanceof \MyZfcAdmin\Controller\AdminController
        && $match->getParam('action') == 'login'
    ) {
        // if you'd rather just set the layout in your controller action just return here
        // return;
        // otherwise, use the configured login layout ..
        $layout = $config['myzfcadmin']['login_layout_template'];
    } else {
        $layout = $config['myzfcadmin']['admin_layout_template'];
    }

    $controller->layout($layout);                
}

正如您所看到的,我添加了代码以检查控制器是您的特定AdminController实例和登录操作,如果是,请设置备用模板,否则使用默认值,现在无需担心它在控制器中。

答案 1 :(得分:1)

在module.config.php

中的视图管理器的模板映射中添加您的布局

像这样:

// View file paths
'view_manager' => array(
    'display_not_found_reason' => true,
    'display_exceptions'       => true,
    'doctype'                  => 'HTML5',
    'not_found_template'       => 'error/404',
    'exception_template'       => 'error/index',
    'template_map'             => array
        'layout/login' => 'path_to_layout_file'
    )
)

然后,在你的控制器中尝试使用setTemplate()方法设置这样的布局:

$layout = $this->layout();
$layout->setTemplate('layout/login');

编辑,以下是Zend库中的代码:

Zend\Mvc\Controller\Plugin\Layout内注意此方法:

/**
 * Invoke as a functor
 *
 * If no arguments are given, grabs the "root" or "layout" view model.
 * Otherwise, attempts to set the template for that view model.
 *
 * @param  null|string $template
 * @return Model|Layout
 */
public function __invoke($template = null)
{
    if (null === $template) {
        return $this->getViewModel();
    }
    return $this->setTemplate($template);
}

如果您不提供模板,则会调用此方法:

/**
 * Retrieve the root view model from the event
 *
 * @return Model
 * @throws Exception\DomainException
 */
protected function getViewModel()
{
    $event     = $this->getEvent();
    $viewModel = $event->getViewModel();
    echo '<pre>' . print_r($viewModel, true) . '</pre>';die;

    if (!$viewModel instanceof Model) {
        throw new Exception\DomainException('Layout plugin requires that event view model is populated');
    }
    return $viewModel;
}

注意print_r语句,如果你看一下,它会告诉你:

Zend\View\Model\ViewModel Object
(
[captureTo:protected] => content
[children:protected] => Array
    (
    )

[options:protected] => Array
    (
    )

[template:protected] => layout/layout
[terminate:protected] => 
[variables:protected] => Zend\View\Variables Object
    (
        [strictVars:protected] => 
        [storage:ArrayObject:private] => Array
            (
            )

    )

[append:protected] => 
)

请注意[template:protected] => layout/layout我之所以说我认为Zend默认使用该布局。

所以,使用__invoke方法进入该文件,并在控制器中使用echo $template;die;设置布局时执行$this->setTemplate('layout/login'),看看它是否已经通过了// where $sm is the service manager $config = $sm->get('config'); $config = array_merge($config, include '/path_to_config/layouts.config.php'); if (isset($config['module_layouts'][$moduleNamespace])) { $controller->layout($config['module_layouts'][$moduleNamespace]); } 。然后你可以更好地追踪它。

编辑:设置多个布局。

以下是为模块设置布局的一种方法,以减少冲突或被覆盖的可能性。

'module_layouts' => array(
   '_default'   => 'layout/layout',
   'admin'      => 'layout/admin',
   'foo'        => 'layout/foo',
   'login'      => 'layout/login' // etc, etc
),

你的布局配置看起来像这样:

{{1}}