Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Select Tree Laravel Package

codewithdennis/filament-select-tree

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require codewithdennis/filament-select-tree:4.x
    php artisan filament:assets
    
  2. Basic Usage (Relationship-Based): For a BelongsTo relationship:

    use CodeWithDennis\FilamentSelectTree\SelectTree;
    
    SelectTree::make('category_id')
        ->relationship('category', 'name', 'parent_id')
    

    For a BelongsToMany relationship:

    SelectTree::make('categories')
        ->relationship('categories', 'name', 'parent_id')
    
  3. Non-Relationship Usage:

    SelectTree::make('category_id')
        ->query(fn() => Category::query(), 'name', 'parent_id')
    

First Use Case

Scenario: Display a hierarchical category selection in a Filament form.

use App\Models\Category;

SelectTree::make('category_id')
    ->label('Select Category')
    ->relationship('category', 'name', 'parent_id')
    ->searchable()
    ->required();

Implementation Patterns

Common Workflows

1. Form Integration

  • Single Selection (BelongsTo):
    SelectTree::make('parent_category_id')
        ->relationship('parentCategory', 'name', 'parent_id')
        ->label('Parent Category')
        ->required();
    
  • Multi-Selection (BelongsToMany):
    SelectTree::make('subcategories')
        ->relationship('subcategories', 'name', 'parent_id')
        ->label('Subcategories')
        ->multiple()
        ->enableBranchNode();
    

2. Dynamic Query Filtering

  • Filter the parent query to load only active categories:
    SelectTree::make('categories')
        ->relationship('categories', 'name', 'parent_id')
        ->modifyQueryUsing(fn($query) => $query->where('is_active', true));
    

3. Table Filters

  • Use in Filament Tables for hierarchical filtering:
    Filters\Filter::make('category_filter')
        ->form([
            SelectTree::make('categories')
                ->relationship('categories', 'name', 'parent_id')
                ->enableBranchNode()
                ->independent(false),
        ])
        ->query(function (Builder $query, array $data) {
            return $query->when($data['categories'], fn($q) =>
                $q->whereHas('categories', fn($q) => $q->whereIn('id', $data['categories']))
            );
        });
    

4. Custom Tree Structure

  • Override the tree structure entirely:
    SelectTree::make('custom_tree')
        ->getTreeUsing(function () {
            return [
                [
                    'name' => 'Electronics',
                    'value' => 'electronics',
                    'children' => [
                        ['name' => 'Phones', 'value' => 'phones'],
                        ['name' => 'Laptops', 'value' => 'laptops'],
                    ],
                ],
            ];
        });
    

5. Prepend/Append Static Items

  • Add a "None" option to the top:
    SelectTree::make('categories')
        ->relationship('categories', 'name', 'parent_id')
        ->prepend([
            'name' => 'None',
            'value' => null,
            'disabled' => true,
        ]);
    

Integration Tips

With Eloquent Relationships

  • Ensure your model has the correct parent_id column and a children() relationship method:
    public function children()
    {
        return $this->hasMany(Category::class, 'parent_id');
    }
    

Performance Optimization

  • Use storeResults() to cache query results if the tree is static:

    SelectTree::make('categories')
        ->relationship('categories', 'name', 'parent_id')
        ->storeResults();
    
  • Disable search if not needed to reduce client-side processing:

    SelectTree::make('categories')
        ->relationship('categories', 'name', 'parent_id')
        ->searchable(false);
    

Conditional Logic

  • Dynamically enable/disable options based on state:
    SelectTree::make('categories')
        ->relationship('categories', 'name', 'parent_id')
        ->disabledOptions(function ($state) {
            return $state['is_admin'] ? [] : [1, 2]; // Disable options for non-admins
        });
    

Gotchas and Tips

Pitfalls

  1. Strict Parent Filtering

    • By default, if a parent node is filtered out, its children are promoted to root. Disable this with:
      ->strictNullParentRootNodes();
      
    • Debug Tip: Use dd($component->getResults()) to inspect the tree structure after filtering.
  2. Key Mismatches

    • If your model uses code instead of id for relationships, specify the key:
      ->withKey('code')
      
    • Gotcha: Forgetting this causes silent failures where the tree loads but selections don’t save.
  3. Closure Evaluation Timing

    • prepend()/append() closures are deferred. Ensure dependencies (e.g., $this) are available:
      ->prepend(fn() => ['name' => $this->getCustomOption(), 'value' => null])
      
  4. PHP 8.5 Deprecations

    • Avoid null array offsets (e.g., $array[null] = 'value'). Use explicit keys:
      ->getTreeUsing([
          ['name' => 'Root', 'value' => 1, 'children' => []],
      ]);
      
  5. Search Behavior

    • Search is case-insensitive by default. For case-sensitive searches, override the search logic via getTreeUsing.

Debugging Tips

  1. Inspect Tree Structure

    • Use ->getTreeUsing() to manually define the tree for debugging:
      ->getTreeUsing(function () {
          $tree = Category::with('children')->get()->toTree();
          return $tree->toArray();
      });
      
  2. Check Query Logs

    • Enable Laravel query logging to verify filtered queries:
      DB::enableQueryLog();
      // Use the field...
      dd(DB::getQueryLog());
      
  3. Validate Relationships

    • Ensure the relationship method exists in your model:
      // Model
      public function categories()
      {
          return $this->belongsToMany(Category::class);
      }
      
  4. Clear Filament Cache

    • After major changes, run:
      php artisan filament:cache:clear
      

Extension Points

  1. Custom Styling

    • Override the default CSS by publishing assets:
      php artisan vendor:publish --tag=filament-select-tree-assets
      
    • Extend the SCSS variables in resources/css/filament-select-tree.scss.
  2. Event Listeners

    • Listen for tree changes via JavaScript:
      document.addEventListener('filament-select-tree-updated', (event) => {
          console.log('Selected values:', event.detail);
      });
      
  3. Custom Validation

    • Add validation rules to the field:
      SelectTree::make('categories')
          ->relationship('categories', 'name', 'parent_id')
          ->rules(['required', 'min:1']);
      
  4. Localization

    • Translate labels dynamically:
      ->placeholder(__('Select a category'))
      ->emptyLabel(__('No categories found'))
      
  5. Access Control

    • Restrict options based on user roles:
      ->disabledOptions(function () {
          return auth()->user()->is_admin ? [] : [1, 2, 3];
      });
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ilhamsyabani/laravel-volt-starter
thethunderturner/filament-latex
ghostcompiler/laravel-querybuilder
webrek/laravel-telescope-mongodb
anousss007/blatui
zatona-eg/zatona-eg-api
cocosmos/filament-sticky-save-bar
patrickbussmann/oauth2-apple
3brs/enterprise-security-bundle
anousss007/vigilance
supportpal/eloquent-model
ardenexal/fhir-models
laravel-at/laravel-image-sanitize
romalytar/yammi-audit-log-laravel
ardenexal/fhir-validation
arshaviras/weather-widget
laravel-chronicle/core
sunchayn/nimbus
daikazu/eloquent-salesforce-objects
unseen-codes/chat