classify admin
This commit is contained in:
209
app/Models/Category.php
Normal file
209
app/Models/Category.php
Normal file
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships;
|
||||
|
||||
class Category extends Model
|
||||
{
|
||||
use HasFactory, HasRecursiveRelationships;
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'parent_category_id',
|
||||
'image',
|
||||
'slug',
|
||||
'status',
|
||||
'description',
|
||||
'is_job_category',
|
||||
'price_optional',
|
||||
];
|
||||
|
||||
public function getParentKeyName()
|
||||
{
|
||||
return 'parent_category_id';
|
||||
}
|
||||
|
||||
protected $appends = ['translated_name', 'translated_description'];
|
||||
|
||||
protected $with = ['translations'];
|
||||
|
||||
public function subcategories()
|
||||
{
|
||||
return $this->hasMany(self::class, 'parent_category_id');
|
||||
}
|
||||
|
||||
public function custom_fields()
|
||||
{
|
||||
return $this->hasMany(CustomFieldCategory::class);
|
||||
}
|
||||
|
||||
public function getImageAttribute($image)
|
||||
{
|
||||
if (! empty($image)) {
|
||||
return url(Storage::url($image));
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
public function items()
|
||||
{
|
||||
return $this->hasMany(Item::class);
|
||||
}
|
||||
|
||||
public function approved_items()
|
||||
{
|
||||
return $this->hasMany(Item::class)->where('status', 'approved');
|
||||
}
|
||||
|
||||
public function getAllItemsCountAttribute()
|
||||
{
|
||||
// Count items in this category
|
||||
$totalItems = $this->items()->where('status', 'approved')->getNonExpiredItems()->count();
|
||||
|
||||
// Count items from ALL descendants (not just loaded ones) using recursive query
|
||||
$descendantIds = $this->descendants()
|
||||
->where('status', 1)
|
||||
->pluck('id')
|
||||
->toArray();
|
||||
|
||||
if (! empty($descendantIds)) {
|
||||
$descendantItemsCount = Item::without('translations')
|
||||
->whereIn('category_id', $descendantIds)
|
||||
->where('status', 'approved')
|
||||
->getNonExpiredItems()
|
||||
->count();
|
||||
|
||||
$totalItems += $descendantItemsCount;
|
||||
}
|
||||
|
||||
return $totalItems;
|
||||
}
|
||||
|
||||
public function scopeSearch($query, $search)
|
||||
{
|
||||
$search = '%'.$search.'%';
|
||||
|
||||
return $query->where(function ($q) use ($search) {
|
||||
$q->orWhere('name', 'LIKE', $search)
|
||||
->orWhere('description', 'LIKE', $search)
|
||||
->orWhereHas('translations', function ($q) use ($search) {
|
||||
$q->where('description', 'LIKE', $search);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public function slider(): MorphOne
|
||||
{
|
||||
return $this->morphOne(Slider::class, 'model');
|
||||
}
|
||||
|
||||
public function translations()
|
||||
{
|
||||
return $this->hasMany(CategoryTranslation::class);
|
||||
}
|
||||
|
||||
public function getTranslatedNameAttribute()
|
||||
{
|
||||
$languageCode = request()->header('Content-Language') ?? app()->getLocale();
|
||||
if (! empty($languageCode)) {
|
||||
// NOTE : This code can be done in Cache
|
||||
$language = Language::select(['id', 'code'])->where('code', $languageCode)->first();
|
||||
|
||||
if (empty($language)) {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
$languageId = $language->id;
|
||||
$translation = $this->translations->first(static function ($data) use ($languageId) {
|
||||
return $data->language_id == $languageId;
|
||||
});
|
||||
|
||||
return ! empty($translation?->name) ? $translation->name : $this->name;
|
||||
}
|
||||
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getTranslatedDescriptionAttribute()
|
||||
{
|
||||
$languageCode = request()->header('Content-Language') ?? app()->getLocale();
|
||||
if (! empty($languageCode)) {
|
||||
// NOTE : This code can be done in Cache
|
||||
$language = Language::select(['id', 'code'])->where('code', $languageCode)->first();
|
||||
|
||||
if (empty($language)) {
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
$languageId = $language->id;
|
||||
$translation = $this->translations->first(static function ($data) use ($languageId) {
|
||||
return $data->language_id == $languageId;
|
||||
});
|
||||
|
||||
return ! empty($translation?->description) ? $translation->description : $this->description;
|
||||
}
|
||||
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
public function parent()
|
||||
{
|
||||
return $this->belongsTo(Category::class, 'parent_category_id');
|
||||
}
|
||||
|
||||
public function getFullPathAttribute()
|
||||
{
|
||||
$names = [];
|
||||
$current = $this;
|
||||
$visited = [];
|
||||
|
||||
while ($current) {
|
||||
if (in_array($current->id, $visited, true)) {
|
||||
break; // prevent loop
|
||||
}
|
||||
$visited[] = $current->id;
|
||||
|
||||
$names[] = $current->name;
|
||||
$current = $current->parent;
|
||||
}
|
||||
|
||||
return implode(' > ', array_reverse($names));
|
||||
}
|
||||
|
||||
public function getItemsGroupedByStatusAttribute()
|
||||
{
|
||||
$counts = [];
|
||||
|
||||
// Count items in this category
|
||||
$items = $this->items()->get();
|
||||
foreach ($items as $item) {
|
||||
$counts[$item->status] = ($counts[$item->status] ?? 0) + 1;
|
||||
}
|
||||
|
||||
// Include subcategories recursively
|
||||
foreach ($this->subcategories as $subcategory) {
|
||||
$subCounts = $subcategory->items_grouped_by_status;
|
||||
foreach ($subCounts as $status => $count) {
|
||||
$counts[$status] = ($counts[$status] ?? 0) + $count;
|
||||
}
|
||||
}
|
||||
|
||||
return $counts;
|
||||
}
|
||||
|
||||
public function getOtherItemsCountAttribute()
|
||||
{
|
||||
$totalItems = $this->items()->where('status', '!=', 'approved')->count();
|
||||
foreach ($this->subcategories as $subcategory) {
|
||||
$totalItems += $subcategory->other_items_count;
|
||||
}
|
||||
|
||||
return $totalItems;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user