How to change layout in controller in ZendFramework2?

廉价感情. 提交于 2019-12-25 03:03:21

问题


I found this topic and answer: Change layout in the controller of Zend Framework 2.0 :: Answer

I am trying to do this:

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

But it doesn't work.

Sure I have file MODULE_DIR/view/layout/login.phtml.

I tried to var_dump($this->layout()); before setting layout and after it and it shows, that layout is changed after $this->layout('layout/login'); line. But it is not.

How to set different layout in controller?

Also, why I don't get any messages if layout is changed? Why standart layout loaded, instead of error?

I think, I have to set up layout somewhere (like I set routes, for example). Possibly in config ['view_manager']['template_map'] by adding something like:

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

— like said there:

Of course you need to define those layouts, too... just check Application Modules module.config.php to see how to define a layout.

That didn't helped me :(

Update 1

Tried this:

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

as @alex suggested. Doesn't work :'(. Same result without return new ViewModel(); line.

You review files by yourself:

  • AdminController.php (loginAction)
  • module.config.php (to be sure I added layout/login correctly

Update 2

I tried to debug as you suggest.

I updated __invoke functioN:

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

There are some cases:

With code, you suggested:

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

it displays NULL. So method is called, but $template is null variable.

With code, from post, I had given in the start of my post:

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

It shows string(12) "layout/login".

Without any code (so layout layout/admin loaded (default for ZfcAdmin), it shows: string(12) "layout/admin".

If I load / of my site it page is loaded with standart layout (in both cases with or without layout/layout in module config.

Update 3

I tried this:

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

in controller. It shows: string(13) "layout/layout" string(12) "layout/login". So layout is changed. But standart layout layout/layout rendered instead of layout/login. :(


回答1:


Because you're using ZfcAdmin and have the use_admin_layout option enabled in that module and the login route you're attempting to set a layout on is a child route of ZfcAdmin, the admin layout listener is kicking in and over-writing the template you're attempting to set in your controller action.

It's perhaps easiest to disable zfcadmin layout, write your own listener and handle the specific case of login layout there. You can do that using essentially the same method that ZfcAdmin uses in Module.php with a tweak or two ...

Be sure to disable ZfcAdmin layout

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

then, using your module name as a config key, set up your own version of the same config ...

'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',
),

Next in MyZfcAdmin/Module.php add a listener, almost exactly like the one in ZfcAdmin only have it check your myzfcadmin config values instead ...

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);                
}

As you can see, I added code to check the controller is your specific AdminController instance and login action, and if so, set the alternate template otherwise use the default, no need to worry about it in your controller now.




回答2:


Add your layout in the template map of your view manager in the module.config.php

Like so:

// 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'
    )
)

Then, in your controller try setting the layout like this, using the setTemplate() method:

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

EDIT, the following is code from the Zend library:

Inside Zend\Mvc\Controller\Plugin\Layout notice this method:

/**
 * 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);
}

If you don't provide a template it will call this method:

/**
 * 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;
}

Notice the print_r statement, if you look at it, it will show you this:

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] => 
)

Notice the [template:protected] => layout/layout that why I was saying I think Zend defaults to that layout.

So go into that file, in the __invoke method and do echo $template;die; when you are setting your layout with $this->setTemplate('layout/login') in your controller and see if its even getting passed there. Then you might be able to trace it better.

EDIT: Setting up multiple layouts.

Here is one way you could set up layouts for your modules in an effort to reduce the likelihood of a conflict or something being overwritten.

// 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]);
}

And your layouts config could look something this:

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


来源:https://stackoverflow.com/questions/23690184/how-to-change-layout-in-controller-in-zendframework2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!