Redirect in Front Controller plugin Zend - zend-framework

I'm trying to centralise my redirects (based on authentication and various other states) into a front controller plugin. So far I've tried:
$this->setRequest(new Zend_Controller_Request_Http('my_url'));
at various points in the plugin (i.e. from routeStartup to dispatchLoopShutdown) and also:
$this->setResponse(new Zend_Controller_Response_Http('my_url'));
Can anyone offer some assistance on this, or point me in the direction of a tutorial?

The easiest way would be to use ZF's Redirect ActionHelper
$r = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
$r->gotoUrl('/some/url')->redirectAndExit();
Alternatively instantiate it without the HelperBroker
$r = new Zend_Controller_Action_Helper_Redirector;
$r->gotoUrl('/some/url')->redirectAndExit();
The ActionHelper provides an API solely concerned about redirecting through a number of methods, like gotoRoute, gotoUrl, gotoSimple, which you can use depending on your desired UseCase.
Internally, the ActionHelper uses the APIs of Response and Router to do the redirect though, so you can also use their methods directly, e.g.
$request->setModuleName('someModule')
->setControllerName('someController')
->setActionName('someAction');
or
$response->setRedirect('/some/url', 200);
Further reading:
http://devzone.zend.com/article/3372-Front-Controller-Plugins-in-Zend-Framework
http://framework.zend.com/manual/en/zend.controller.actionhelpers.html
http://framework.zend.com/manual/en/zend.controller.response.html
http://framework.zend.com/manual/en/zend.controller.plugins.html
http://framework.zend.com/apidoc/core
http://framework.zend.com/svn/framework/standard/trunk/library/Zend/Controller/

If you are looking to redirect if the user is not logged it, the first parameter of dispatchLoopStartup() is a handle to the request object.
public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
{
if(!Zend_Auth::getInstance()->hasIdentity())
{
$request->setControllerName('auth');
$request->setActionName('login');
// Set the module if you need to as well.
}
}

If you want to redirect in the index page then this should suffice.
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
if(!Zend_Auth::getInstance()->hasIdentity())
{
$baseUrl = new Zend_View_Helper_BaseUrl();
$this->getResponse()->setRedirect($baseUrl->baseUrl());
}
}
If you want to redirect somewhere else then just change the parameter in the setRedirect() function
Thanks!
:)

Related

{guzzle-services} How to use middlewares with GuzzleClient client AS OPPOSED TO directly with raw GuzzleHttp\Client?

My middleware need is to:
add an extra query param to requests made by a REST API client derived from GuzzleHttp\Command\Guzzle\GuzzleClient
I cannot do this directly when invoking APIs through the client because GuzzleClient uses an API specification and it only passes on "legal" query parameters. Therefore I must install a middleware to intercept HTTP requests after the API client prepares them.
The track I am currently on:
$apiClient->getHandlerStack()-push($myMiddleware)
The problem:
I cannot figure out the RIGHT way to assemble the functional Russian doll that $myMiddleware must be. This is an insane gazilliardth-order function scenario, and the exact right way the function should be written seems to be different from the extensively documented way of doing things when working with GuzzleHttp\Client directly. No matter what I try, I end up having wrong things passed to some layer of the matryoshka, causing an argument type error, or I end up returning something wrong from a layer, causing a type error in Guzzle code.
I made a carefully weighted decision to give up trying to understand. Please just give me a boilerplate solution for GuzzleHttp\Command\Guzzle\GuzzleClient, as opposed to GuzzleHttp\Client.
The HandlerStack that is used to handle middleware in GuzzleHttp\Command\Guzzle\GuzzleClient can either transform/validate a command before it is serialized or handle the result after it comes back. If you want to modify the command after it has been turned into a request, but before it is actually sent, then you'd use the same method of Middleware as if you weren't using GuzzleClient - create and attach middleware to the GuzzleHttp\Client instance that is passed as the first argument to GuzzleClient.
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Command\Guzzle\GuzzleClient;
use GuzzleHttp\Command\Guzzle\Description;
class MyCustomMiddleware
{
public function __invoke(callable $handler) {
return function (RequestInterface $request, array $options) use ($handler) {
// ... do something with request
return $handler($request, $options);
}
}
}
$handlerStack = HandlerStack::create();
$handlerStack->push(new MyCustomMiddleware);
$config['handler'] = $handlerStack;
$apiClient = new GuzzleClient(new Client($config), new Description(...));
The boilerplate solution for GuzzleClient is the same as for GuzzleHttp\Client because regardless of using Guzzle Services or not, your request-modifying middleware needs to go on GuzzleHttp\Client.
You can also use
$handler->push(Middleware::mapRequest(function(){...});
Of sorts to manipulate the request. I'm not 100% certain this is the thing you're looking for. But I assume you can add your extra parameter to the Request in there.
private function createAuthStack()
{
$stack = HandlerStack::create();
$stack->push(Middleware::mapRequest(function (RequestInterface $request) {
return $request->withHeader('Authorization', "Bearer " . $this->accessToken);
}));
return $stack;
}
More Examples here: https://hotexamples.com/examples/guzzlehttp/Middleware/mapRequest/php-middleware-maprequest-method-examples.html

Silverstripe Login params

Im trying to style my login page. My login url is website/Security/login. Im trying to locate the 'login' piece of the url. What have i done wrong below?
public function DisplayPageType() {
$param = $this->request->param('Action');
if ($param === 'login')
{
return 'Login';
}
Thanks
I think that won't work since the controller during render is the Page_Controller and not the Security controller. So the $Action param is not equal to login. It could be index, I'm not sure.
If you just want to check if you're in the login page, you can add this to your Page_Controller:
public function getIsLoginPage()
{
return $_REQUEST['url'] == '/Security/login';
}
Then in your template:
<body class="<%if $IsLoginPage %>login-page<% end_if %>">
A bit dirty but it's the quickest way I know.
Another way is to leverage SilverStripe's legacy support. You can add a css file called tabs.css at mysite/css/tabs.css. If this file exists, SilverStripe will include this in the page.
You can also create templates that SilverStripe will automatically use if they exist:
themes/<theme_name>/Security.ss - If you want your login page to use an entirely different layout.
themes/<theme_name>/Layout/Security_login.ss - If you want to change just the content part (the $Layout section)
I hope this helps.
#gpbnz is right, the $Action param is not equal to login, it actually returns null as accessing $this->request from the Page_Controller when accessing the Security/login returns a NullHTTPRequest.
To get the action, you will want to get the current controller using Controller::curr(). It is then as simple as calling getAction on this controller.
To confirm that the action isn't from a random controller that happens to have an action called login, you can check the instanceof the controller like so: Controller::curr() instanceof Security
This check will still allow it to work for any controller that extends Security though which may/may not happen depending on the project.
I would stick away from actually reading the URL for the information manually though as that can create issues with maintainability in the future.
To bring this to a nice little function:
public function isLoginPage()
{
$controller = Controller::curr();
return $controller instanceof Security && $controller->getAction() == 'login';
}
Otherwise #gpbnz had a good suggestion of using the template system to your advantage for overriding not only the styles but the HTML around it.

Zend Framework website.com/username

One of the application I am developing using Zend Framework requires the user's profile page to be accessed via website.com/username, while other pages should be accessed by website.com/controller_name/action_name
I am not too sure how can this be achieved, however, I feel this can be done with some tweaks in the .htaccess file.
Can someone here please help me out?
Many thanks in advance
As suggested before, you can use a custom route that will route single level requests. However, this will also override the default route. If you're using modules, this will no longer work example.com/<module>.
I have done this before but only for static pages. I wanted this:
example.com/about
instead of this:
example.com/<some-id>/about
while maintaining the default route so this still works
example.com/<module>
example.com/<controller>
The way I did this was using a plugin to test if my request could be dispatched. If the request could not be dispatched using the default route, then I would change the request to the proper module to load my page. Here is a sample plugin:
class My_Controller_Plugin_UsernameRoute extends Zend_Controller_Plugin_Abstract
{
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$dispatcher = Zend_Controller_Front::getInstance()->getDispatcher();
if (!$dispatcher->isDispatchable($request)) {
$username = $request->getControllerName();
$request->setModuleName('users');
$request->setControllerName('dashboard');
$request->setActionName('index');
$request->setParam('username', $username);
/** Prevents infinite loop if you make a mistake in the new request **/
if ($dispatcher->isDispatchable($request)) {
$request->setDispatched(false);
}
}
}
}
What about using Zend_Controller_Router_Route, look here the link http://framework.zend.com/manual/en/zend.controller.router.html#zend.controller.router.routes.standard.variable-requirements

using action helpers in Zend Framework 1.8

Hi am starting off with Zend Framework and have a question about action helpers. My first application is a simple authentication system (following a tutorial from a book). The registration and authentication seems to work fine but the redirect doesn't.
I have a customer controller that has this among others:
class CustomerController extends Zend_Controller_Action
{
// some code here......
public function authenticateAction()
{
$request = $this->getRequest();
if (!$request->isPost()) {
return $this->_helper->redirector('login');
}
// Validate
$form = $this->_forms['login'];
if (!$form->isValid($request->getPost())) {
return $this->render('login');
}
if (false === $this->_authService->authenticate($form->getValues())) {
$form->setDescription('Login failed, please try again.');
return $this->render('login');
}
return $this->_helper->redirector('index');
}
the authenticate url is http://localhost/customer/authenticate and this seems to work fine but it does not redirect. After authentication I get a blank page which looks like its taking me to the index and just sits there. I tried using '/index' instead but that did not help either. Do I need to do anything special to make the redirector helper work? I have a logout action which behaves the same.
You should call
$this->_helper->redirector('index');
without the return.
I found out there may be a problem with my setup. The code above is perfect, works on another computer.

How to access URL parameters in bootstrap

I'm trying to capture a URL parameter in my bootstrap file but after several attempts I'm not able to do it.
I've tried this but it does not work:
protected function _initGetLang() {
$frontController = Zend_Controller_Front::getInstance();
$lang= $frontController->getParam('lang');
}
Is this the right way to do it?
Thks.
You won't be able to access the request params from the bootstrap because it hasn't yet gone through the dispatch/routing process. I think you'd be better served by using a Controller Plugin, performing actions based on the URL is what they do best. Or if you absolutely have to do it in the bootstrap, getRequestUri() or $_GET is available, or you could write a quick script to parse the url yourself.
Edit:
I've done some silly stuff like this in the past before I figured out how plugins work:
/**
* Grab the module name without a request instance
*
* #return string The module name
*/
public static function getModuleName()
{
$uri = ltrim($_SERVER["REQUEST_URI"], "/");
$module = substr($uri, 0, strpos($uri, "/"));
return $module;
}
This would at least give you a module name that you could switch on in the bootstrap. You should be able to do anything you need with the plugins done correctly though.