3

With Slim I group my controllers and generally have an abstract BaseController I extend for each group. I use class based routing:

/* SLIM 2.0 */
// Users API - extends BaseApiController
$app->post('/users/insert/'   , 'Controller\Api\UserApiController:insert');
.
.
// Campaigns - extends BaseAdminController
$app->get('/campaigns/', 'Controller\CampaignController:index')->name('campaigns');

and needed to password protect some routes, at other times I needed to have a slightly different configuration. BaseApiController, BaseAdminController... etc. There were times I needed to know which route I was in so I could execute a certain behavior for just that route. In those cases I would have a helper function like so:

/* SLIM 2.0 */
// returns the current route's name
function getRouteName()
{
    return Slim\Slim::getInstance()->router()->getCurrentRoute()->getName();
}

This would give me the route name that is currently being used. So I could do something like...

namespace Controller;
abstract class BaseController
{
    public function __construct()
    {
        /* SLIM 2.0 */
        // Do not force to login page if in the following routes
        if(!in_array(getRouteName(), ['login', 'register', 'sign-out']))
        {
            header('Location: ' . urlFor('login'));
        }
    }
}

I cannot find a way to access the route name being executed. I found this link

Slim 3 get current route in middleware

but I get NULL when I try

$request->getAttribute('routeInfo');

I have also tried the suggested:

'determineRouteBeforeAppMiddleware' => true

I've inspected every Slim3 object for properties and methods, I can't seem to find the equivalent for Slim3, or get access to the named route. It doesn't appear that Slim3 even keeps track of what route it executed, it just... executes it.

These are the following methods the router class has and where I suspect this value would be:

//get_class_methods($container->get('router'));

setBasePath
map
dispatch
setDispatcher
getRoutes
getNamedRoute
pushGroup
popGroup
lookupRoute
relativePathFor
pathFor
urlFor

I was hoping someone has done something similar. Sure, there are other hacky ways I could do this ( some I'm already contemplating now ) but I'd prefer using Slim to give me this data. Any Ideas?

NOTE: I'm aware you can do this with middleware, however I'm looking for a solution that will not require middleware. Something that I can use inside the class thats being instantiated by the triggered route. It was possible with Slim2, was hoping that Slim3 had a similar feature.

Eko3alpha
  • 540
  • 6
  • 16

3 Answers3

4

It's available via the request object, like this:

$request->getAttribute('route')->getName();

Some more details available here

The methods in your controller will all accept request and response as parameters - slim will pass them through for you, so for example in your insert() method:

use \Psr\Http\Message\ServerRequestInterface as request;

class UserApiController {
    public function insert( request $request ) {

    // handle request here, or pass it on to a getRouteName() method

    }
}
danjam
  • 1,064
  • 9
  • 13
  • While this works using middleware it does not work inside the class that's being instantiated upon triggering the route. Also as a side note you must have 'determineRouteBeforeAppMiddleware' config value set to true in order for this to work in a middleware. Unfortunately this will not work in my case – Eko3alpha Jan 18 '16 at 18:38
  • @Eko3alpha I've updated my answer with more detail on how to access `$request` within your controller. I'm no slim expert so there may be a better way but this is how I do it. – danjam Jan 18 '16 at 19:31
  • A few things... When a route instantiates a class, in your example UserApiController, it passes an instance of Slim\Container to the class __constructor, then it executes the insert method. However Slim3 by default passes 3 parameters to every method, a Slim\Http\Request object, Slim\Http\Response object, and an array of captured {parameters} in the route (if any). The use statement in your snippet is redundant since the first parameter, Slim\Http\Request is already implementing \Psr\Http\Message\ServerRequestInterface. Unfortunately this still doesn't help in my situation – Eko3alpha Jan 18 '16 at 20:25
  • The namespace alias and type hinting I left in for completeness, mainly as a sanity check to enforce the interface if it's ever swapped out for another implementation. You can indeed capture the request from the container, though I prefer explicit injection - either way that's two methods to capture the request to access the route name. Am I missing something about your controller implementation that stops this working for you? – danjam Jan 18 '16 at 20:35
  • Ok, so I did a test of $request->getAttribute('route')->getName(); inside the class method and it does indeed work! So thank you for that. However, I need that value in the __constructor of the base controller. I'm trying to access it from the Slim\Container as I can get the request and response objects from there. But those route attributes aren't in there. So in the class method it works, in the __constructor it doesn't :( – Eko3alpha Jan 18 '16 at 20:35
  • Well I now see your problem - I can access request and route in the constructor easily enough but not get the route name from there... going to do some digging - I'll let you know if I find a solution as I'm now curious myself – danjam Jan 18 '16 at 20:59
  • I think the issue is the Slim\Http\Request Object in the Slim\Container being passed in the constructor is not the same instance of the Slim\Http\Request being passed in the method. I did a var_dump on both and their object reference ID's are different. I believe they could be 2 different instances in the Slim lifecycle? – Eko3alpha Jan 18 '16 at 21:05
  • You're right, the request is immutable. It looks like the request is recreated with the attributes needed after controller instantiation via the middleware stack when invoking the chosen controller method - sadly this means middleware is really the only way to go if you don't want to handle it in the controller's method. – danjam Jan 18 '16 at 21:29
4

After playing around I found a way to do it. It may not be the most efficient way but it works, and although it uses Middleware to accomplish this I think there are other applications for sharing data in the Middleware with controller classes.

First you create a middleware but you use a "Class:Method" string just like you would in a route. Name it whatever you like.

//Middleware to get route name
$app->add('\Middleware\RouteMiddleware:getName');

Then your middleware:

// RouteMiddleware.php

namespace Middleware;
class RouteMiddleware
{
    protected $c; // container

    public function __construct($c)
    {
        $this->c = $c; // store the instance as a property
    }

    public function getName($request, $response, $next)
    {
        // create a new property in the container to hold the route name
        // for later use in ANY controller constructor being 
        // instantiated by the router

        $this->c['currentRoute'] = $request->getAttribute('route')->getName();
        return $next($request, $response);
    }
}

Then in your routes you create a route with a route name, in this case I'll use "homePage" as the name

// routes.php
$app->get('/home/', 'Controller\HomeController:index')->setName('homePage');

And in your class controller

// HomeController.php
namespace Controller;
class HomeController
{
    public function __construct($c)
    {
     $c->get('currentRoute'); // will give you "homePage"
    }
}

This would allow you to do much more then just get a route name, you can also pass values from the middleware to your class constructors.

If anyone else has a better solution please share!

Eko3alpha
  • 540
  • 6
  • 16
  • Just revisited this, did not know it was possible to wire up middleware with Class:Method - very handy – danjam Feb 10 '16 at 16:34
  • FYI, in version 3, you have to set the setting `'determineRouteBeforeAppMiddleware' => true` to get route name in middleware https://www.slimframework.com/docs/v3/cookbook/retrieving-current-route.html – Christopher Chase Jun 24 '21 at 06:57
-1
$app->getCurrentRoute()->getName();
$request->getAttribute('route')->getName();
Tunaki
  • 132,869
  • 46
  • 340
  • 423