*/ protected $fillable = [ 'title', 'slug', 'content', 'excerpt', 'category_id', 'featured_image', 'is_featured', 'status', 'published_at', ]; /** * The attributes that should be cast. * * @return array */ protected function casts(): array { return [ 'is_featured' => 'boolean', 'published_at' => 'datetime', ]; } /** * Boot the model and register model events. */ protected static function booted(): void { static::creating(function (Post $post): void { if (blank($post->slug)) { $post->slug = static::generateUniqueSlug($post->title); } }); static::updating(function (Post $post): void { if ($post->isDirty('title') && blank($post->slug)) { $post->slug = static::generateUniqueSlug($post->title, $post->id); } }); } /** * Get the category that owns the post. */ public function category(): BelongsTo { return $this->belongsTo(Category::class); } /** * Generate a unique slug based on the post title. */ public static function generateUniqueSlug(string $title, ?int $ignoreId = null): string { $baseSlug = Str::slug($title); $slug = $baseSlug; $counter = 1; while (static::query() ->where('slug', $slug) ->when($ignoreId, fn ($query) => $query->whereKeyNot($ignoreId)) ->exists()) { $slug = "{$baseSlug}-{$counter}"; $counter++; } return $slug; } /** * Determine whether the post is published. */ public function isPublished(): bool { return $this->status === self::STATUS_PUBLISHED; } }