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

Laravel Searchable Laravel Package

mozex/laravel-searchable

Add a Searchable trait to any Eloquent model to search multiple columns and related data (relations, morphs, even cross-database) via a single ->search() call. Works with Laravel Scout and includes optional Filament table/global search integration.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require mozex/laravel-searchable
    

    No additional configuration or migrations required.

  2. Basic Model Integration: Add the Searchable trait to your Eloquent model and define searchableColumns():

    use Mozex\Searchable\Searchable;
    
    class Comment extends Model
    {
        use Searchable;
    
        public function searchableColumns(): array
        {
            return ['body', 'author.name']; // Direct column + relation
        }
    
        public function author()
        {
            return $this->belongsTo(User::class);
        }
    }
    
  3. First Search Query:

    $results = Comment::search('laravel')->get();
    // Or with query constraints:
    $results = Comment::where('published', true)
        ->search($request->input('q'))
        ->paginate();
    

Where to Look First

  • Documentation: mozex.dev/docs/laravel-searchable/v1
  • Source Code: Focus on Searchable trait and searchableColumns() method
  • Filament Integration: Check advancedSearchable() macro if using Filament

Implementation Patterns

Core Workflow

  1. Define Searchable Columns:

    public function searchableColumns(): array
    {
        return [
            'title',                     // Direct column
            'author.name',               // BelongsTo relation
            'tags.name',                 // HasMany relation
            'commentable:post.title',    // Morph relation
        ];
    }
    
  2. Search Execution:

    // Basic search
    Model::search('query')->get();
    
    // With query builder
    Model::query()
        ->where('status', 'active')
        ->search($request->q)
        ->get();
    
  3. Column Filtering:

    // Search specific columns
    Model::search('query', in: ['title', 'body'])->get();
    
    // Add/remove columns dynamically
    Model::search('query', include: ['slug'], except: ['author.name'])->get();
    

Advanced Patterns

  1. Morph Relations:

    // Requires morph map setup
    Relation::morphMap(['post' => Post::class, 'video' => Video::class]);
    
    public function searchableColumns(): array
    {
        return ['commentable:post.title', 'commentable:video.name'];
    }
    
  2. Cross-Database Relations:

    // Automatically handles external connections
    Model::search('query', externalLimit: 200)->get();
    
  3. Filament Integration:

    // Table column search
    TextColumn::make('title')->advancedSearchable();
    
    // Global search provider
    $panel->globalSearch(SearchableGlobalSearchProvider::class);
    
  4. Query Builder Integration:

    // When $query->search() conflicts
    $model->applySearch($query, 'term', in: ['title']);
    

Integration Tips

  • Scout Compatibility: Use trait aliasing to avoid method conflicts:
    use Mozex\Searchable\Searchable as DatabaseSearchable;
    
    class Model
    {
        use DatabaseSearchable { scopeSearch as scopeDatabaseSearch; }
        use \Laravel\Scout\Searchable;
    }
    
  • Performance Optimization:
    • Add indexes to frequently filtered columns (not search columns)
    • Consider Scout for large datasets (>1M rows)
    • Use pg_trgm indexes on PostgreSQL for LIKE performance

Gotchas and Tips

Common Pitfalls

  1. Method Conflict Resolution:

    • Scout Conflict: Always alias the trait method when using both Scout and this package
    • Builder Overrides: Custom builders may shadow the search() method - use applySearch() instead
  2. Case Sensitivity:

    • Defaults to case-insensitive (database-dependent)
    • No runtime flag to change - modify column collation instead
  3. Cross-Database Limits:

    • External relation searches cap at 50 IDs by default
    • Adjust with externalLimit parameter if needed
  4. Performance Caveats:

    • Leading wildcards (%term%) prevent index usage
    • Complex relations add correlated subqueries
    • Monitor query plans for deep relation searches

Debugging Tips

  1. Query Inspection:

    $query = Model::query()->search('term')->toSql();
    dd($query); // View generated SQL
    
  2. Column Validation:

    • Verify all relation paths exist in your model
    • Check morph map aliases match exactly
  3. Filament Issues:

    • Ensure getGloballySearchableAttributes() is defined for each resource
    • Verify column names match exactly with searchableColumns()

Extension Points

  1. Custom Search Logic:

    // Override search behavior
    public function scopeCustomSearch($query, $term)
    {
        return $this->applySearch($query, $term, in: ['custom_column']);
    }
    
  2. Dynamic Column Configuration:

    // Conditional search columns
    public function searchableColumns()
    {
        return $this->isAdmin()
            ? ['title', 'body', 'author.name']
            : ['title', 'body'];
    }
    
  3. Advanced Filament Customization:

    // Custom global search provider
    class CustomSearchProvider extends SearchableGlobalSearchProvider
    {
        protected function getSearchableModels(): array
        {
            return [Post::class, Page::class];
        }
    }
    

Configuration Quirks

  1. Morph Relation Requirements:

    • Must define morph map in a service provider
    • Colon notation requires exact morph type aliases
  2. Relation Path Validation:

    • Nested relations must exist in the model hierarchy
    • Example: author.company.name requires authorcompanyname chain
  3. Database-Specific Behavior:

    • MySQL: Collation affects case sensitivity
    • PostgreSQL: Always case-insensitive for LIKE
    • SQLite: Case-sensitive for non-ASCII characters

Performance Optimization

  1. Query Structure:

    • The package generates WHERE (col1 LIKE '%term%' OR col2 LIKE '%term%')
    • For large tables, consider full-text indexes or Scout
  2. Relation Handling:

    • Each relation adds a correlated EXISTS subquery
    • Limit to essential relations for complex searches
  3. Memory Considerations:

    • Cross-database searches fetch external IDs into memory
    • Adjust externalLimit based on your data volume
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky