Skip to content

Instantly share code, notes, and snippets.

@MrPunyapal
Created November 29, 2023 16:40
Show Gist options
  • Save MrPunyapal/2b1cfdd2c4ace0e14df31e65bbd93b38 to your computer and use it in GitHub Desktop.
Save MrPunyapal/2b1cfdd2c4ace0e14df31e65bbd93b38 to your computer and use it in GitHub Desktop.
Efficient Laravel Slug Generation: Unique, Sleek, and No Looping πŸš€
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
class Blog extends Model
{
use HasFactory;
protected $guarded = [];
public static function boot()
{
parent::boot();
static::creating(function ($post) {
// When creating a new post, automatically generate a unique slug
$post->slug = static::generateUniqueSlug($post->title);
});
}
protected static function generateUniqueSlug($title)
{
// Generate a base slug from the post title
$slug = str($title)->slug();
// Check if a post with the same slug doesn't already exist
if (static::whereSlug($slug)->doesntExist()) {
// If no existing post has the same slug, return the base slug
return $slug;
}
// Find the maximum numeric suffix for slugs with the same base
$max = static::query()
->where('slug', 'like', $slug . '-%')
->max(DB::raw('CAST(SUBSTRING_INDEX(slug, "-", -1) AS SIGNED)'));
// If there are no slugs with the same base, or the max value is null, append '-2'
if ($max === null) {
return $slug . '-2';
}
// Append the next numeric suffix to the base slug
return $slug . '-' . ($max + 1);
}
}
@MrPunyapal
Copy link
Author

MrPunyapal commented Nov 30, 2023

better version 🀯 by @eusonlito

<?php

protected static function generateUniqueSlug(string $title): string
{
    $slug = str_slug($title);

    if (static::query()->where('slug', $slug)->doesntExist()) {
        return $slug;
    }

    $last = static::query()
        ->selectRaw('CAST(REPLACE(`slug`, ?, "") AS UNSIGNED) `last`', [$slug.'-'])
        ->whereRaw('REPLACE(`slug`, ?, "") REGEXP "\-[0-9]+$"', [$slug])
        ->orderBy('last', 'DESC')
        ->value('last');

    return $slug.'-'.($last + 1);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment