Laravel Controller

PHP:7.2

Laravel:5.7

正常的狀況下,在 routes 定義的 endpoint 不太可能會像範例一樣處理單一邏輯,而且如果把開發邏輯都寫在 routes 在架構上也不符合 MVC 原則。

Laravel Controller 是定義開發邏輯的一個 類別,開發者可以透過繼承 Controller 定義不同邏輯的開發。Controller 的目錄統一放在 app/Http/Controllers

建立 Controller

Controller 雖然可以手動建立,但必須自己注意 Namespace 及繼承 Controller,建議可以使用 artisan 建立 Controller。

# 使用 make:controller 建立 ProfileController(class name)
# 預設會建立在 app/Http/Controllers 目錄底下
php artisan make:controller ProfileController

# 建立在 app/Http/Controllers/Admin 目錄
php artisan make:controller Admin/ProfileController

建立出來的 Controller

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ProfileController extends Controller
{
    //
}

Controller 基本使用

Controller 最典型的基本的應用就是建立一個可以傳入參數的 endpoint ,並在 Controller 端加以使用。

Route

Route::get('/profile/{id}', 'ProfileController@showID');

Controller

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ProfileController extends Controller
{
    public function index()
    {
        return 'Hello';
    }

    public function showID($id)
    {
        return $id;
    }

    public function list()
    {
        // 使用 view
        return view('test');
    }
}

如果 Controller 只有一個 action 的話,可以使用 __invoke 當 action name,在 routes 就不需要特別指定。

Route::get('/profile/{id}', 'ProfileController');
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ProfileController extends Controller
{
    public function __invoke($id)
    {
            return $id;
    }
}

Resource Controller

在需要用到 CRUD 的情形下,Laravel 也提供了 Resource Controller 解決必須大量建立 action 和 對應 route 的困擾。

利用 artisan 建立 Resource Controller

# 使用 --resource 參數建立 Controller
php artisan make:controller DataController --resource

建立完成以後,就可以看到加入 --resource 參數建立出來的 Controller 裡面已經自動建出 CRUD 會需要用到的 action,接著只要再補入邏輯就可以了。

Route

// 使用 resource method 以後,Laravel 會自動對應到相對的 action
Route::resource('data', 'DataController');

// 也可以透過 resources method 一次對應多個 Resource Controller
Route::resources([
    'photos' => 'PhotoController',
    'posts' => 'PostController'
]);

Partial Resource Routes

開發的需求上如果沒有需要完整的 Resource Controller,但又想使用該功能的話,可以考慮使用 Partial Routes,只留部份 endpoint

// 只對應到 index、show
Route::resource('photos', 'PhotoController')->only([
    'index', 'show'
]);

// 反向設定,只對應到 index、show
Route::resource('photos', 'PhotoController')->except([
    'create', 'store', 'update', 'destroy'
]);

Resource Controller action 及 route 的對應表

Verb URI Action Route Name
GET /data index data.index
GET /data/create create data.create
POST /data store data.store
GET /data/{id} show data.show
GET /data/{id}/edit edit data.edit
PUT/PATCH /data/{id} update data.update
DELETE /data/{id} destroy data.destroy

API Resource Controller

除了一般頁面使用的 Resource Controller,Laravel 也有提供 API 專用的,除了 action 數量不同以外,用法基本上都是一樣的。

# 利用 artisan 建立 API Resource Controller
php artisan make:controller API/DataController --api
// 使用 apiResource method 以後,Laravel 會自動對應到相對的 action
Route::apiResource('data', 'DataController');

// 一次對應多個 API Resource Controller
Route::apiResources([
    'photos' => 'PhotoController',
    'posts' => 'PostController'
]);

Notice:PUT/PATCH、DELETE

PUT/PATCH、DELETE 是 HTTP 的 method ,並不是 HTML 的標準,因此要在 HTML 的 <form> 使用這幾個 HTTP Verbs 時,必須加入一個 hidden 的 _method field 欺騙 HTTP。

而 Laravel 提供了一個 Blade directive 可以快速解決這件事。

<form action="/data/10" method="POST">
    <!-- 使用 @method 的 Blade directive -->
    @method('PUT')

    <!-- 使用 csrf_field() 自動在 form 代入 token-->
    {{ csrf_field() }}
    <button type="submit">讚</button>
</form>

Controller 取得參數

Laravel 的 Service Container 實作了相依性注入(Dependency Injection) 解決函式相依的問題,讓其他的 Instance 注入到 Controller 中直接使用。

HTTP Requests

Laravel 的架構下,透過 Illuminate\Http\Request 這個物件可以取得 HTTP Request 的參數。

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TestController extends Controller
{
    // 注入 Request
    public function create(Request $request)
    {
        // 透過 all method 取得所有參數
        $result = $request->all();

        // 透過 input method 取得 name 參數的值
        $name = $request->input('name');
        // 也可以直接取值
        $name = $request->name;

        // 當沒有該參數時,設定預設值
        $age = $request->input('age', '25');

        // 判斷是否有值
        if ($request->has('name')) {
            // Do something
        }
    }

    // 注入 Request 和代入參數
    public function update(Request $request, $id)
    {
        // 如果 Content-Type 是 application/json,可以用 dot 走訪 JSON arrays
        $name = $request->input('user.name');
    }
}
Categories: Laravel