简体   繁体   中英

Access current route name in Slim3 controller's class constructor

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.

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

    }
}

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!

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM