2013-11-28 124 views
15

Slim是否有可能在中間件內獲取當前路由?Slim PHP中間件路由

class Auth extends \Slim\Middleware{ 
    public function call(){ 
    $currentRoute = $this->app->getRoute(); // Something like this? 
    } 
} 

我知道你可以打電話$app->router()->getCurrentRoute()slim.before.dispatch鉤被調用後,但是當你從中間件稱之爲它返回一個非對象。任何幫助將不勝感激。

回答

19

是的,沒有。如果您查看Slim的源代碼,您會看到當調用Slim::run方法時,將按LIFO順序調用已註冊的中間件,然後Slim運行它自己的「調用」方法,在該方法中處理請求開始。在這種方法中,Slim解析並處理路線。在這種情況下,您不能在Middleware::call方法中訪問$app->router()->getCurrentRoute(),因爲它尚未被解析和定義。

要做到這一點的唯一方法是在您的中間件中註冊一個偵聽器slim.before.dispatch,並實現您想要在該方法中執行的任何操作。

從你的班級的名字我假設你正在嘗試創建一個基本的認證模塊?我做了一些類似的面前,它去是這樣的:

class AuthMiddleware extends \Slim\Middleware 
{ 
    public function call() 
    { 
     $this->app->hook('slim.before.dispatch', array($this, 'onBeforeDispatch')); 

     $this->next->call(); 
    } 

    public function onBeforeDispatch() 
    { 
     $route = $this->app->router()->getCurrentRoute(); 

     //Here I check if the route is "protected" some how, and if it is, check the 
     //user has permission, if not, throw either 404 or redirect. 

     if (is_route_protected() && !user_has_permission()) 
     { 
      $this->app->redirect('/login?return=' . urlencode(filter_input(INPUT_SERVER, 'REQUEST_URI'))); 
     } 
    } 
} 

在這個例子中,onBeforeDispatch方法處理程序被調用的路線之前運行。如果你看看源代碼,你可以看到這個事件在try/catch塊內被觸發,它正在監聽$app->redirect()$app->pass()等拋出的異常。這意味着我們可以在這裏實現我們的檢查/重定向邏輯,就好像這是一個路由處理函數。

以上is_route_protecteduser_has_permission只是僞代碼來說明我的認證中間件是如何工作的。我構造了這個類,以便您可以指定中間件構造函數中受保護的路由列表或路由正則表達式,以及傳遞實現用戶權限檢查的服務對象等。希望這有助於您。

+0

不錯的一個。感謝您提供整潔的解決方案和詳細的解釋。 在中間件的call()函數中註冊掛鉤是否適合它? 這似乎是因爲它保持整潔,只是想知道這是否會導致掛鉤被多次註冊/調用? – plong0

+3

我認爲可以安全地假定每個請求只會調用一次調用方法。實際上,這歸結於鏈中的前一箇中間件的實現,因爲設計使用單個鏈接列表,每個中間件都會調用下一個中間件。如果一箇中間件調用鏈式調用方法中的下一個,雖然我會建議它的Doing It Wrong™,你應該停止使用它:)。 –

+0

謝謝,這是工作 – mapodev

2

您應該使用app-> request() - > getPathInfo()而不是app-> getRoute()。

class Auth extends \Slim\Middleware{ 
    public function call(){ 
     $currentRoute = $this->app->request()->getPathInfo(); 
    } 
} 
3

有一種替代方法可以做到這一點,因爲我一直處於相同的情況。我想避免被匹配的路線任何東西,想用路由名稱代替,所以你可以嘗試以下方法:

public function call() { 

    $routeIWantToCheckAgainst = $this->slimApp->router()->urlFor('my.route.name'); 
    $requestRoute = $this->slimApp->request()->getPathInfo(); 
    if ($routeIWantToCheckAgainst !== $requestRoute) { 
     // Do stuff you need to in here 
    } 

    $this->next->call(); 
} 

你甚至可以擁有的路由數組,你不希望在中間件上運行然後只是檢查它是否in_array()等,如果沒有,做你需要的。