Basic
laravel5.1/5.2釋出的路由模型繫結是一個非常強大的功能,dingo/api中想要使用路由模型繫結需要引入bindings元件到dingo的路由組中
路由中的引數命名
如有需要,使用資源的單數形式為路由命名,而不是 {id}/{slug}/{code}等等
正確的示例
# api.php
Route::resource('posts', 'PostController'); // laravel會將引數命名為 post
Route::get('users/{user}/posts', 'PostController@index');
Route::get('posts/{post}/comments', 'CommentController@index');
顯式繫結
以簡書的文章為例,使用RESTFul 風格可以得到以下幾條路由
# api.php
Route::get('posts', 'PostController@index'); // 首頁/基礎帖子展示
Route::get('users/{user}/posts', 'PostController@index'); // 某個使用者的帖子
Route::get('collections/{collection}/posts', 'PostController@index') // 某個專題下的帖子
可以看到,這裡我使用了同一個方法來處理這三條路由.
接下來定義路由模型繫結,這裡使用顯式繫結,以獲得較大的靈活性
# RouteServiceProvider.php
Route::model('user', User::class);
Route::model('collection', Collection::class)
然後看看控制器中的定義
# PostController.php
public function index($parent = null)
{
$query = $parent ? $parent->posts() : Post::query();
// e.g
$posts = $query->latest()->paginate();
// ...
}
當我們使用第一條路由訪問我們的帖子時, $parent得到的是一個null, $query = Post::query
.
訪問後兩條路由時,由於路由模型繫結,$parent 被賦值為具體的model. 此時可以透過model中定義的關聯關係來獲取query. 透過顯示繫結和關聯關係的定義,使得$parent->posts()足夠抽象,不依賴於具體的model.具有強大的通用性.
p.s
# User.php
public function posts()
{
return $this->hasMany(Post::class);
}
# Collection.php
public function posts()
{
return $this->belongsToMany(Post::class, 'collection_post');
}
Advance
對於, 如 我的文章列表,我的訂單等我們可能會這樣定義我們的 RESTFul 路由
// 這裡單數形式的user就代表著me的意思, 參考於github api
Route::get('user/posts', 'PostController@index');
Route::get('user/orders', 'OrderController@index');
甚至,依舊已簡書為例,簡書有兩個板塊30日熱門和7日熱門, 我們可能會有這樣兩條路由
Route::get('hot-30/posts', 'PostController@index');
Route::get('hot-7/posts', 'PostController@index');
// 又或者根據推薦演算法透過使用者畫像推薦不同的文章
Route::get('recommend/posts', 'PostController@index');
不要激動,接下來不是演算法環節?
?現在的問題是,如何依舊使用同一個方法實現?的幾條路由呢?
我們換一種思路.前面我們都是在控制器層面做抽象,然後把具體邏輯交給路由層.可面對上面的需求依舊有些力不從心,那我們不妨尋找一下上面需求的共同點,再提取一層抽象
當然更簡單的思路是 拆開幾個方法寫就ok啦,搞這麼麻煩是吧.見仁見智.瞎折騰就是了
我們可以這麼做
# api.php
// 使用 {virtual} 來匹配上面的hot-30,hot-7,recommend 等等
Route::get('{virtual}/posts', 'PostController@index');
# RouteServiceProvider.php
Route::bind('virtual', function ($value) {
$virtual = "App\\Virtual\\" . studly_case($value);
return new $virtual($value);
});
上面的做法是, 路由模型繫結是基於model,或者說 entity 的(在symfony中model被稱作entity).但是hot-30/hot-7/recommend 並不基於model.(當然也可以基於model,不過這不是我們本次討論的重點),
那我們不妨使用一個virtual 來承載它們, virtual是一個和entity相近又相反的意思.在這裡再適合不過了.來看看具體實現
# Hot30.php
namespace App\Virtual;
use App\Models\Post;
class Hot30 extends Virtual
{
public function posts()
{
$ids = ...; // service
return Post::whereIn('id', $ids);
}
}
Hot7,Recommend同理. 這樣我們又承接起了上面控制器的程式碼.這裡的posts()的作用就相當於比如User.php中的posts()的作用,但是卻更加的靈活.
魯迅說過: 不要害怕在你的app下新增目錄
我只是分享了一個簡單的想法,更多的用法等著你來探索.
successful!
本作品採用《CC 協議》,轉載必須註明作者和本文連結