PHP code example of solution-forest / filament-tree
1. Go to this page and download the library: Download solution-forest/filament-tree library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
solution-forest / filament-tree example snippets
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->treeColumns(); // Adds parent_id, order, title columns
$table->timestamps();
});
// Or manually:
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->integer('parent_id')->default(-1)->index(); // Must default to -1!
$table->integer('order')->default(0);
$table->string('title');
$table->timestamps();
});
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use SolutionForest\FilamentTree\Concern\ModelTree;
class Category extends Model
{
use ModelTree;
protected $fillable = ['parent_id', 'title', 'order'];
protected $casts = [
'parent_id' => 'integer'
];
}
namespace App\Filament\Widgets;
use App\Models\Category;
use Filament\Forms\Components\TextInput;
use SolutionForest\FilamentTree\Widgets\Tree as BaseWidget;
class CategoryWidget extends BaseWidget
{
protected static string $model = Category::class;
protected static int $maxDepth = 3;
protected ?string $treeTitle = 'Categories';
protected bool $enableTreeTitle = true;
protected function getFormSchema(): array
{
return [
TextInput::make('title')->
// In your resource's ListRecords page
protected function getHeaderWidgets(): array
{
return [CategoryWidget::class];
}
// In your PanelProvider
public function panel(Panel $panel): Panel
{
return $panel
->pages([
CategoryTree::class,
]);
}
// In your CategoryResource
public static function getPages(): array
{
return [
'index' => Pages\ListCategories::route('/'),
'create' => Pages\CreateCategory::route('/create'),
'edit' => Pages\EditCategory::route('/{record}/edit'),
'tree' => Pages\CategoryTree::route('/tree'), // Add this line
];
}
public function getTreeRecordTitle(?\Illuminate\Database\Eloquent\Model $record = null): string
{
if (!$record) return '';
return "[{$record->id}] {$record->title}";
}
public function getTreeRecordIcon(?\Illuminate\Database\Eloquent\Model $record = null): ?string
{
if ($record->parent_id != -1) {
return null; // No icon for child records
}
return match ($record->title) {
'Categories' => 'heroicon-o-tag',
'Products' => 'heroicon-o-shopping-bag',
'Settings' => 'heroicon-o-cog',
default => 'heroicon-o-folder',
};
}
protected function hasDeleteAction(): bool { return true; }
protected function hasEditAction(): bool { return true; }
protected function hasViewAction(): bool { return false; }
protected static int $maxDepth = 4; // Limit nesting depth
public function getNodeCollapsedState(?\Illuminate\Database\Eloquent\Model $record = null): bool
{
return true; // Start with all nodes collapsed
}
// Used for all operations (fallback)
protected function getFormSchema(): array
{
return [
TextInput::make('title')->a(): array { /* ... */ }
protected function getEditFormSchema(): array { /* ... */ }
protected function getViewFormSchema(): array { /* ... */ }
use SolutionForest\FilamentTree\Concern\ModelTree;
use Spatie\Translatable\HasTranslations;
class Category extends Model
{
use HasTranslations, ModelTree;
protected $translatable = ['title'];
}
use LaraZeus\SpatieTranslatable\Actions\LocaleSwitcher;
use SolutionForest\FilamentTree\Concern\TreeRecords\Translatable;
class CategoryTree extends TreePage
{
use Translatable;
public function getTranslatableLocales(): array
{
return ['en', 'fr', 'es'];
}
protected function getActions(): array
{
return [LocaleSwitcher::make()];
}
}
use App\Models\Menuitem;
use Illuminate\Database\Eloquent\Builder;
class MenuItemsWidget extends Tree
{
// Accessing the current record in the widget
public ?Model $record = null;
protected function getTreeQuery(): Builder
{
return MenuItem::query()
->where('menu_id', $this->record?->id); // Filter by the current menu ID
}
class Category extends Model
{
use ModelTree;
public function determineOrderColumnName(): string
{
return 'sort_order'; // Instead of 'order'
}
public function determineParentColumnName(): string
{
return 'parent_category_id'; // Instead of 'parent_id'
}
public function determineTitleColumnName(): string
{
return 'name'; // Instead of 'title'
}
public static function defaultParentKey(): int
{
return 0; // Instead of -1
}
}
// Pre-collapse deep nodes to improve initial load
public function getNodeCollapsedState(?\Illuminate\Database\Eloquent\Model $record = null): bool
{
return $record && $record->getDepth() > 2;
}
// Custom tree depth per implementation
protected static int $maxDepth = 5;
public function getTreeRecordTitle(?\Illuminate\Database\Eloquent\Model $record = null): string
{
if (!$record) return '';
$title = $record->title;
// Add indicators
if ($record->children()->count() > 0) {
$title .= " ({$record->children()->count()})";
}
if (!$record->is_active) {
$title = "🚫 " . $title;
}
return $title;
}
return [
/**
* Default column names for tree structure
*/
'column_name' => [
'order' => 'order',
'parent' => 'parent_id',
'title' => 'title',
],
/**
* Default parent ID for root nodes
*/
'default_parent_id' => -1,
/**
* Default children relationship key
*/
'default_children_key_name' => 'children',
];