+1

Laravel Controllers

Writing Controllers

Basic Controllers

  • Thông thường Controller bạn tạo ra sẽ extend từ base Controller App\Http\Controllers\Controller
<?php
 
namespace App\Http\Controllers;
 
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)
        ]);
    }
}
  • Bạn có thể định nghĩa route cho method show như sau:
use App\Http\Controllers\UserController;
 
Route::get('/user/{id}', [UserController::class, 'show']);
  • Extend từ base controller là không bắt buộc, nhưng khi đó controller bạn tạo ra sẽ không có quyền truy cập vào các tính năng sẵn có của laravel như middleware default hoặc authorize method

Single Action Controllers

  • Trong trường hợp một action trong controller của bạn đặc biệt phức tạp, sẽ thuận tiện khi bạn tạo ra 1 controller và xử lý duy nhất action đó trong controller, khi đó bạn cần định nghĩa 1 method __invoke
<?php
 
namespace App\Http\Controllers;
 
use App\Models\User;
 
class ProvisionServer extends Controller
{
    /**
     * Provision a new web server.
     *
     * @return \Illuminate\Http\Response
     */
    public function __invoke()
    {
        // ...
    }
}
  • Khi đăng ký route cho signle action controller trên bạn sẽ không cần chỉ định method, thay vào đó bạn chỉ cần truyền class của controller:
use App\Http\Controllers\ProvisionServer;
 
Route::post('/server', ProvisionServer::class);
  • Bạn cũng có thể tạo 1 single action controller thông qua artisan command:
php artisan make:controller ProvisionServer --invokable

Controller Middleware

  • Bạn có thể chỉ định middleware cho route của controller trong file route của bạn:
Route::get('profile', [UserController::class, 'show'])->middleware('auth');
  • Hoặc bạn có thể chỉ định middleware trong method __construct() của controller, khi đó bạn cũng có thể dễ dàng tùy chỉnh middleware cho action nào hoặc loại bỏ action nào:
class UserController extends Controller
{
    /**
     * Instantiate a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
        //Chỉ định middleware cho action
        $this->middleware('log')->only('index');
        //Loại bỏ middleware cho action
        $this->middleware('subscribed')->except('store');
    }
}
  • Ngoài ra controller cũng cho phép bạn đăng ký middleware bằng cách sử dụng một closure, cung cấp cú pháp thuận tiện cho việc đăng ký một middleware đơn cho controller mà không cần định nghĩa 1 class middleware và đăng ký sử dụng nó:
$this->middleware(function ($request, $next) {
    return $next($request);
});

Resource Controllers

  • Bạn có thể hiểu resource controller là một khuôn mẫu controller gồm 7 method sẵn có để xử lý CRUD (create, read, update, and delete)
  • 7 method gồm:
index()
create()
store()
show()
edit()
update()
destroy()
  • Để tạo resource controller bạn có thể dùng artisan command:
php artisan make:controller PhotoController --resource
  • Khi đó, để khai báo route resource:
use App\Http\Controllers\PhotoController;
 
Route::resource('photos', PhotoController::class);
  • Hoặc khai báo route cho nhiều resource controller:
Route::resources([
    'photos' => PhotoController::class,
    'posts' => PostController::class,
]);
  • Actions Handled By Resource Controller: image.png

Customizing Missing Model Behavior

  • Thông thường, phản hồi HTTP 404 sẽ được tạo nếu không tìm thấy mô hình tài nguyên bị ràng buộc ngầm nhưng bạn có thể customize bằng cách call method missing khi định nghĩa resource route. Method missing là một closure được gọi khi không tìm thấy một mô hình rằng buộc ngầm:
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');
        });

Soft Deleted Models

  • Thông thường model sử dụng soft deleted thì các truy vấn sẽ mặc định không truy xuất data đã bị xóa mềm, trong trường hợp bạn muốn bỏ qua rằng buộc ngầm đó thì có thể dùng method withTrashed, để bỏ qua đối với tất cả resource route:
use App\Http\Controllers\PhotoController;
 
Route::resource('photos', PhotoController::class)->withTrashed();
  • Hoặc cũng có thể bỏ qua với medthod chỉ định trong controller bằng cách truyền tham số vào method withTrashed
Route::resource('photos', PhotoController::class)->withTrashed(['show']);
  • Bạn cũng có thể bỏ qua bằng cách dùng method withTrashed trong eloquent

Specifying The Resource Model

  • Nếu bạn muốn tạo model cùng controller bạn có thể thêm optinal --model
php artisan make:controller PhotoController --model=Photo --resource

Generating Form Requests

  • Nếu bạn muốn tạo form request tương ứng khi tạo controller
php artisan make:controller PhotoController --model=Photo --resource --requests

API Resource Routes

  • Khi định nghĩa route API cho resource controller, bạn có thể muốn loại bỏ 1 số route render HTML như: create, edit, để loại bỏ 2 route đó bạn có thể sử dụng method apiResource của facecade Route
use App\Http\Controllers\PhotoController;
 
Route::apiResource('photos', PhotoController::class);
  • Bạn cũng có thể loại bỏ route createedit cho 1 nhóm resorce controller
use App\Http\Controllers\PhotoController;
use App\Http\Controllers\PostController;
 
Route::apiResources([
    'photos' => PhotoController::class,
    'posts' => PostController::class,
]);
  • Bạn cũng có thể loại bỏ luôn route createedit cũng như method của nó trong controller bằng cách thêm optinal --api khi tạo resource controller
php artisan make:controller PhotoController --api
  • Khi đó trong resource controller chỉ tạo ra các method: index(), store(), update(), show(), destroy()

Nested Resources

  • Nếu bạn muốn khai báo route lồng nhau:
use App\Http\Controllers\PhotoCommentController;
 
Route::resource('photos.comments', PhotoCommentController::class);
  • Khi đó URIs sẽ có dạng:
/photos/{photo}/comments/{comment}
  • Chi tiết tất cả url image.png

Shallow Nesting

  • Thường thì trong route không nhất thiết phải chứa cả id cha và id con, ví dụ như trong trường route /photos/{photo}/comments/{comment} thì không cần thiết chứa cả id của phôt và id của comment vì chỉ cần id của comment đã là mã định danh duy nhất rồi, nên trong các trường hợp như vậy bạn có thể sử dụng lông nhau nông shallow nesting:
Route::resource('photos.comments', \App\Http\Controllers\PhotoCommentController::class)->shallow();
  • Khi đó route sẽ như sau: image.png

Naming Resource Routes

  • Theo mặc định thì tất cả các route của resource controller đều đã có một route name, tuy nhiên bạn có thể override tên của nó bằng cách truyền mảng names khi đăng ký route:
use App\Http\Controllers\PhotoController;
 
Route::resource('photos', PhotoController::class)->names([
    'create' => 'photos.build'
]);

Naming Resource Route Parameters

  • Mặc định Route::resource sẽ tạo parameter cho route dựa trên dạng số ít, bạn có thể override điều này bằng phương thức parameters, mảng truyền trong phương thức parameters phải là mảng kết hợp với key là resource và value là tên tham số
use App\Http\Controllers\AdminUserController;
 
Route::resource('users', AdminUserController::class)->parameters([
    'users' => 'admin_user'
]);
  • Ví dụ trên tạo URI sau cho route show :
/users/{admin_user}

Scoping Resource Routes

Localizing Resource URIs

  • Mặc định thì Route:resource sẽ tạo ra URIs sử dụng động từ tiếng anh, ví dụ như: photos/{photo}/comments/create, photos/{photo}/comments/{comment}/edit nếu bạn không muốn sử dụng các từ khóa như create, edit thì có thể override lại bằng cách sử dụng phương thức Route::resourceVerbs trong action boot()RouteServiceProvider.php
public function boot()
    {
        $this->configureRateLimiting();

        $this->routes(function () {
            Route::middleware('api')
                ->prefix('api')
                ->group(base_path('routes/api.php'));

            Route::middleware('web')
                ->group(base_path('routes/web.php'));
        });
        Route::resourceVerbs([
            'create' => 'crear',
            'edit' => 'editar',
        ]);
    }
  • Khi đó URIs route sẽ như sau: image.png

Supplementing Resource Controllers

  • Để bổ sung route cho resource controller, bạn chỉ cần định nghĩa route như bình thường
  • Trong trường hợp URIs của route trùng với resource controller thì route nào được định nghĩa sau sẽ override route trước đó
Route::get('photos/{photo}/comments', [\App\Http\Controllers\PhotoCommentController::class, 'index'])->name('test');
Route::resource('photos.comments', \App\Http\Controllers\PhotoCommentController::class);
  • Trong trường hợp trên route có name là test đã bị route resource override do route khai báo trùng URI là photos/{photo}/comments image.png

Singleton Resource Controllers

  • Đôi khi bạn muốn có những tài nguyên chỉ có thể 1 instance duy nhất, VD profile của user có thể được updated những một user chỉ có duy nhất 1 profile, những tài nguyên như vậy được gọi là singleton resources có nghĩa là trong 1 thời điểm chỉ có duy nhất 1 phiên bản của tài nguyên được tồn tại, trong trường hợp như vậy bạn có thể đăng ký 1 singleton resource controller
use App\Http\Controllers\ProfileController;
use Illuminate\Support\Facades\Route;
 
Route::singleton('profile', ProfileController::class);
  • Route trên sẽ sinh ra các URIs như sau: image.png
  • Bạn thấy route create, store, destroy sẽ không được sinh ra và các route edit, show, update sẽ không chấp nhận tham số Creatable Singleton Resources
  • Nhưng đôi khi bạn lại muốn định nghĩa route create, store, delete cho singleton resource. Khi đó bạn có thể sử dụng method creatable() trong khi định nghĩa singleton resource route:
Route::singleton('photos.thumbnail', ThumbnailController::class)->creatable();
  • Các URIs tương ứng cho route trên như sau: image.png
  • Nếu bạn chỉ muốn định nghĩa thêm route DELETE cho singleton resource mà không muốn định nghĩa route createstore thì bạn có thể dùng method destroyable
Route::singleton(...)->destroyable();

API Singleton Resources

  • apiSingleton method sử dụng để đăng ký một singleton resource cho API, khi đó sẽ loại bỏ các route không cần thiết khi sử dụng API như: createedit
Route::apiSingleton('profile', ProfileController::class);
  • Tương tự trường hợp đặc biệt bạn cũng có thể tạo ra các route như: create, edit bằng method creatable()
Route::apiSingleton('photos.thumbnail', ProfileController::class)->creatable();

Dependency Injection & Controllers

Constructor Injection

<?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

<?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;
 
        //
    }
}
  • Nếu bạn muốn truyền tham số vào method trong controller, giải sử bạn muốn truyền tham số cho route tương ứng như:
use App\Http\Controllers\UserController;
 
Route::put('/user/{id}', [UserController::class, 'update']);
  • Khi đó bạn chỉ cần khai báo tham số sau biến $request như sau:
<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
 
class UserController extends Controller
{
    /**
     * Update the given user.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  string  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }
}

All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.