Current state
This commit is contained in:
116
app/Models/Category.php
Normal file
116
app/Models/Category.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\{BelongsTo, HasMany, BelongsToMany, HasOne};
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Category extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'content_type_id','parent_id','name','slug',
|
||||
'description','image','is_active','sort_order'
|
||||
];
|
||||
|
||||
protected $casts = ['is_active' => 'boolean'];
|
||||
|
||||
/**
|
||||
* Ensure slug is always lowercase and valid before saving.
|
||||
*/
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::saving(function (Category $model) {
|
||||
if (isset($model->slug)) {
|
||||
$model->slug = strtolower($model->slug);
|
||||
if (!preg_match('/^[a-z0-9-]+$/', $model->slug)) {
|
||||
throw new \InvalidArgumentException('Category slug must be lowercase and contain only a-z, 0-9, and dashes.');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function contentType(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(ContentType::class);
|
||||
}
|
||||
|
||||
public function parent(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Category::class, 'parent_id');
|
||||
}
|
||||
|
||||
public function children(): HasMany
|
||||
{
|
||||
return $this->hasMany(Category::class, 'parent_id')
|
||||
->orderBy('sort_order')->orderBy('name');
|
||||
}
|
||||
|
||||
public function descendants(): HasMany
|
||||
{
|
||||
return $this->children()->with('descendants');
|
||||
}
|
||||
|
||||
public function seo(): HasOne
|
||||
{
|
||||
return $this->hasOne(CategorySeo::class);
|
||||
}
|
||||
|
||||
public function artworks(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Artwork::class, 'artwork_category');
|
||||
}
|
||||
|
||||
public function scopeActive($query)
|
||||
{
|
||||
return $query->where('is_active', true);
|
||||
}
|
||||
|
||||
public function scopeRoots($query)
|
||||
{
|
||||
return $query->whereNull('parent_id');
|
||||
}
|
||||
|
||||
public function getFullSlugPathAttribute(): string
|
||||
{
|
||||
return $this->parent
|
||||
? $this->parent->full_slug_path . '/' . $this->slug
|
||||
: $this->slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full public URL for this category (authoritative spec).
|
||||
* Example: /photography/abstract/dark
|
||||
*/
|
||||
public function getUrlAttribute(): string
|
||||
{
|
||||
$contentTypeSlug = strtolower($this->contentType->slug);
|
||||
$path = strtolower($this->full_slug_path);
|
||||
return '/' . $contentTypeSlug . ($path ? '/' . $path : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the canonical URL for SEO (authoritative spec).
|
||||
* Example: https://skinbase.org/photography/abstract/dark
|
||||
*/
|
||||
public function getCanonicalUrlAttribute(): string
|
||||
{
|
||||
return 'https://skinbase.org' . $this->url;
|
||||
}
|
||||
|
||||
public function getBreadcrumbsAttribute(): array
|
||||
{
|
||||
return $this->parent
|
||||
? array_merge($this->parent->breadcrumbs, [$this])
|
||||
: [$this];
|
||||
}
|
||||
|
||||
public function getRouteKeyName(): string
|
||||
{
|
||||
return 'slug';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user