【问题标题】:Access current route name in Slim3 controller's class constructor在 Slim3 控制器的类构造函数中访问当前路由名称
【发布时间】:2016-01-18 16:39:20
【问题描述】:

我使用 Slim 对我的控制器进行分组,并且通常为每个组扩展一个抽象的 BaseController。我使用基于类的路由:

/* 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');

并且需要密码保护某些路由,有时我需要稍微不同的配置。 BaseApiController、BaseAdminController... 等等。有时我需要知道我在哪条路由中,以便我可以针对该路由执行某种行为。在这些情况下,我会有一个这样的辅助函数:

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

这会给我当前正在使用的路线名称。所以我可以做类似...

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'));
        }
    }
}

我找不到访问正在执行的路由名称的方法。我找到了这个链接

Slim 3 get current route in middleware

但是当我尝试时得到 NULL

$request->getAttribute('routeInfo');

我也尝试过建议的:

'determineRouteBeforeAppMiddleware' => true

我已经检查了每个 Slim3 对象的属性和方法,我似乎找不到 Slim3 的等价物,或者无法访问命名路由。看起来 Slim3 甚至没有跟踪它执行的路线,它只是......执行它。

这些是路由器类具有的以下方法,我怀疑这个值会在哪里:

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

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

我希望有人做过类似的事情。当然,还有其他一些我可以做到这一点的 hacky 方法(一些我现在已经在考虑),但我更喜欢使用 Slim 来给我这些数据。有什么想法吗?

注意:我知道您可以使用中间件来做到这一点,但是我正在寻找一种不需要中间件的解决方案。我可以在触发路由实例化的类中使用的东西。 Slim2 可以,希望 Slim3 也有类似的功能。

【问题讨论】:

    标签: php slim slim-3


    【解决方案1】:

    它可以通过request 对象获得,如下所示:

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

    更多详情here

    您的控制器中的方法都将接受请求和响应作为参数 - slim 会为您传递它们,例如在您的 insert() 方法中:

    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
    
        }
    }
    

    【讨论】:

    • 虽然这可以使用中间件工作,但它在触发路由时实例化的类中不起作用。另外作为旁注,您必须将 'determineRouteBeforeAppMiddleware' 配置值设置为 true 才能在中间件中工作。不幸的是,这在我的情况下不起作用
    • @Eko3alpha 我已经更新了我的答案,详细说明了如何在控制器中访问$request。我不是苗条的专家,所以可能有更好的方法,但我就是这样做的。
    • 一些事情......当路由实例化一个类时,在您的示例 UserApiController 中,它将 Slim\Container 的实例传递给类 __constructor,然后执行插入方法。然而,Slim3 默认为每个方法传递 3 个参数,一个 Slim\Http\Request 对象、Slim\Http\Response 对象和路由中捕获的 {parameters} 数组(如果有)。 sn-p 中的 use 语句是多余的,因为第一个参数 Slim\Http\Request 已经实现了 \Psr\Http\Message\ServerRequestInterface。不幸的是,这对我的情况仍然没有帮助
    • 为了完整起见,我留下了命名空间别名和类型提示,主要是为了在接口被换出另一个实现时强制执行接口的完整性检查。您确实可以从容器中捕获请求,尽管我更喜欢显式注入 - 无论哪种方式,这都是捕获访问路由名称的请求的两种方法。我是否遗漏了有关您的控制器实现的某些内容,从而阻止了它对您的工作?
    • 好的,所以我做了一个测试 $request->getAttribute('route')->getName();在类方法中,它确实有效!非常感谢你的帮忙。但是,我需要在基本控制器的 __constructor 中使用该值。我正在尝试从 Slim\Container 访问它,因为我可以从那里获取请求和响应对象。但是那些路由属性不在那里。所以在类方法中它有效,在 __constructor 它没有:(
    【解决方案2】:

    在玩了一圈之后,我找到了一种方法。这可能不是最有效的方式,但它确实有效,虽然它使用中间件来完成此任务,但我认为还有其他应用程序可以在中间件中与控制器类共享数据。

    首先您创建一个中间件,但您使用“Class:Method”字符串,就像在路由中一样。随意命名。

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

    然后是你的中间件:

    // 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);
        }
    }
    

    然后在您的路线中创建一个带有路线名称的路线,在这种情况下,我将使用“主页”作为名称

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

    在你的类控制器中

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

    这将允许您做更多的事情,而不仅仅是获取路由名称,您还可以将值从中间件传递给您的类构造函数。

    如果其他人有更好的解决方案,请分享!

    【讨论】:

    • 刚刚重温了一下,不知道可以用 Class:Method 连接中间件 - 非常方便
    • 仅供参考,在版本 3 中,您必须设置设置 'determineRouteBeforeAppMiddleware' => true 才能在中间件 slimframework.com/docs/v3/cookbook/… 中获取路由名称
    【解决方案3】:
    $app->getCurrentRoute()->getName();
    $request->getAttribute('route')->getName();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-25
      • 1970-01-01
      • 1970-01-01
      • 2010-11-03
      • 2022-06-16
      • 1970-01-01
      相关资源
      最近更新 更多