post-image

Tối ưu URL với Eloquent Sluggable

Tổng quan

1. Tại sao nên tối ưu cấu trúc đường dẫn?

Việc tối ưu cấu trúc đường dẫn sẽ giúp bạn tạo ra các đường dẫn thân thiện (Friendly URLs) để các công cụ tìm kiếm dễ dàng đọc, lập chỉ mục, dễ nhớ và ngắn gọn ngoài ra còn có thể bao gồm từ khóa có trong nội dung của đường dẫn để tốt nhất cho việc SEO.

Ví dụ về đường dẫn thân thiện và không thân thiện:

Mặc định Laravel cũng đã giúp bạn để các đường dẫn trở nên dễ đọc và dễ nhìn như http://localhost.dev/post/10http://localhost.dev/post/10/comments

Tuy nhiên đường dẫn như vậy thường sẽ không cung cấp nhiều thông tin cho cả người đọc và các công cụ tìm kiếm. Chẳng hạn con số 10 ở đây có ý nghĩa gì đối với người dùng? Các bạn đều biết đó là giá trị integer đại diện cho primary key của bản ghi được tìm thấy trong bảng “post” tuy nhiên nó sẽ có ý nghĩa hơn rất nhiều nếu sử dụng đường dẫn như sau: http://localhost.dev/post/duong-dan-than-thien-trong-laravel-5.

Các bạn có thể thấy được tác dụng của việc tối ưu cấu trúc đường dẫn, trong phần sau của ìa viết mình sẽ hướng dẫn các bạn cách tạo ra đường dẫn thân thiện trong Laravel 5.

2. Tối ưu URL với Eloquent Sluggable

Việc tạo đường dẫn thân thiện trong Laravel tương đối đơn giản dưới sự hỗ trợ của package eloquent-sluggable.

2.1. Cài đặt

CHÚ Ý: Tùy thuộc vào phiên bản laravel mà chúng ta cài đặt package với các version khác nhau

Laravel VersionSluggable Version
4.x2.x
5.1, 5.24.0
5.1*, 5.2*, 5.34.1

Chúng ta có thể cài đặt package thông qua Composer

$ composer require cviebrock/eloquent-sluggable:^4.1
Code language: JavaScript (javascript)

Sau đó, cập nhật config config/app.php

'providers' => [ // ... Cviebrock\EloquentSluggable\ServiceProvider::class, ];
Code language: PHP (php)

Sau đó, bạn sẽ cập nhật việc cấu hình bằng cách chạy lệnh php artisan vendor:publish trong console:

php artisan vendor:publish --provider="Cviebrock\EloquentSluggable\ServiceProvider"
Code language: JavaScript (javascript)

2.2. Cập nhật Eloquent Models

Để sử dụng slug thì trong model cũng như database của bạn cần phải có collumn chứa nó, chúng ta có thể thêm vào bằng migration. Tiếp theo chúng ta cập nhật lại các models cần sử dụng slug. Nhữn models đó cần phải sử dụng Sluggable trait đồng thời phải khai báo phương thức sluggable(), phương thức này trả về 1 mảng chứa các config liên quan tới slug của model hiện tại. Các bạn xem thêm tại: Configuration

use Cviebrock\EloquentSluggable\Sluggable; class Post extends Model { use Sluggable; /** * Return the sluggable configuration array for this model. * * @return array */ public function sluggable() { return [ 'slug' => [ 'source' => 'title' ] ]; } }
Code language: PHP (php)

2.3. Sử dụng

Sau các bước trên, slug sẽ được tự động tạo mỗi khi chúng ta thực hiện phương thức save() của model:

$post = new Post([ 'title' => 'My Awesome Blog Post', ]); $post->save();
Code language: PHP (php)

Đê lấy slug:

echo $post->slug;
Code language: PHP (php)

Nếu chúng ta thực hiện sao chép model với phương thức replicate() của Eloquent thì package sẽ tự động tạo lại slug cho giá trị được sao chép để đảm bảo slug là unique.

$post = new Post([ 'title' => 'My Awesome Blog Post', ]); $post->save(); // $post->slug is "my-awesome-blog-post" $newPost = $post->replicate(); // $newPost->slug is "my-awesome-blog-post-1"
Code language: PHP (php)

2.4. Class SlugService

Tất cả các xử lý logic về việc tạo slug đều được quản lý bởi class \Cviebrock\EloquentSluggable\Services\SlugService

Bạn có thể tạo ra slug mà không thực hiện việc tạo và lưu vào model bằng phương thức createSlug:

use \Cviebrock\EloquentSluggable\Services\SlugService; $slug = SlugService::createSlug(Post::class, 'slug', 'My First Post');
Code language: PHP (php)

Ngoài 3 tham số cơ bản trên, phương thức createSlug còn có thêm tham số thứ 4 là một array chứa config, ví dụ:

$slug = SlugService::createSlug(Post::class, 'slug', 'My First Post', ['unique' => false]);
Code language: PHP (php)

Với việc đặt unique = falseslug được tạo ra từ ví dụ trên sẽ ko là unique.

2.5. Events

Các model Sluggable sẽ thực thi 2 Eloquent events "slugging" and "slugged".

Event "slugging" được thực hiện trước khi slugs được tạo ra. Nếu hàm callback từ event này trả về là false thì slug sẽ không được tạo ra.

Event slugged được thực thi ngay sau slug được tạo ra. Nó sẽ không được gọi nếu model không cần slugging (bạn cần khai báo việc cần slugging hay không với phương thức needsSlugging()).

Post::registerModelEvent('slugging', function($post) { if ($post->someCondition()) { // the model won't be slugged return false; } }); Post::registerModelEvent('slugged', function($post) { Log::info('Post slugged: ' . $post->getSlug()); });
Code language: PHP (php)

2.6. Configuration

Configuration được thiết kế để trở lên linh hoạt nhất có thể. Bạn có thể cài đặt mặc định cho tất cả các models và thực hiện việc setting riêng cho từng models sau đó.

Mặc định, configuration tổng quát cho các models được lưu trong file app/config/sluggable.php. Nếu bạn chưa publish file sluggable.php thì package sẽ lấy dữ liệu từ vendor/cviebrock/eloquent-sluggable/resources/config/sluggable.php như là dữ liệu mặc định.

return [ 'source' => null, 'maxLength' => null, 'method' => null, 'separator' => '-', 'unique' => true, 'uniqueSuffix' => null, 'includeTrashed' => false, 'reserved' => null, ];
Code language: PHP (php)

Cho từng modelsconfiguration được quản lý với phương thức sluggable(). Phương thức này sẽ trả về một danh sách chứa config cho model:

public function sluggable() { return [ 'title-slug' => [ 'source' => 'title' ], 'author-slug' => [ 'source' => ['author.firstname', 'author.lastname'] ], ]; }
Code language: PHP (php)

Chúng ta có thể tạo nhiều slugs cho cùng model, dựa trên các source khác nhau cùng với các options khác nhau, ví dụ:

public function sluggable() { return [ 'title-slug' => [ 'source' => 'title' ], 'author-slug' => [ 'source' => ['author.firstname', 'author.lastname'], 'separator' => '_' ], ]; }
Code language: PHP (php)

2.7. SluggableScopeHelpers Trait

Bằng việc thêm SluggableScopeHelpers trait vào model của bạn, bạn có thể thực hiện một số phương thức như:

$post = Post::whereSlug($slugString)->get(); $post = Post::findBySlug($slugString); $post = Post::findBySlugOrFail($slugString);
Code language: PHP (php)

Xem thêm tại: SCOPE-HELPERS.md.

2.8. Route Model Binding

Như các bạn đã biết, kể từ laravel 5.2, Laravel đã bắt đầu hỗ trợ Model Binding trong Route.

2.8.1. Implicit Binding

Để thay đổi việc Implicit binding bằng id sang slug, chúng ta chỉ cần thêm phương thức getRouteKeyName()vào model và trả về tên của slug:

use Cviebrock\EloquentSluggable\Sluggable; use Cviebrock\EloquentSluggable\SluggableScopeHelpers; use Illuminate\Database\Eloquent\Model; class Post extends Model { use Sluggable; public function sluggable() { return [ 'slug' => [ 'source' => 'title', ] ]; } /** * Get the route key for the model. * * @return string */ public function getRouteKeyName() { return 'slug'; } }
Code language: PHP (php)

Tiếp theo chúng ta set up routes tương tự như việc sử dụng id cho binding trong Eloquent documentation:

Route::get('api/posts/{post}', function (App\Post $post) { return $post->title; });
Code language: PHP (php)

Nếu bạn sử dụng SluggableScopeHelpers trait, bạn có thể bind route bằng slug mặc định:

public function getRouteKeyName() { return $this->getSlugKeyName(); }
Code language: PHP (php)

2.8.2 Explicit Binding

Bạn cũng có thể sử dụng phương thức RouteServiceProvider::boot như được miêu tả trong Laravel Documentation để quản lý explicit route model binding.

public function boot() { parent::boot(); Route::model('user', App\User::class); }
Code language: CSS (css)

Các bạn có thể tham khảo các bài viết hay về Laravel tại đây.


Hãy tham gia nhóm Học lập trình để thảo luận thêm về các vấn đề cùng quan tâm.

Tham khảo: https://viblo.asia/p/laravel-toi-uu-url-voi-eloquent-sluggable-ZDEeLRAdvJb

Leave a Reply

Your email address will not be published. Required fields are marked *