问题
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