你所不知道 ❌ 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
相关文章
相关标签/搜索