Demonstrates how to create nested resources, with restaurant menu categories and dishes. You can reorder Categories and Dishes in the Filament table.
In this project, we have two Models:
Here are the contents of both models with fields and relationships defined.
app/Models/Category.php
namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\HasMany; class Category extends Model{ use HasFactory; protected $fillable = ['name', 'position']; public function dishes(): HasMany { return $this->hasMany(Dish::class); }}
app/Models/Dish.php
namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsTo; class Dish extends Model{ use HasFactory; protected $fillable = [ 'category_id', 'name', 'price', 'position', ]; public function category(): BelongsTo { return $this->belongsTo(Category::class); }}
First, we need a way to abstract this functionality to have nested resources. The main idea is for every child page to have a parent resource. For that reason, we implement this trait.
app/Filament/Traits/HasParentResource.php
namespace App\Filament\Traits; use Exception;use Illuminate\Database\Eloquent\Builder;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\ModelNotFoundException; trait HasParentResource{ public Model|int|string|null $parent = null; public function bootHasParentResource(): void { if ($parent = (request()->route('parent') ?? request()->input('parent'))) { $parentResource = $this->getParentResource(); $this->parent = $parentResource::resolveRecordRouteBinding($parent); if (! $this->parent) { throw new ModelNotFoundException(); } } } public function getParentResource(): string { if (! isset(static::$parentResource)) { throw new Exception('Parent resource is not set for ' . static::class); } return static::$parentResource; } protected function applyFiltersToTableQuery(Builder $query): Builder { return $query->where(str($this->parent?->getTable())->singular()->append('_id'), $this->parent->getKey()); } public function ...