分析 Routing(4)
今天要接著來看,是如何設定各式各樣的 route 了。先來看 get()
與 post()
的原始碼:
public function get($uri, $action = null) |
這裡可以知道,實際做事的是 addRoute()
:
public function addRoute($methods, $uri, $action) |
RouteCollection::add()
是新增一筆 Route 並把該 Route 實例回傳。這樣的設計是為了讓後面的 fluent pattern 可以更加直觀:
Route::get('/', function() { |
createRoute()
則是建立 Route 實例:
protected function createRoute($methods, $uri, $action) |
順帶一提,可以發現 Laravel 在撰寫主要邏輯時,都會寫的比較白話;當追查後面實作才會覺得比較「技術」。
actionReferencesController()
的任務是確認 Action 是不是指向 Controller:
protected function actionReferencesController($action) |
轉換成 array 是呼叫 convertToControllerAction()
:
protected function convertToControllerAction($action) |
prependGroupNamespace()
裡面有一段判斷可以看一鑑:
return isset($group['namespace']) && strpos($class, '\\') !== 0 |
isset($group['namespace'])
應該不用多解釋,有趣的地方是 strpos($class, '\\') !== 0
,這代表如果 Controller 給絕對路徑的 namespace 的話,是不會受到 group 的 namespace 影響的。假設我有一個 Controller,完整類別名為 \App\Http\Controllers\HelloController
則下面兩個是等價的:
文件其實沒有講到這個用法,要翻原始碼才會知道
// 假設預設 namespace 是 App\Http\Controllers |
準備好 Action 後,就可以建構 Route 實例了。建構完 Route,會確認有沒有 group stack,有的話就呼叫 $this->mergeGroupAttributesIntoRoute()
合併 group stack 設定到 Route 實例裡
protected function mergeGroupAttributesIntoRoute($route) |
最後,呼叫 addWhereClausesToRoute()
把 global where 設定加進 Route 實例裡。
protected function addWhereClausesToRoute($route) |
這裡其實就是實作 Global Constraints 的功能。為何下面的 pattern()
設定會變成全域有效,就是上面這段程式碼實作出來的。
Route::pattern('id', '[0-9]+'); |
同時也可以知道 Route 所設定的 where 是 array 多筆的形式。
到目前為止,Router 跟設定有關的程式碼都看的差不多了,我們可以發現 Router 本身跟設定相關最核心的任務,其實就是產生 Action 並建構 Route 實例。而 Route 實例也不存放在 Router,而是放在 RouteCollection。這就是標準的 facade pattern,所有控制後面角色行為的互動,都可以靠 facade,也就是 Router 來處理;而且,facade pattern 的一個特色是,因為這三天已經知道必要的參數是哪些了,所以是可以繞過 Router 自己來處理的。
明天再來繼續看 Route 如何存放與處理 Action 的資訊。