Todo List: Liên kết Route và Model tự động trong Laravel

1381

Bài viết được sự cho phép của tác giả Kien Dang Chung

Video trong bài viết

Laravel được lựa chọn để phát triển ứng dụng web vì có rất nhiều các công cụ, tính năng được tích hợp sẵn, nó giúp cho công việc phát triển thuận lợi hơn, viết ít code hơn và code cũng dễ dàng maintain. Route Model Binding là một trong những hạt cát của sa mạc công cụ, nhưng có thể thấy những cái nhỏ nhất cũng chứa đựng đầy tinh thần Laravel.

  Bộ cài đặt Laravel Installer đã hỗ trợ tích hợp Jetstream
  Cách sử dụng Laravel với Socket.IO

Xem thêm tuyển dụng Laravel lương cao trên TopDev

Route Model Binding là gì?

Trước khi đến với định nghĩa Route Model Binding là gì? chúng ta quay trở lại với các phương thức đã viết code trong TodosController ở những bài trước:

public function show($todoId)
{
    return view('todos.show')->with('todo', Todo::find($todoId));
}

public function edit($todoId)
{
    return view('todos.edit')->with('todo', Todo::find($todoId));
}

public function update($todoId)
{
    $this->validate(request(), [
        'name' => 'required|min:6|max:12',
        'description' => 'required'
    ]);

    $data = request()->all();

    $todo = Todo::find($todoId);
    $todo->name = $data['name'];
    $todo->description = $data['description'];

    $todo->save();
    return redirect('/todos');
}

public function destroy($todoId)
{
    $todo = Todo::find($todoId);
    $todo->delete();
    return redirect('/todos');
}

Để ý kỹ thấy rằng các phương thức này trong TodosController đều có tham số là một biến chứa ID của Todo và trong phương thức đều có một đoạn code thực hiện tìm Todo tương ứng trong database. Nhận ra sự dư thừa này, Laravel đưa ra tính năng Route Model Binding.

Route Model Binding (tạm dịch là Liên kết Route và Model) là một cơ chế truyền một instance của Model trực tiếp vào Route. Ví dụ ở đây thay vì truyền một ID của Todo chúng ta sẽ truyền vào Model Todo. Toàn bộ các phương thức trên có thể viết lại với Route Model Binding như sau:

public function show(Todo $todo)
{
    return view('todos.show')->with('todo', $todo);
}

public function edit(Todo $todo)
{
    return view('todos.edit')->with('todo', $todo);
}

public function update(Todo $todo)
{
    $this->validate(request(), [
        'name' => 'required|min:6|max:12',
        'description' => 'required'
    ]);

    $data = request()->all();

    $todo->name = $data['name'];
    $todo->description = $data['description'];

    $todo->save();
    return redirect('/todos');
}

public function destroy(Todo $todo)
{
    $todo->delete();
    return redirect('/todos');
}

Như vậy, Laravel đã ngầm định rằng phần biến động {todo} trong Route tương ứng với Model Todo khi xử lý trong Controller, rất đơn giản và giảm bớt được việc viết code phải không?

Bạn thử thực hiện lại các chức năng trong ứng dung Todo List, mọi thứ hoạt động bình thường phải không?

Các loại liên kết Route Model

Về phạm vi bài học thì đã kết thúc, xong nhân tiện nói về Liên kết Route Model, chúng ta tìm hiểu thêm một chút. Trong Laravel có hai loại Liên kết Route Model:

Liên kết tự động (Implicit Binding)

Như trong ví dụ trên, Laravel tự động phân giải Model định nghĩa trong Route hoặc trong Controller với các biến đặt tên dạng type-hint. Một chú ý là mặc định Liên kết này sử dụng trường id của Model, nếu bạn muốn sử dụng một trường khác thì khai báo qua phương thức getRouteKeyName() trong Model đó.

Ví dụ: Trong các trang chi tiết của bài viết thì thường người ta sử dụng slug là chuỗi các từ phân cách bởi dấu gạch ngang, chuỗi này sẽ tương ứng với ID bài viết. Ví dụ bạn đang trong bài viết https://allaravel.com/blog/todo-list-lien-ket-route-va-model-tu-dong-trong-laravel thì slug ở đây là todo-list-lien-ket-route-va-model-tu-dong-trong-laravel. Chúng ta khai báo sử dụng slug này như sau trong model Post.

/**
 * Get the route key for the model.
 *
 * @return string
 */
public function getRouteKeyName()
{
    return 'slug';
}

Như vậy trong Route chúng ta có thể định nghĩa đường dẫn chi tiết cho bài viết như sau:

Route::get('/blog/{slug}', function(Post $post){
   return view('post.detail')->with('post', $post)
});

Rất hay phải không, chúng ta có thể thực hiện liên kết tự động Route và Model với bất kỳ trường nào có giá trị là duy nhất.

Liên kết theo khai báo (Explicit Binding)

Với kiểu Explicit Binding, chúng ta có thể đưa vào các logic nghiệp vụ riêng. Ở ví dụ trên chúng ta sử dụng slug, nhưng nếu chúng ta vừa muốn sử dụng slug vừa muốn sử dụng id thì thế nào?

Ví dụ, đường dẫn kiểu /blog/bai-viet-thu-nhat và /blog/1 đều có thể hiển thị bài viết đầu tiên. Mặc dù ví dụ này không hữu ích trong thực tế, nhưng sẽ có lúc bạn cần một trường hợp tương tự như vậy. Chúng ta sẽ phải sử dụng đến Explicit Binding, khai báo vào phương thức boot() của RouteServiceProvider:

public function boot()
{
    parent::boot();

    Route::bind('post', function ($value) {
        return AppPost::where('slug', $value)
            ->orWhere('id', $value)
            ->first() ?? abort(404);
    });
}

Bài này hơi dài dòng một tí vì phần này mình thấy khá hay mà trong video ngắn quá, rất mong anh em đóng góp ý kiến giúp All Laravel ngày càng hoàn thiện hơn.

Source code: Bài 15 – Route Model Binding

Bài viết gốc được đăng tải tại allaravel.com

Có thể bạn quan tâm: