# Laravel Controllers > 處理相關的一系列相關的 request 邏輯,ex: UserController 處理 顯示、建立、更新和刪除等等 https://laravel.com/docs/8.x/controllers # 編輯 Controllers ## basic 所有 controller 都會繼承一個 base controller `App\Http\Controllers\Controller` ```php= // controller <?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use App\Models\User; class UserController extends Controller { /** * Show the profile for a given user. * * @param int $id * @return \Illuminate\View\View */ public function show($id) { return view('user.profile', [ 'user' => User::findOrFail($id) ]); } } // route use App\Http\Controllers\UserController; Route::get('/user/{id}', [UserController::class, 'show']); ``` ## Single Action Controllers 當 controller 非常複雜時,可以寫一個 `__invoke` 方法去處理所有動作 ```php= // controller <?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use App\Models\User; class ProvisionServer extends Controller { /** * Provision a new web server. * * @return \Illuminate\Http\Response */ public function __invoke() { // ... } } // route use App\Http\Controllers\ProvisionServer; Route::post('/server', ProvisionServer::class); // artisan 建立 invoke controller php artisan make:controller ProvisionServer --invokable ``` # Controller Middleware ## 在 route ```php= Route::get('profile', [UserController::class, 'show'])->middleware('auth'); ``` ## 在 controller 檔案裡 ```php= class UserController extends Controller { /** * Instantiate a new controller instance. * * @return void */ public function __construct() { $this->middleware('auth'); $this->middleware('log')->only('index'); $this->middleware('subscribed')->except('store'); } } ``` ## inline middleware 不需要定義整個 middleware 檔案 ```php= $this->middleware(function ($request, $next) { return $next($request); }); ``` # Resource Controllers 想像每個 eloquent model 都是一個資源,使用者會對它進行 CRUD 的動作,也因為有這些動作 route 應該也要有相對項的路徑,所以 laravel 提供一個簡易的方式產生 resource controller ``` //artisan php artisan make:controller PhotoController --resource // 產生的檔案在 app/Http/Controllers/PhotoController.php //在 route 裡 單一 resource 的寫法 use App\Http\Controllers\PhotoController; Route::resource('photos', PhotoController::class); //在 route 裡 多個 resource 的寫法 Route::resources([ 'photos' => PhotoController::class, 'posts' => PostController::class, ]); ``` Resource Controller 提供的 actions |Verb|URI|Action|Route Name| |-|-|-|-| |GET|/photos|index|photos.index| |GET|/photos/create|create|photos.create| |POST|/photos|store|photos.store| |GET|/photos/{photo}|show|photos.show| |GET|/photos/{photo}/edit|edit|photos.edit| |PUT/PATCH| /photos/{photo}|update|photos.update| |DELETE|/photos/{photo}|destroy|photos.destroy| 客製化當找不到 resource controller 的 eloquent model 時的 404 寫法 ```php= use App\Http\Controllers\PhotoController; use Illuminate\Http\Request; use Illuminate\Support\Facades\Redirect; Route::resource('photos', PhotoController::class) ->missing(function (Request $request) { return Redirect::route('photos.index'); }); ``` 建立 controller 順便產生 model ``` php artisan make:controller PhotoController --model=Photo --resource ``` 建立 controller 順便產生 model 和 form request ``` php artisan make:controller PhotoController --model=Photo --resource --requests ``` ## Partial Resource Routes 當不是要所有的 resource action 都要要用到 controller 時 ```php= use App\Http\Controllers\PhotoController; //只有 Route::resource('photos', PhotoController::class)->only([ 'index', 'show' ]); //排除 Route::resource('photos', PhotoController::class)->except([ 'create', 'store', 'update', 'destroy' ]); ``` ### API Resource Routes 如果只需要將 laravel 當作提供只提供 api 框架那 route 的部份可以用`apiResource`,它會排除[上面提到的 action ](/5IkX0waITXKttvqBbOEM2w?view#Actions-Handled-By-Resource-Controller) create 和 edit 動作 ```php= // route use App\Http\Controllers\PhotoController; Route::apiResource('photos', PhotoController::class); ``` 多個 apiResources 的寫法 ```php= Route::apiResources([ 'photos' => PhotoController::class, 'posts' => PostController::class, ]); ``` 產生 apiResource Controller ```php= php artisan make:controller PhotoController --api ``` ## Nested Resources 有多個資源的 route ```php= use App\Http\Controllers\PhotoCommentController; Route::resource('photos.comments', PhotoCommentController::class); ``` 上面的寫法會是這種 route 的路徑 ```php= /photos/{photo}/comments/{comment} ``` ### Shallow Nesting ```php= use App\Http\Controllers\CommentController; Route::resource('photos.comments', CommentController::class)->shallow(); ``` 上面的寫法是會有下面這些 route Verb|URI|Action|Route Name -|-|-|- GET|/photos/{photo}/comments|index|photos.comments.index GET|/photos/{photo}/comments/create|create|photos.comments.create POST|/photos/{photo}/comments|store|photos.comments.store GET |/comments/{comment}|show|comments.show GET|/comments/{comment}/edit|edit|comments.edit PUT/PATCH|/comments/{comment}|update|comments.update DELETE|/comments/{comment}|destroy|comments.destroy ## 命名 Resource Routes ```php= se App\Http\Controllers\PhotoController; Route::resource('photos', PhotoController::class)->names([ 'create' => 'photos.build' ]); ``` ## Naming Resource Route Parameters 陣列裡需要 resource names 和 parameter names ```php= use App\Http\Controllers\AdminUserController; Route::resource('users', AdminUserController::class)->parameters([ 'users' => 'admin_user' ]); ``` 上面寫法會是下面這樣的 route ```php= /users/{admin_user} ``` ## Scoping Resource Routes 可能 child resource 是用不同的欄位去找可以有這種寫法 ```php= use App\Http\Controllers\PhotoCommentController; Route::resource('photos.comments', PhotoCommentController::class)->scoped([ 'comment' => 'slug', ]); ``` 上面寫法會是下面這種 route ```php= /photos/{photo}/comments/{comment:slug} ``` 這個 route 會去撈 photo 還有和它相關的 一個comment ## Localizing Resource URIs 預設 Route::resource 會用英文的動詞,假如你要自己定義 create 和 edit 等等相關的動詞,可以用 Route::resourceVerbs 方法去實踐在 `App\Providers\RouteServiceProvider` 裡 ```php= public function boot() { Route::resourceVerbs([ 'create' => 'crear', 'edit' => 'editar', ]); // ... } ``` `Route::resource('fotos', PhotoController::class)` 就會產生下面的 route ``` /fotos/crear /fotos/{foto}/editar ``` ## Supplementing Resource Controllers 要增加其它 route 要記得在 resource route 之前 ```php= use App\Http\Controller\PhotoController; Route::get('/photos/popular', [PhotoController::class, 'popular']); Route::resource('photos', PhotoController::class); ``` # Dependency Injection & Controllers [service container ](https://laravel.com/docs/8.x/container) 會去解析所有 contollers,所以你可以 type-hint 任何相依性在 constructor ```php= <?php namespace App\Http\Controllers; use App\Repositories\UserRepository; class UserController extends Controller { /** * The user repository instance. */ protected $users; /** * Create a new controller instance. * * @param \App\Repositories\UserRepository $users * @return void */ public function __construct(UserRepository $users) { $this->users = $users; } } ``` ## Method Injection 除了 constructor injection ,你或許會 type-hint dependencies 在你的 controller methods. 比較常見的是 Illuminate\Http\Request 實例在 controller method ```php= <?php namespace App\Http\Controllers; use Illuminate\Http\Request; class UserController extends Controller { /** * Store a new user. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $name = $request->name; // } } ``` ###### tags: `2021` `laravel` `controller` `route` `injection` `resource` {%hackmd BJrTq20hE %}