Getting $_GET parameters from route in Zend Framework 2
Asked Answered
D

3

7

Zend Framework 1 had a very simple way of parsing URL routes and setting found params in the $_GET superglobal for easy access. Sure, you could use ->getParam($something) inside the controller, but if the param was found in the URL, it was also accessible via $_GET.

Example for url mypage.com/mymodule/mycontroller/myaction/someparam/5:

ZF1

$this->getParam('someparam'); // 5
$_GET['someparam']; // 5

ZF2

$this->getEvent()->getRouteMatch()->getParam('someparam'); // 5
$_GET['someparam'] // undefined index someparam

Obviously, the difference is that ZF2 does NOT put the route params into the $_GET superglobal.

How do I make it put the parsed parameters into the $_GET superglobal, since extending the controller and just defining a constructor that does that is out of the question (because RouteMatch is not an object yet and cannot be called from the controller's constructor)?

Calling $_GET = $this->getEvent()->getRouteMatch()->getParam('someparam'); in every one of my controllers would work, but I don't want that.

In other words, following the example URL from above, I want to be able to do $_GET['someparam'] and still get the value "5" in any component in the application.

Edit: Looks like I wasn't clear enough, so I'll try to clarify some more. I want whatever param I enter in the URL via /key/value formation to be available in $_GET instantly. I don't really have a problem with getting the param, I know how to get it and I extended Zend's controller so I can just call $this->getParams again like in ZF1, and now all controllers extend that one, I just want the params from the URL to automatically be in $_GET as well, so I can access them easily in third party components which use $_GET natively.

Edit 2: Updated as reaction to Samuel Herzog's answer: I don't really mind invalidating the SRP in this case, because the libraries are built in such a way that they need direct access to $_GET - they do their own filtering and directly depend on this superglobal. They also directly fetch $_FILES and $_POST for processing, it's just the way their code works.

I've made the following method in the abstract controller: $this->mergeGet(); which basically makes $_GET absorb all the route matched params and everything works as intended, but seeing as the libraries will be required in every controller/action, it might get tedious to call that method every time. If only the controller had an init() method like in ZF1...

Doubletongued answered 5/8, 2012 at 23:11 Comment(3)
Not sure enough for an answer, try ->params('key', $defaultValue) on either the Controller or Request, i think this is the one you're looking for.Stacey
I have no problem fetching the param, my worry is a different one. Please see edited questionDoubletongued
@Stacey its Controller::Params('key', $default) which calls a Controller Plugin (Params) to prevent you from writing Controller::getEvent()->getRouteMatch()->getParam(...).Mesognathous
M
8

First of all, you shouldn't use $_GET or any other superglobal directly if you're building on an object oriented stack. The SRP is invalidated this way.

If you have no possibility to change the way of your (3rd party?) librarys to change you might want to hook into the MvcEvent, listen to --event-- and then get the RouteMatch, you may fill $_GET with a simple loop.

For a most-performant answer, you should know if the named library will be needed for every action, just for one module, or only in certain controllers/actions. If the latest is your use-case, you should write a controller plugin instead.

some example code for the first approach:

namespace YourModule;
use Zend\EventManager\EventInterface as Event;
use Zend\Mvc\MvcEvent;

class Module
{
    ...

    public function onBootstrap(Event $ev)
    {
        $application = $e->getApplication();
        $eventManager = $application->getEventManager();

        $eventManager->attach('route', function(MvcEvent $mvcEvent) {
            $params = $mvcEvent->getRouteMatch()->getParams();

            foreach ( $params as $name => $value )
            {
                if ( ! isset($_GET[$name]) 
                {
                    $_GET[$name] = $value;
                }
            }
        });
    }
}
Mesognathous answered 6/8, 2012 at 17:14 Comment(9)
Thanks for the update @Swader, each Modules onBootstrap event gets called on every request. So if there is a request /shop/product/milk and the sample code is in the Application but not the Shop module it will be called regardless! listening to the route event at one central place (Your Application/Module.php) will do the trick perfectly.Mesognathous
Ok, this is typical ZF, there is zero documentation on how to listen to the bootstrap event in the Module class, could you drop me a hint please? Perhaps put it in the answer so I can mark it as accepted if it does what I want it to do?Doubletongued
Documentation is in progress, thats why it's only RC atm ;) The code i provide does exactly this. see: $eventManager->attach('route', function(MvcEvent $e) { ... just an anonymous function as listener attached.Mesognathous
See my answer here https://mcmap.net/q/1475768/-how-do-i-access-a-routed-parameter-from-inside-a-controller for easier and up to date param fetching.Whittington
Ah, but curiously it gives me this: Fatal error: Call to undefined method Zend\Mvc\Router\Http\TreeRouteStack::getRouteMatch() in /Users/swader/Sites/stm/module/Application/Module.php on line 23, the same error as if I had tried to call the $_GET merge inside the constructor of the main controller abstract.Doubletongued
ouch, my bad. There is no need to access the router first, it's just $e->getRouteMatch()->getParams(); see the Docs on MvcEvent. As the route-Event is thought for routers you maybe want to listen at very low priority (e.g. -1000) or listen to dispatch (the route is definitly set) with very high priority instead.Mesognathous
@Sam, can you please explain more why SRP is invalidated when using GET?Crosseyed
can anyone explain why SRP is invalidated when using raw GET?Crosseyed
@Crosseyed Knowing about the channel for parameters is a responsibility, you likely want this in a dedicated class. If you use raw GET, you'll couple all your classes to this input method. If you need to validate or transform the GET variables, you'll then have validation/transformation wherever you've used GET, thereby adding additional responsibility to all these classes.Mesognathous
M
13

In ZF2, Im using this

$getparams = $this->getRequest()->getQuery();
Mishear answered 15/1, 2013 at 3:3 Comment(0)
M
8

First of all, you shouldn't use $_GET or any other superglobal directly if you're building on an object oriented stack. The SRP is invalidated this way.

If you have no possibility to change the way of your (3rd party?) librarys to change you might want to hook into the MvcEvent, listen to --event-- and then get the RouteMatch, you may fill $_GET with a simple loop.

For a most-performant answer, you should know if the named library will be needed for every action, just for one module, or only in certain controllers/actions. If the latest is your use-case, you should write a controller plugin instead.

some example code for the first approach:

namespace YourModule;
use Zend\EventManager\EventInterface as Event;
use Zend\Mvc\MvcEvent;

class Module
{
    ...

    public function onBootstrap(Event $ev)
    {
        $application = $e->getApplication();
        $eventManager = $application->getEventManager();

        $eventManager->attach('route', function(MvcEvent $mvcEvent) {
            $params = $mvcEvent->getRouteMatch()->getParams();

            foreach ( $params as $name => $value )
            {
                if ( ! isset($_GET[$name]) 
                {
                    $_GET[$name] = $value;
                }
            }
        });
    }
}
Mesognathous answered 6/8, 2012 at 17:14 Comment(9)
Thanks for the update @Swader, each Modules onBootstrap event gets called on every request. So if there is a request /shop/product/milk and the sample code is in the Application but not the Shop module it will be called regardless! listening to the route event at one central place (Your Application/Module.php) will do the trick perfectly.Mesognathous
Ok, this is typical ZF, there is zero documentation on how to listen to the bootstrap event in the Module class, could you drop me a hint please? Perhaps put it in the answer so I can mark it as accepted if it does what I want it to do?Doubletongued
Documentation is in progress, thats why it's only RC atm ;) The code i provide does exactly this. see: $eventManager->attach('route', function(MvcEvent $e) { ... just an anonymous function as listener attached.Mesognathous
See my answer here https://mcmap.net/q/1475768/-how-do-i-access-a-routed-parameter-from-inside-a-controller for easier and up to date param fetching.Whittington
Ah, but curiously it gives me this: Fatal error: Call to undefined method Zend\Mvc\Router\Http\TreeRouteStack::getRouteMatch() in /Users/swader/Sites/stm/module/Application/Module.php on line 23, the same error as if I had tried to call the $_GET merge inside the constructor of the main controller abstract.Doubletongued
ouch, my bad. There is no need to access the router first, it's just $e->getRouteMatch()->getParams(); see the Docs on MvcEvent. As the route-Event is thought for routers you maybe want to listen at very low priority (e.g. -1000) or listen to dispatch (the route is definitly set) with very high priority instead.Mesognathous
@Sam, can you please explain more why SRP is invalidated when using GET?Crosseyed
can anyone explain why SRP is invalidated when using raw GET?Crosseyed
@Crosseyed Knowing about the channel for parameters is a responsibility, you likely want this in a dedicated class. If you use raw GET, you'll couple all your classes to this input method. If you need to validate or transform the GET variables, you'll then have validation/transformation wherever you've used GET, thereby adding additional responsibility to all these classes.Mesognathous
R
1

You could use in your controlller:

 $paramValue = $this->params()->fromQuery('your_param_here');

Regards

Remde answered 27/5, 2016 at 1:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.