Files
thrillwiki_laravel/app/Traits/HasSlugHistory.php

106 lines
2.6 KiB
PHP

<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Support\Str;
use App\Models\SlugHistory;
trait HasSlugHistory
{
/**
* Boot the trait.
*/
protected static function bootHasSlugHistory(): void
{
static::saving(function ($model) {
if (!$model->slug) {
$model->slug = $model->generateSlug();
}
});
static::updating(function ($model) {
if ($model->isDirty('slug') && $model->getOriginal('slug')) {
$model->addToSlugHistory($model->getOriginal('slug'));
}
});
}
/**
* Get all slug histories for this model.
*/
public function slugHistories(): MorphMany
{
return $this->morphMany(SlugHistory::class, 'sluggable');
}
/**
* Add a slug to the history.
*/
protected function addToSlugHistory(string $slug): void
{
$this->slugHistories()->create(['slug' => $slug]);
}
/**
* Generate a unique slug.
*/
protected function generateSlug(): string
{
$slug = Str::slug($this->name);
$count = 2;
while (
static::where('slug', $slug)
->where('id', '!=', $this->id)
->exists() ||
SlugHistory::where('slug', $slug)
->where('sluggable_type', get_class($this))
->where('sluggable_id', '!=', $this->id)
->exists()
) {
$slug = Str::slug($this->name) . '-' . $count++;
}
return $slug;
}
/**
* Find a model by its current or historical slug.
*
* @param string $slug
* @return static|null
*/
public static function findBySlug(string $slug)
{
// Try current slug
$model = static::where('slug', $slug)->first();
if ($model) {
return $model;
}
// Try historical slug
$slugHistory = SlugHistory::where('slug', $slug)
->where('sluggable_type', static::class)
->latest()
->first();
if ($slugHistory) {
return static::find($slugHistory->sluggable_id);
}
return null;
}
/**
* Find a model by its current or historical slug or fail.
*
* @param string $slug
* @return static
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
*/
public static function findBySlugOrFail(string $slug)
{
return static::findBySlug($slug) ?? throw new \Illuminate\Database\Eloquent\ModelNotFoundException;
}
}