In our last article Laravel slug generator with example we demonstrate how we can generate slug for model but in that article we need to rewrite the same code for multiple models if we want use the slug generation in multiple model. so in this article i will show you how can we achieve a reusable slug generator in laravel.we are going to create slug from any input field. slug is useful search engine optimization and also from security perspective because in some case we use primary id or unique id of table to fetch the detail in page but its not recommended way to show number in URL. Showing ID in URL can be open to SQL injection which lead to website hacking.
Create reusable slug using trait
In this way we will create a event in every model to generate the slug and save into the table.
Step 1: Create a model
First step is to create the model using artisan command or you can choose your any model
php artisan make:model Post
it will generate a Post model in app\Model folder.
Step 2: Create a trait and register events
Now, we need to create a trait in folder app\Traits
and file Sluggable.php
. if Traits folder already in app folder then you can directly copy the file and paste in Sluggable.php
<?php
namespace App\Traits;
use Illuminate\Support\Str;
trait Sluggable
{
private static $__sluggableConfig=["slug_column"=>"slug","slug_from_column"=>"title"];
protected static function bootSluggable()
{
self::setSluggableConfig(); // set initial config for sluggable
static::creating(function ($model) {
$model->{self::$__sluggableConfig['slug_column']} = $model->generateUniqueSlug($model->{self::$__sluggableConfig['slug_from_column']},0,self::$__sluggableConfig['slug_column']);
});
}
private static function setSluggableConfig(){
if(isset(self::$sluggableConfig['slug_column'])){
self::$__sluggableConfig['slug_column']=self::$sluggableConfig['slug_column'];
}
else{
self::$__sluggableConfig['slug_column']="slug";
}
if(isset(self::$sluggableConfig['slug_from_column'])){
self::$__sluggableConfig['slug_from_column']=self::$sluggableConfig['slug_from_column'];
}
else{
self::$__sluggableConfig['slug_from_column']="title";
}
}
private function generateUniqueSlug($name,$counter=0,$slugField="slug")
{
$updatedName = $counter==0?$name:$name."-".$counter;
if (static::where($slugField,Str::slug($updatedName))->exists()) {
return $this->generateUniqueSlug($name,$counter+1);
}
return Str::slug($updatedName);
}
}
Here , we created a boot method bootSluggable
and then registered a event static::creating
to catch the creating event from model.
Then, we are also setting some basic settings for this plugin using setSluggableConfig
to set the slug column and set the slug from column(slug_from_column).
After it we created a dynamic method generateUniqueSlug
to generate the unique slug for each row of table.
Step 4: Add trait to model
We have successfully created a trait and now its time to use it in our any model, here we will use it in our created post model.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
class Post extends Model
{
use HasFactory;
use \App\Traits\Sluggable;
}
In above code we used use
\App\Traits\Sluggable;
to implement the slug feature in model.
By default this trait use slug column for slug and generator column title. we can also change this behavior by defining a property $sluggableConfig
which accepts a array.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
class Post extends Model
{
use HasFactory;
use \App\Traits\Sluggable;
private static $sluggableConfig=["slug_column"=>"slug","slug_from_column"=>"title"];
}
Step 3: Create the route and save post
This is the time to check our implementation, so we need to create the route and create a new post
<?php
use Illuminate\Support\Facades\Route;
use App\Models\Post;
Route::get('/check-slug',function(){
$post=new Post;
$post->title="This is a test";
$post->description="This is a test";
$post->save();
});
now we can check in browser and below is screenshot