'date', 'qty' => 'float', 'created_at' => 'datetime', ]; } /** * Relasi ke model Category */ public function category(): BelongsTo { return $this->belongsTo(Category::class, 'category_id'); } /** * Booting model events */ protected static function booted() { static::saving(function ($food) { // 1. OTOMATIS GENERATE SLUG if ($food->isDirty('nama_makanan') || empty($food->slug)) { $food->slug = Str::slug($food->nama_makanan) . '-' . Str::lower(Str::random(5)); } // 2. AUTO-CATEGORIZATION (SMART LOGIC) // Jalankan hanya jika category_id belum diisi manual atau nama makanan berubah if (empty($food->category_id) || $food->isDirty('nama_makanan')) { $productName = strtolower($food->nama_makanan); $categories = Category::whereNotNull('keywords')->get(); $found = false; foreach ($categories as $cat) { $keywordsArray = explode(',', strtolower($cat->keywords)); foreach ($keywordsArray as $keyword) { $cleanKeyword = trim($keyword); if (!empty($cleanKeyword) && str_contains($productName, $cleanKeyword)) { $food->category_id = $cat->id; $food->kategori = $cat->name; $found = true; break 2; // Keluar dari kedua loop sekaligus } } } // 3. FALLBACK LOGIC if (!$found && empty($food->category_id)) { $default = Category::where('name', 'Dry Food') ->orWhere('name', 'Umum') ->first(); if ($default) { $food->category_id = $default->id; $food->kategori = $default->name; } else { $food->kategori = $food->kategori ?: 'Umum'; } } } // 4. SINKRONISASI TEKS KATEGORI // Jika category_id diisi manual di form, pastikan kolom 'kategori' (string) juga terupdate if ($food->isDirty('category_id') && !empty($food->category_id)) { $food->kategori = $food->category?->name ?? $food->kategori; } }); } /** * Accessor: Cek Status Expired */ public function getIsExpiredAttribute(): bool { return $this->expired_at ? $this->expired_at->isPast() : false; } }