小練習- 共識 Controller 與 Service

練習時間30分鐘


今天想跟大家達成一個共識,之前在 小練習 – 共識 Controller 與 URL 這邊文章中,有提到 Controller 與 URL ,因此建議Controller 裡面的方法都要對應到一個網址以及HTTP動作,以下是基於 RESTful 設計模式的 API,AnimalController 為例。

方法名稱定義網址 (HTTP動詞 + 網址)
index動物列表資料GET /v1/api/animals
store建立動物資料POST /v1/api/animals
show查看單一動物資料GET /v1/api/animals/{animal}
update更新修改動物資料PATCH | PUT /v1/api/animals/{animal}
destroy移除動物資料DELETE /v1/api/animals/{animal}
AnimalController.php 方法定義的操作

若因為業務邏輯越來越複雜,導致方法越來越多,如果有物件導向的觀念,或許會設法把,functroller 做拆分,建議Controller 裡面,不要再有其他不會對應到 網址的方法,建議使用 Service 來輔助,因此非常建議,Controller 裡面就定義上面表格的方法就好。

要怎麼建立 Service 簡單來說他就是另外建立的一個 class 類別,如果你一開始就是接觸Laravel 可能不太懂物件導向,建議可以多了解一下物件導向,可以更深入 Laravel 到底層設計。

建議把 Service 建立在 Laravel 專案中的 app\Services 資料夾中,這個資料夾就要自己新建了,有了這個資料夾,定義他要來操作Animal 動物的資源的話,就在這個資料夾當中建立一個 AnimalService.php 的檔案,裡面建立一個 AnimalService 類別。

<?php

namespace App\Services;

class AnimalService
{

}

這時候你就可以將你的 Controller 拆分到這個 Service 當中,你可以依照不同的商業邏輯拆分不同的小方法 在《使用Laravel 8 PHP主流框架打造RESTful API(iT邦幫忙鐵人賽系列書)》 這本書中,整個重構的章節都在說明如何拆分,很重要的一點就是測試程式,在重構的時候,建議要有足夠的測試,不然很有可能因為你的修改而造成新的 bug。

不過這篇文章主要是說明,如何使用 Service 來輔助 Controller ,假設你的內容,你可以在 原本的 AnimalController 檔案中加入以下程式碼

<?php

namespace App\Http\Controllers\Api\V1\Animal;

use App\Models\Animal;
use App\Services\AnimalService;
use Illuminate\Http\Request;

class AnimalController extends Controller
{
    private $service

    public function __construct(AnimalService $animalService)
    {
        $this->service = $animalService;
    }

    public function index(){}

    public function store(Request $request){}

    public function show(Animal $animal){}

    public function update(Request $request, Animal $animal){}

    public function destroy(Animal $animal){}
}

將需要輔助的 Controller 加上以上粗體字,引用 AnimalService 類別,並寫在 AnimalController 類別中定義一個私有元素 $service (這邊我自己是習慣講相同資源名稱的省略),接著建立一個建構子方法 __construct (前方的底線是兩個 「 _ 」 喔!),並且設定變數傳入一個 AnimalService 類別的$animalService 變數,這裡 Laravel 會自動依賴注入這個參數,最後在建構子的方法中撰寫

$this->service = $animalService;

AnimalController 定義的私有變數 service 設定為依賴注入的 $animalService;

接著在 AnimalController 方法中就可以使用以下方式取的得 AnimalService 撰寫的方法,假設 AnimalService 裡面我有撰寫一個 doSomething

<?php

namespace App\Services;

class AnimalService
{
    public function doSomething()
    {
        return '做一些事情';
    }
}

這樣的話你可以在 剛剛修改好的 controller 使用以下方式呼叫 AnimalService 類別的 doSomething(),假設Service的方法是要在 AnimalController 的 index 方法使用

<?php

namespace App\Http\Controllers\Api\V1\Animal;

use App\Models\Animal;
use App\Services\AnimalService;
use Illuminate\Http\Request;

class AnimalController extends Controller
{
    private $service

    public function __construct(AnimalService $animalService)
    {
        $this->service = $animalService;
    }

    public function index()
    {
        return $this->service->doSomething();
    }
}

這樣就可以輕易拿到 doSomething 方法回傳的字串喔!


以上是簡單的範例,但這邊複習一下,建立在我們達成的共識回答以下問題,歡迎留言給我!

  1. 如上範例 app\Http\Controllers\Api\V1\Animal\AnimalController.php 檔案中定義的 index 方法通常是在做什麼事情的? (參考:小練習 – 共識 Controller 與 URL小練習 – 共識 Controller function
  2. 請求什麼網址可以來到index ?(參考:小練習 – 共識 Controller 與 URL
  3. 請問如上範例,他會回傳什麼資料顯示於畫面上?

發佈留言