Created
May 24, 2019 23:09
-
-
Save alexrusin/c107f34e274ae1be4ec8028d2ff7af49 to your computer and use it in GitHub Desktop.
Bootable Sluggable Trait
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://dotdev.co/creating-unique-title-slugs-with-laravel/ | |
// https://andy-carter.com/blog/using-laravel-s-eloquent-traits | |
<?php | |
namespace App\Traits; | |
use Illuminate\Support\Str; | |
trait Sluggable | |
{ | |
public static function bootSluggable() | |
{ | |
static::saving(function ($model) { | |
$model->slug = $model->createSlug(get_class($model), $model->title); | |
}); | |
static::updating(function ($model) { | |
$model->slug = $model->createSlug(get_class($model), $model->title, $model->id); | |
}); | |
} | |
/** | |
* @param $title | |
* @param int $id | |
* @return string | |
* @throws \Exception | |
*/ | |
public function createSlug($className, $title, $id = 0) | |
{ | |
// Normalize the title | |
$slug = Str::slug($title); | |
// Get any that could possibly be related. | |
// This cuts the queries down by doing it once. | |
$allSlugs = $this->getRelatedSlugs($className, $slug, $id); | |
// If we haven't used it before then we are all good. | |
if (!$allSlugs->contains('slug', $slug)) { | |
return $slug; | |
} | |
// Just append numbers like a savage until we find not used. | |
for ($i = 1; $i <= 10; $i++) { | |
$newSlug = $slug . '-' . $i; | |
if (!$allSlugs->contains('slug', $newSlug)) { | |
return $newSlug; | |
} | |
} | |
throw new \Exception('Can not create a unique slug'); | |
} | |
protected function getRelatedSlugs($className, $slug, $id = 0) | |
{ | |
return $className::select('slug')->where('slug', 'like', $slug . '%') | |
->where('id', '<>', $id) | |
->get(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment