最適合入門的 Laravel 入門教程 (五)

白俊遙發表於2018-01-13

路由我們會建立了;
控制器也有了;
接下來要搞的就是把兩者關聯起來了;
最適合入門的laravel初級教程(三)
我們講過 Route 的 get 或者 post 方法第一個引數就是我們要定義的路由;
就是我們在位址列請求的那段url;
第二個引數可以是一個閉包函式;
裡面寫請求定義的路由時執行的內容;
上篇文章我們說過;
如果把程式碼都放這個閉包函式中是臃腫且難以維護的;
所以就需要使用控制器了;
很顯然;控制器就是來替代這第二個引數的閉包函式的;
寫起來也非常簡單直接寫控制器名即可;
然後用 @ 符號分割控制器和控制器的方法

Route::get('article/index', 'ArticleController@index');
Route::get('article/create', 'ArticleController@create');
Route::post('article/store', 'ArticleController@store');


可以在控制器中寫點內容;

訪問定義的路由就可以看到內容了;

一切都是這麼的完美;
但是如果你和我一樣帥;
額;不是;
如果你和我一樣懶且善於總結思考;
你會發現這三條路由都是以 article/ 為字首的;
在路由中我們應該怎麼減少這種重複呢?
這就是我們接著要講的分組的概念;
路由組就是把一些有相同特性的路由放在一個組裡面;
我們先來定義一個字首路由組;
上面這3條路由就可以改造成這個樣子了;

Route::prefix('article')->group(function () {
    Route::get('index', 'ArticleController@index');
    Route::get('create', 'ArticleController@create');
    Route::post('store', 'ArticleController@store');
});

隨著專案的擴大;
如果控制器都直接放在 app/Http/Controllers 目錄下的話;
那維護起來也開始略頭疼了;
於是就可以為控制器分目錄存放了;
比如說我要建一個 app/Http/Controllers/Admin/ArticleController.php;
再建一個 app/Http/Controllers/Home/ArticleController.php ;
命令列也是可以加目錄的;

php artisan make:controller Admin/ArticleController --resource
php artisan make:controller Home/ArticleController --resource

再在新建的控制器中寫點內容加以區分;

這種多級目錄是不需要指明目錄的;
只需要指明相對於app/Http/Controllers 目錄的 namespace 即可;

Route::prefix('admin/article')->namespace('Admin')->group(function () {
    Route::get('index', 'ArticleController@index');
    Route::get('create', 'ArticleController@create');
    Route::post('store', 'ArticleController@store');
});

group 是可以巢狀的;
那麼上面這樣的路由還可以改造下;

Route::prefix('home')->namespace('Home')->group(function () {
    Route::prefix('article')->group(function () {
        Route::get('index', 'ArticleController@index');
        Route::get('create', 'ArticleController@create');
        Route::post('store', 'ArticleController@store');
    });
});

訪問起來就是這樣的了;

因為 Admin 目錄下我們還會建立更多的路由器;
所以;我們應該使用 group 巢狀的這種方式;
比如說我們再有一個 app/Http/Controllers/Home/TagController.php;
那路由就是這樣的了;

Route::prefix('home')->namespace('Home')->group(function () {
    Route::prefix('article')->group(function () {
        Route::get('index', 'ArticleController@index');
        Route::get('create', 'ArticleController@create');
        Route::post('store', 'ArticleController@store');
    });
    Route::prefix('tag')->group(function () {
        Route::get('index', 'TagController@index');
        Route::get('create', 'TagController@create');
        Route::post('store', 'TagController@store');
    });
});

除了文件上講的這種方式;
其實以前版本的 laravel 還有另一種定義路由組的方式;

Route::group(['prefix'=>'admin', 'namespace'=>'Admin'], function () {
    Route::group(['prefix'=>'article'], function () {
        Route::get('index', 'ArticleController@index');
        Route::get('create', 'ArticleController@create');
        Route::post('store', 'ArticleController@store');
    });
});

就是把 prefix 和 namespace 這些都作為 group 方法的第一個引數;
不過現在不推薦這種寫法了;
不過因為很多以前的專案都是這樣寫的;
這裡講一下讓童鞋們檢視別人以前的專案的時候能理解而不迷茫;

到這裡我們已經學會了如何組織多級目錄了;
為了講解的簡單;
我們回到 app/Http/Controllers/ArticleController.php 檔案接著往下看;
會發現命令列建立的控制器裡面有個 edit 方法;

public function edit($id)
{
    //
}

edit 方法有個 $id 引數;
這個引數是幹什麼用的呢?
通過名字我們很容易就明白這是用來修改資料的;
id 一般又是資料庫的自增欄位;
那這就是要修改指定 id 的資料了;
但是這個 id 是哪傳來的呢?
下面就到了講解路由引數的時候了;
定義路由的時候我們是可以定義路由引數的;
我們接著上面的路由加一個 edit 的;

Route::prefix('article')->group(function () {
    Route::get('index', 'ArticleController@index');
    Route::get('create', 'ArticleController@create');
    Route::post('store', 'ArticleController@store');
    Route::get('edit/{id}', 'ArticleController@edit');
});

我們在定義路由的時候用花括號包一個變數名;
那這個變數就可以直接傳到控制器方法中;
然後在位址列傳什麼控制器中就可以接到什麼;
為了方便測試我們在這個方法中返回 id ;

public function edit($id)
{
    return '位址列傳的引數是:'.$id;
}

攜帶著路由引數通過路由訪問這個方法;

這裡面有個容易栽跟頭的地方;
就是控制器中的引數名跟路由引數名不是必須相同的;
也就是說我這樣寫也是可以的;

public function edit($a)
{
    return '位址列傳的引數是:'.$a;
}

一個路由引數的時候這倒不會覺得什麼;
一旦定義多個路由引數的時候;
這個坑就真的坑了;

Route::prefix('article')->group(function () {
    // ...
    Route::get('edit/{id}/{name}', 'ArticleController@edit');
});

在控制器中獲取路由引數的時候;

public function edit($name, $id)
{
    return 'id是:' . $id . '<br>name是:' . $name;
}

訪問 http://bjyblog.test/article/edit/666a/白俊遙
在你以為閉著眼都知道結果的時候;
一隻碩大的么蛾子飛了過來;

你發現 id 和 name 沒對上;
該敲黑板畫重點了筒子們;
路由引數中的第一個引數對應控制器中的第一個路由引數;
以此類推;
在控制器中路由引數跟引數名是沒關係的;
只跟順序有關;

再個 id 一般都是純數字;
這裡卻傳了字母 ;
我們應該怎麼約束下 id 呢?
laravel 方方面面都為我們考慮到了;
我們加個 where 就行了;

Route::prefix('article')->group(function () {
    // ...
    Route::get('edit/{id}/{name}', 'ArticleController@edit')->where('id', '[0-9]+');
});

這樣就只能傳數字了;
其實大多的表都是用 id 做主鍵的;
如果每個路由都手動定義一遍約束;
那也是挺麻煩的;
laravel 又一次方方面面都為我們考慮到了;
找到 app/Providers/RouteServiceProvider.php 這個檔案;
在 boot 方法中可以定義全域性約束;

public function boot()
{
    Route::pattern('id', '[0-9]+');

    parent::boot();
}

這樣就不需要為每條帶 id 引數的路由定義約束了;
以後所有帶 id 引數的路由就只能傳數字了;
不懂這個 RouteServiceProvider 的話沒關係不要糾結在這;
就先當是固定用法;
以後慢慢懂;

跟路由引數容易搞混的是請求引數;
路由引數?請求引數?傻傻分不清楚;
舉個例子;

Route::prefix('article')->group(function () {
    // ...
    Route::get('edit/{id}/{name}', 'ArticleController@edit');
});

bjyblog.test/article/edit/666/白俊遙?music=越過山丘&book=平凡世界
id 和 name 就是路由引數;
music 和 book 就是請求引數;
路由引數的獲取我們已經會了;
那請求引數怎麼獲取呢?
我們再回控制器中轉悠轉悠還會發現 update 方法;

public function update(Request $request, $id)
{
    //
}

這個 Request $request 就是我們用來獲取請求引數的關鍵;
它的意思是向控制器的方法傳一個 $request 它是一個 Request 類;
我們可以把我們的 edit 方法也加個 $request ;

    public function edit(Request $request, $id, $name)
    {
        $music = $request->input('music');
        $book = request()->input('book');
        $str = <<<php
id: $id <br>
name: $name <br>
music: $music <br>
book: $book <br>
php;
        return $str;
    }

這個 Request $request 是不會影響路由引數的順序的;
它放前放後都是可以的;
我們訪問這個方法並攜帶請求引數;

Request 類有一個 input 方法;
把要獲取的引數名傳給它就可以了;
我上面示例中還用了個 request() 函式;
它跟 Request $request 效果是一樣的;
$request 可以方便複用;
所以在控制器中更推薦使用 $request ;
如果傳的請求引數比較多的時候;
這樣一個一個的獲取還是麻煩;
Request 還有個 all 方法就可以獲取全部的請求引數;

    public function edit(Request $request, $id, $name)
    {
        dump($request->all());
    }

dump 是 laravel 自帶的一個列印函式;
就是 php 自帶的 var_dump 函式的升級版;
列印出來的效果是這樣的;

如果想列印資料並 die 掉可以使用 dd() 函式;
如果只想從一大堆請求引數中獲取指定的請求引數
Request 還有個 only 方法;

    public function edit(Request $request, $id, $name)
    {
        dump($request->only('music', 'book'));
    }

那如果想排除某個引數剩下的全要呢?
Request 還有個 except 方法;

    public function edit(Request $request, $id, $name)
    {
        dump($request->except('music'));
    }

再次讚美 laravel 的體貼周到;

本文為白俊遙原創文章,轉載無需和我聯絡,但請註明來自白俊遙部落格 https://baijunyao.com

相關文章