owned this note
owned this note
Published
Linked with GitHub
# 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 %}