你所不知道 ❌ Resource

前言

找我請到 掘金 或者 Github

本身也維護不過來那麼多站點,對不住你們了。php

👇 更新平臺多偶爾會漏掉,若是以爲文章還行點個 star 防走失。
你所不知道 ❌ 系列一塊兒探索未知

好久沒寫文章了,在新的公司新的遇到了新的夥伴,胖丁哥哥讓我看了 laracon 2017 - Adam Wathan 的視頻,略微手癢想分享一下本身的東西,這邊使用的是 laravel 做爲講解,可是思想卻不侷限於於 laravel 或者 php
呦呦呦呦,這邊是差很少的小二先生~~~~laravel

差很少的 路由

平時咱們寫代碼的時候常常會寫出不少下面這樣的路由:git

Route::get('/podcasts', 'PodcastsController@index');
Route::get('/podcasts/create', 'PodcastsController@create');
Route::post('/podcasts', 'PodcastsController@store');
Route::get('/podcasts/{id}', 'PodcastsController@show');
Route::get('/podcasts/{id}/edit', 'PodcastsController@edit');
Route::patch('/podcasts/{id}', 'PodcastsController@update');
Route::delete('/podcasts/{id}', 'PodcastsController@destroy');

Route::post('/podcasts/{id}/update-cover-image', 'PodcastsController@updateCoverImage');
Route::post('/podcasts/{id}/subscribe', 'PodcastsController@subscribe');
Route::post('/podcasts/{id}/unsubscribe', 'PodcastsController@unsubscribe');
Route::post('/podcasts/{id}/publish', 'PodcastsController@publish');
Route::post('/podcasts/{id}/unpublish', 'PodcastsController@unpublish');

Route::get('/episodes', 'EpisodesController@index');
Route::get('/episodes/{id}', 'EpisodesController@show');
Route::get('/episodes/{id}/edit', 'EpisodesController@edit');
Route::patch('/episodes/{id}', 'EpisodesController@update');

Route::get('/podcasts/{id}/episodes', 'PodcastController@indexEpisode');
Route::post('/podcasts/{id}/episodes', 'PodcastController@storeEpisode');
Route::get('/podcasts/{id}/episodes/new', 'PodcastController@createEpisode');

應該很是熟悉這樣所謂 嵌套資源,隨着項目的擴大,這樣會使得控制器一個個的變得胖起來邏輯開始複雜起來,如今讓咱們開始爲這差很少的路由作個變身。github

差很少的 CURD / REST

這邊進行一個小插曲,對資源總結起來大概就是 7 個標準的 Action :json

  • Index - 用來展現全部的資源項,好比全部用戶。
  • Show - 用來展現單個的資源項,好比用戶詳情。
  • Create - 用來顯示建立資源的頁面,先後端分離可能就沒這個 Action 。
  • Store - 用來接受數據並建立資源項,好比建立用戶。
  • Edit - 用來顯示編輯資源的頁面,先後端分離可能就沒這個 Action 。
  • Update - 用來接受數據並修改資源項,好比保存用戶詳情。
  • Destroy - 用來刪除指定的資源項,好比刪除用戶。

在後面的路由列表中,咱們把只帶有這 7 種 Action 的路由器都寫成 Resource後端

差很少的 小問題

在上面的路由中咱們選擇一條常見的路由來作變身:微信

GET /podcasts/{id}/episodes

對於這樣的一個 URL,若是咱們只想讓控制器只擁有 7 個標準的 Action ,咱們應該把它放在哪一個控制器呢?前後端分離

差很少的 控制器

放在 PodcastsController 控制器中嗎?那這樣就會與控制器中的 Index Action 衝突了。
放在 EpisodesController 控制器中嗎?這樣也會與控制器中的 Index Action 衝突。ide

GET /podcasts/{id}/episodes => Index
GET /podcasts/              => Index
GET /episodes/              => Index

那咱們須要怎麼安放這個處處被人嫌棄的 URL 呢?post

不同的 控制器

其實咱們能夠把 podcasts 和 episodes 合起來當作一種資源,存放在 PodcastEpisodesController 中。

class PodcastEpisodesController extends Controller
{
    public function index($id)
    {
        $podcast = Podcast::with('episodes')->findOrFail($id);
        return response()->json(['podcast' => $podcast]);
    }
}

不同的 路由

Route::resource('podcasts', 'PodcastsController');
Route::resource('episodes', 'EpisodesController');
Route::resource('podcasts.episodes', 'PodcastEpisodesController');

Route::post('/podcasts/{id}/update-cover-image', 'PodcastsController@updateCoverImage');
Route::post('/podcasts/{id}/subscribe', 'PodcastsController@subscribe');
Route::post('/podcasts/{id}/unsubscribe', 'PodcastsController@unsubscribe');
Route::post('/podcasts/{id}/publish', 'PodcastsController@publish');
Route::post('/podcasts/{id}/unpublish', 'PodcastsController@unpublish');

按照這個思路來進行路由的變身,咱們將會獲得三個控制器:

  • PodcastsController 擁有 7個標準 Action,5個非標準的 Action
  • EpisodesController 擁有 4個標準 Action
  • PodcastEpisodesController 擁有 3個標準 Action

差很少的 問題

雖然經歷瘦身後,路由列表已經變得很短了,可是PodcastsController 中還有 5 個非標準的 Action,咱們將繼續對這些方法進行瘦身:

POST /podcasts/{id}/update-cover-image

不同的 控制器

這個 URL 是用來更新 podcasts 的封面圖片的,咱們是不能把封面圖片也單獨當作一種資源呢?顯然是能夠的,這個資源中包含了一個更新的方法。

class PodcastCoverImageController extends Controller
{
    public function update($id)
    {
        $podcast = Auth::user()->podcasts()->findOrFail($id);
        $podcast->update([
            'cover_path' => request()->file('cover_image')->store('images', 'public')
        ]);
        return response()->json(['message' => 'ok']);
    }
}

不同的 路由

這個時候新的路由能夠寫成:

Route::put('/podcasts/{id}/cover-image', 'PodcastCoverImageController@update');

新的路由表能夠寫爲:

Route::resource('podcasts', 'PodcastsController');
Route::resource('episodes', 'EpisodesController');
Route::resource('podcasts.episodes', 'PodcastEpisodesController');
Route::resource('podcasts.cover-image', 'PodcastCoverImageController');

Route::post('/podcasts/{id}/subscribe', 'PodcastsController@subscribe');
Route::post('/podcasts/{id}/unsubscribe', 'PodcastsController@unsubscribe');
Route::post('/podcasts/{id}/publish', 'PodcastsController@publish');
Route::post('/podcasts/{id}/unpublish', 'PodcastsController@unpublish');

差很少的 中間表問題

剛纔咱們討論的兩個問題都是對於普通的表進行操做,可是若是咱們修改和建立的數據在中間表上咱們又該如何呢?

Route::post('/podcasts/{id}/subscribe', 'PodcastsController@subscribe');
Route::post('/podcasts/{id}/unsubscribe', 'PodcastsController@unsubscribe');

這兩個路由,分別對 user_podcast 中間表的進行刪除數據和建立數據。

不同的 控制器

其實咱們能夠把中間表也看作一種資源,寫成 SubscriptionsController,其中裏面包含兩個 Action 有 storedestroy。按照這個思路可把剩下的兩個控制器寫入 PublishedPodcastsController,也是包含了 storedestroy Action。

不同的 路由

通過這麼瘦身下來,咱們的路由表變成這個樣子:

Route::resource('podcasts', 'PodcastsController');
Route::resource('episodes', 'EpisodesController');
Route::resource('podcasts.episodes', 'SubscriptionsController');
Route::resource('podcasts.cover-image', 'PodcastCoverImageController');
Route::resource('subscriptions', 'SubscriptionsController');
Route::resource('published-podcasts', 'PublishedPodcastsController');

驚喜不驚喜,刺激不刺激,好看很差看,簡潔不簡潔!!!

結尾

其實,咱們能夠把 Everything 都看作是資源,對其進行 CURD 的操做,帶來的好處也是顯而易見,更加輕的控制器,更加進行的分類,更加的 RESTful。

相關資源

一塊兒成長

在困惑的城市裏總少不了並肩同行的 夥伴 讓咱們一塊兒成長。
  • 若是您想讓更多人看到文章能夠點個 點贊
  • 若是您想激勵小二能夠到 Github 給個 小星星
  • 若是您想與小二更多交流添加微信 m353839115

微信公衆號

本文原稿來自 PushMeTop
相關文章
相關標籤/搜索