I dont know if this is a bug of ZF2 or I just dont understand it well, but Im very excited why is this happening.
I'm using a solution to change layout of each module globaly by attaching a Dispatch event. (for example from http://framework.zend.com/manual/2.1/en/modules/zend.view.quick-start.html#dealing-with-layouts, last example)
It's working well, but problem is, when in some action I want to setTerminate(true); (for Ajax call) it will not display only content of controller/action template, but only layout template without content! And that is what I'm not expecting.
This is how to simulate this, set layout in dispatch function (instead of attaching event, to make it cleaner) and then setTerminate in controller's action.
public function dispatch(Request $request, Response $response = null)
{
parent::dispatch($request, $response);
$this->layout('layout/new');
}
public function indexAction()
{
$model = new ViewModel();
$model->setTerminal(true);
return $model;
}
Again, I'm expecting that this will display only content of controler/index template, but instead of that, it display only content of layout/new without content.
I tried to set layout in action, and it working how I'm expecting.
public function indexAction()
{
$this->layout('layout/new');
$model = new ViewModel();
$model->setTerminal(true);
return $model;
}
This is working, it display only content of controller/index template and not layout.
So if I'm changing layout globaly (by attaching dispatch event) for each controller it working until I want to use one of these controllers for Ajax call and use setTerminate.
Thanks for help with that.
When you mark your view model as terminal, listener on dispatch event replaces layout view model with view model you returned.
So it is too late to do $this->layout('layout/new'); after dispatch, you are changing template of your view model.
What you should do is attach listener. For example, from controller itself:
protected function attachDefaultListeners()
{
//do not forget to call parent
parent::attachDefaultListeners();
$events = $this->getEventManager();
//attach before action
$events->attach(MvcEvent::EVENT_DISPATCH, array($this, 'changeLayout'), 10);
}
public function changeLayout(MvcEvent $event)
{
$this->layout('layout/new');
}
That will set layout for your controller, but you will be able to change it from action and setTerminal() will work as expected
If you want to only show the content from the actions view file you can use this approach without an issue:
1) Make a new layout, for ajax calls. This will replace layout.phtml
application/layout/ajax-layout.phtml
<?php echo $this->content ?>
2) Modify your action to ovverride the default layout during Ajax calls
Inside your controller/action :
// Don't render base layout if Ajax call
if($this->getRequest()->isXmlHttpRequest()) {
$this->layout('application/layout/ajax-layout');
}
$model = new ViewModel();
return $model;
this will just render your actions content, and override your base layout :)
Related
I am very new to SugarCRM (SuitCRM 7.7.8). I could create a controller and could echo some strings in it. I wanted to make that value in a view file. I got confused whether I should use some js files or some tpl view file.
This is my code:
<?php
class MymoduleController extends SugarController {
//Can now put actions here
public function action_convert(){
echo "Hello world!";
//return true;
exit;
}
}
How can I map the controller to a view file.
In your controller action method add the following:
$this->view = 'EditView'
Change the 'EditView' to the view you wish to use. The built in MVC stuff is kept in include/MVC and the include/ListView, include/EditView, and include/MVC/DetailView.
If you take a look at say module/Accounts/views. You can see how views are implemented. It is best to create your code in the custom/modules/[module] folder. As this ensures that your changes will not be overwritten when you upgrade SuiteCRM.
You should separate your html with your view using tpls.
if you add the following in the display method of your view:
function display(){
$template = new Sugar_Smarty();
$template->assign('APP', $app_strings);
$template->assign('MOD', $mod_string);
echo $template->fetch('include/ListView/ListViewGeneric.tpl');
}
you can load your custom views.
In the past, with Yii 1, I use to load partial views with "renderPartial", if you did not use renderPartial, it loaded the "partial view" with layout. Now in Yii2, method renderPartial has been moved to the controller, BUT you also can do:
<?= $this->render('_form', [
'model' => $model,
]) ?>
Inside another view, and it works same way as renderPartial, what kind of sorcery is this? :D. I guess in some level Yii2 checks if it is being loaded inside another view and uses renderPartial but I have not been able to find it. Anyone has found this?
I came to this question, because I was reviewing Pjax, playing with it and I saw a couple examples where the controller used return $this->render but Pjax still worked, as far as I know Pjax stops working if <html> tag or error has been found on the response, am I right?
All the controller and view render() methods are essentially using the same method, part of the view model. It's a key concept in DRY (don't repeat yourself) The view model has this method;
public function render($view, $params = [], $context = null)
{
$viewFile = $this->findViewFile($view, $context);
return $this->renderFile($viewFile, $params, $context);
}
All it does is render the view file specified by $view.
Now in the controller, you have two methods; render() and renderPartial(). The difference is just that in one a layout is applied, and in the other it isn't. The code looks like this;
public function render($view, $params = [])
{
$content = $this->getView()->render($view, $params, $this);
return $this->renderContent($content);
}
The first line in the method does two things. Firstly it gets the view object, then, by chaining, it uses the render() method of that view object to generate the html from that view.
The second line then passes that content on to the renderContent() method of the controller, which applies any layout to the content.
The code for renderPartial() is this;
public function renderPartial($view, $params = [])
{
return $this->getView()->render($view, $params, $this);
}
As you can see, it's exactly the same as the render() method of the controller, except that it doesn't pass anything to the renderContent() method of the controller, it just outputs it.
As for the pjax part of your question, I'm guessing that as long as your pjax doesn't generate any substantial errors, it will work whether you are using $controller->render(), $controller->renderPartial() or $view->render().
As an admin I can create pages (don't think I have to paste my adminpagescontroller here, because you understand the logic). What I'm getting stuck on, is selecting, but especially using the layout that will be used for the page.
i.e. I have three layouts:
page with left sidebar
page with right sidebar
page with full-width (no sidebars)
And i.e. I want to create a salespage or so, which uses the layouts "page with full-width". How can I call this in my view?
Now all my views begin with #extends('layouts.path.file') <--- I need that to be filled in by the database, if you know what I mean.
One way of doing it is to use a view composer to define the current layout to be used. View composers set variables that can be used by all your views ('*') or just some ('users.profile', 'admin.profile'), so this is an example of using a user specific layout:
View::composer('*', function($view)
{
$view->with('userLayout', Auth::check() ? Auth::user()->layout : 'main');
});
And in your view you just have to:
#extends('layouts.'.$userLayout);
If you just need to select a page on your controller, you can pass a layout to it:
return View::make('myview')->with('layout', 'front.main');
And use it in your view:
#extends('layouts.'.$layout);
And if you have it on a table, you can just pass it on:
$layout = Pages::first()->layout;
return View::make('myview')->with('layout', $layout);
Or do the same in your composer
View::composer('*', function($view)
{
$layout = Pages::first()->layout;
$view->with('layout', $layout);
});
A lot of people like to set the layout in controller too, so you could in your controller do:
public function showProfile()
{
$this->layout = Pages::first()->layout;
$this->layout->content = View::make('user.profile');
}
And your views doesn't have to #extend a layout anymore, because you are already telling them which layout to use.
I have an existing Zend 1.12 project with modules et al that I am trying to simply add a view to create another web page. So there is a controller called "Management" that has an index action, the default of course, and the correct view page called index.phtml. That is all fine and works inside the entire project/website.
class Management_IndexController extends Default_Controller_Action {
function indexAction() {
$this->view->headStyle()->appendFile('contact.css', 'contact')
->appendFile('message.css')
;
$this->setLayout('management');
$this->view->headTitle()->set('Management');
$message = new Com_Ui_Message();
$request = $this->_request;
$settings=new Com_Data();
$content=new Com_Data();
$data = new Com_Data($request->getPost());
$this->setFocus('#name');
}
function chatAction() {
$this->view->headStyle()->appendFile('contact.css', 'contact')
->appendFile('message.css')
;
$this->view->testMessage = "test";
}
}
So if I browse to http://www.bmcmusicgroup.com/management I see the default action public function, and that is all good. If I try to add another public function called chatAction inside of the management controller, and create a view page called chat.phtml in the appropriate folder where the index.phtml file is (the management index.phtml file), and then point my browser to http://www.bmcmusicgroup.com/management/chat I get nothing.
This is an existing site that I am trying decipher. Any pointers would be greatly appreciated.
Try changing your url to the following and you should see the page: http://www.bmcmusicgroup.com/management/index/chat. The URL you entered (http://www.bmcmusicgroup.com/management/chat) decomposes like so:
Module: management;
Controller: chat;
Action: index
I have two modules Admin and Login.
I want to display the Login view 'login.phtml' within the admin view 'index.html'
I have the following in the Admin modules indexAction controller
public function indexAction()
{
$login = new LoginController();
$view = new ViewModel(array(
'theloginform' => $login->loginAction(),
));
return $view;
}
In the LoginAction method in the Login controller I return the ViewModel for the 'login.phtml' file.
public function LoginAction() {
$view = new ViewModel();
return $view;
}
The indexAction throws an error as the variable 'theloginform' is an object.
Catchable fatal error: Object of class Zend\View\Model\ViewModel could not be converted to string in...
If i add the following:
$authentication->loginAction()->captureTo('test')
The 'index.phtml' shows a string "content".
I have read that i may need to render the ViewModel before i assign it to the view variable 'theloginform', but i can't seem to get it to work, i have tried the following with no luck.
public function LoginAction() {
$view = new ViewModel();
$renderer = new PhpRenderer();
$resolver = new Resolver\AggregateResolver();
$map = new Resolver\TemplateMapResolver(array(
'login' => __DIR__ . '/../view/login.phtml'
));
$resolver->attach($map);
$view->setTemplate("login");
return $renderer->render($view);
}
If get the following error:
Zend\View\Renderer\PhpRenderer::render: Unable to render template "login"; resolver could not resolve to a file
I have even tried adding the DI into the autoload_classmap.php file but still get the same error, i have double checked the login.phtml file is at the correct path:
'/Login/view/login/login/login.phtml' I even copied it to '/Login/src/Login/view/login.phtml'
Very confused have read then re-read the Zend documentation, i just want to pass a view to another view...
If you need share some view content you can use partials for that:
$this->partial('partial/login.pthml', array()); //add this to your index view
you can read about them here
You may also find some usefull information: How does Zend Framework 2 render partials inside a module?
As per this zf2 documentaion page
Write this in login Action:
public function loginAction()
{
return new ViewModel();
}
And in indexAction :
$view = new ViewModel(
array(
//here any thig you want to assign to index view
)
);
$loginView = new ViewModel(
array(
//here any thig you want to assign to login view
)
);
$loginView->setTemplate('moduleName/controllerName/login');
$view->addChild($loginView, 'login');
return $view
In index.phtml you can just echo login <? echo $this->login ?> where ever you want to display loginView.
In ZF 1.x I would likely recommend you build an action helper that is referenced to a view placeholder or a controller plugin that calls back to loginAction for the form logic.
In Zf2 it looks like action helpers have been replaced by controller plugins and seem to be triggered through the event manager and may need to be aware of one or more of the "managers". However the placeholder view helper still exists and even seems somewhat familiar.
I would suggest you look into building/adapting a controller plugin for your login form display that can then be attached to a placeholder view helper. You might be able to get the required functionality with just a view helper, if you're lucky.
I wish I could help more, but I'm still wading through this mess myself.
Good luck.
In you admin view you have to use the render view helper and echo the script rendered, so you can do echo $this->render($this->theloginform);