I'm using Zend Framework to build a website and I'm having some trouble with the dispatch loop.
Normally, Zend Framework URLs are built this way: http://www.domain.com/module/controller/action.
On my website, I'm using customized dynamic URLs which are parsed on the dispatch loop by a custom method. So, each one of these URLs, after being parsed, will execute a specific action of a specific controller and module.
I need to perform some tasks which depend on the module, controller and action that were parsed. The problem is that I'm only being able to know the parsed module, controller and action when dispatchLoopShutdown occurs. The tasks that I need to execute will set some cookies which will make changes on the output that will be sent to the browser.
But, at this point, the view has already been rendered, and the cookies that were set when dispatchLoopShutdown occurs won't change the output accordingly.
So, my question is... is there a way to force the view to be rendered again? Or a way to know what module, controller and action will be executed, before the dispatchLoopShutdown? I've also tried to accomplish this on the postDispatch but the results are the same!
Hope I could explain my problem right.
Thank you for your help.
Here is a good schema about the Zend Framework sequence.
You can know the module, controller and action before the dispatch by using a controller plugin:
<?php
class Custom_Controller_Plugin_CheckRoute extends Zend_Controller_Plugin_Abstract
{
public function preDispatch($request)
{
//Get Request
$controller = $request->controller;
$action = $request->action;
$module = $request->module;
//=> perform actions before dispatch
//Update the Request
$request->setModuleName('default')
->setControllerName('index')
->setActionName('action2');
}
}
?>
I had the same problem. It was solved by Zend_Controller_Plugin_ActionStack. I added some action where implemented logic from dispatchLoopShutdown. This link can be useful http://framework.zend.com/manual/1.12/en/zend.controller.plugins.html#zend.controller.plugins.standard.actionstack
Related
I working in zend 1 and I want to do this. If anybody call http://example.com/fruits/apple, then I want to redirect to http://example.com/pen/apple.
I am already using this code to perform this.
resources.router.routes.pen.type = "Zend_Controller_Router_Route_Static"
resources.router.routes.pen.route = "pen/apple"
resources.router.routes.pen.defaults.controller = "fruits"
resources.router.routes.pen.defaults.action = "apple"
But if I have 20 actions, then I need to do this for all actions.
I want a single code to redirect to another controller with the same action in Zend Framework 1.
To achieve this result you should write a Action Plugin, then register it.
Plugin will run for each request and you can attach your functionality at a specific point in the dispatch process, here's the doc https://framework.zend.com/manual/1.10/en/zend.controller.plugins.html .
The strategy you should use is at pre dispatch, check the controller within the current request and if the controller is 'fruit' change it with 'pen'.
I have a large application using SF 3.4 and I need to find a better way to do custom rendering based on user on each page load.
Right now we have listeners for a side menu, a footer, side menu favorites, an application menu, and whether or not you are timed out. These listeners fire a theme event via the render function that adds information pertaining to the users access/favorites/if they are timed out. This cannot be done with roles in twig because we have things like menu favorites that change all the time.
We override the Controller render method to dispatch that theme event and array_merge what we get back with the render function's parameter array like this:
protected function render($view, array $parameters = array(), Response $response = null)
{
$themeEvent = new ExampleThemeEvent($this->getUser(), $this->getMyMenuApplication());
$result = $this->getDispatcher()->dispatch(ExampleThemeEvent::NAME, $themeEvent);
$parameters = array_merge($result->getModel(),$parameters);
return parent::render($view, $parameters, $response);
}
Because of this most of our Controllers extend ExampleThemeController instead of just Controller so every page we want to have these features does.
This works fine, but the render method has been marked final as of SF 3.4 and shouldn't be overridden. What would be the best way to approach this without overriding the render method? Is there another place I can dispatch our theme event?
We have tried onKernelController subscribers/listeners to no avail because we need to add the extra view parameters to the container which cannot be done at that point.
Thank you!
For such user-specific changes that go beyond passing globals to twig, I'd check out embedding controllers. You can render a part of your response with a different controller, responsible only for the favourites for example.
In Zend Framework whats a better method to restrict user from accessing post login pages
if the user is not logged in.Without Zend I would have write a code to check if the
userid is set in session or not and put that code in common file(being used on all post
login pages).
In Zend Framework I can check that using hasIdentity method of zend_auth but I don't
want to check that inside all actions.The another method I am thinking is to create a
plugin and hook it to routeshutdown event,then after fetching controller and action
name from request object I can decide whether to redirect user or not.
Please suggest some good method to implement it in zend framework
You would normally write a Controller Plugin and add it to the front controller. This way you can intercept the dispatch and route process where you want and issue a redirect to an appropriate page.
class Your_Controller_Plugin_Authcheck extends Zend_Controller_Plugin_Abstract
{
}
In the Bootstrap class:
protected function _initFrontControllerPlugins()
{
$this->bootstrap(array('AuthcheckPlugin', 'FrontController'));
$front = $this->getResource('FrontController');
$front->registerPlugin($this->getResource('AuthcheckPlugin'));
}
protected function _initAuthcheckPlugin()
{
$plugin = new Your_Controller_Plugin_Authcheck();
return $plugin;
}
BTW: This is Zend Framework 1 - might work the same in 2, but I believe you might change things a bit there if you already use it.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the difference between redirect and forward in Zend framework
I'm new to zend framework, when i try to use foward, redirect, setViewRender in controller, what are their diffences?
As the official docs say:
_forward($action, $controller = null, $module = null, array $params = null): perform another action. If called in preDispatch(), the
currently requested action will be skipped in favor of the new one.
Otherwise, after the current action is processed, the action
requested in _forward() will be executed.
_redirect($url, array $options = array()): redirect to another location. This method takes a URL and an optional set of options. By
default, it performs an HTTP 302 redirect.
Read more to understand it better.
i'm pretty sure that a redirect redirects you to a particular page/ controller therefore going through all of the pre view processes including if you can view the page, setViewRender will just output the view you have selected and disregard all of the stuff the controller etc handles. (i haven't used zend for a while however)
_redirect creates a completely new http request, where as _forward simply forwards the request. I realized this when setting a variable in zend_registry, well this might sound a little off the track but when you use _request all the request variables and headers and registry variables are completely reset where as in case of _forward it simply forwards all those things. This is like you can have previously provided information along with some more information in case of _forward.
Well for setViewRenderer I really like this idea, I mean this is something like dependency injection. You dont really need to have a default view, you could provide a new view for the given action. I think you would get the best answer if you look into this.
_forward is an internal redirect. Where as _redirect sends a header that tells the client's browser to go to some other URL, _forward tells the Dispatcher to internally redirect the request somewhere else.
If you consider the normal dispatch order of:
preDispatch()
someAction()
anotherAction()
postDispatch()
Calling _forward at any point in that progression will cause the following steps to not be executed. So if you call _forward in preDispatch(), someAction() will not be called and so on. If you _forward() in someAction() and you are using the viewRenderer action helper to render your views (you are letting the framework choose what view script to render), then no view script will be rendered in someAction().
When the request is forwarded to the new Controller / Module the entire dispatch process will be repeated there.
Note:
If you forward inside someAction() to anotherAction() you must do it like this
return $this->_forward('another');
You should add a return to $this->_forward() or your current Action will continue to execute before forwarding to the other Action.
Also note that the view that will be rendered will be another.phtml
While when doing a redirect, ZF would instruct the browser to load http://example.com/controller-name/action-name as _redirect() sends a header, meaning you create a new HTTP Request and go through the entire dispatch process with it.
Last to render a certain view inside an action use the viewRenderer Action helper:
// Bar controller class, foo module:
class Foo_BarController extends Zend_Controller_Action
{
public function addAction()
{
// Render 'bar/form.phtml' instead of 'bar/add.phtml'
$this->_helper->viewRenderer('form');
}
public function editAction()
{
// Render 'bar/form.phtml' instead of 'bar/edit.phtml'
$this->_helper->viewRenderer->setScriptAction('form');
}
public function processAction()
{
// do some validation...
if (!$valid) {
// Render 'bar/form.phtml' instead of 'bar/process.phtml'
$this->_helper->viewRenderer->setRender('form');
return;
}
// otherwise continue processing...
}
}
I call an action helper in one of my views using the following code
echo $this->action('foo', 'bar');
The fooAction in the barController does its thing and outputs a list of pages. However, the list has the layout in the output again, which is mightily irritating. If I disable the layout in the fooAction, this causes layout to be completely disabled on the live side, as well.
I'm vexed. I could just create a view helper, and there are many ways around this, but out of curiousity I was wondering if anyone had a solution to this.
From the ZF Reference Guide on Action ViewHelper
The API for the Action view helper follows that of most MVC components that invoke controller actions: action($action, $controller, $module = null, array $params = array()). $action and $controller are required; if no module is specified, the default module is assumed.
Modify your controller to accept a param that controls whether the action should disable the layout. When using the action helper, pass this control flag.
On a sidenote: using the Action ViewHelper is considered bad practise as it will go through the entire dispatch process again and this will slow down your app. If possible, try to access the model directly.