shammaa / laravel-search
Professional, high-performance search library for Laravel with MySQL Full-Text Search, advanced query builder, Arabic support, and search analytics
Installs: 2
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/shammaa/laravel-search
Requires
- php: ^8.1
- illuminate/cache: ^9.0|^10.0|^11.0|^12.0
- illuminate/database: ^9.0|^10.0|^11.0|^12.0
- illuminate/queue: ^9.0|^10.0|^11.0|^12.0
- illuminate/support: ^9.0|^10.0|^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0
- phpunit/phpunit: ^10.0
README
A professional, high-performance search library for Laravel with MySQL Full-Text Search, advanced query builder, Arabic support, and search analytics.
β¨ Features
Core Features
- π MySQL Full-Text Search - Fast search using native FULLTEXT indexes (no external dependencies)
- π Advanced Query Builder - Powerful, fluent query builder with filters, facets, and sorting
- π Arabic Language Support - Excellent Arabic search capabilities
- β‘ Auto-Indexing - Automatic FULLTEXT index creation and management
- π Search Analytics - Track searches, popular queries, and statistics
- π― Faceted Search - Advanced faceted search with multiple filters
- π‘ Auto-complete - Built-in autocomplete functionality
Performance & Scalability
- π Queue Support - Non-blocking index creation with queue jobs
- πΎ Smart Caching - Intelligent caching for search results and popular queries
- βοΈ Zero Configuration - Works out of the box with sensible defaults
- π Scalable - Handles millions of records efficiently
Developer Experience
- π¨ Type Safe - Full type hints and strict types (PHP 8.1+)
- π οΈ Artisan Commands - Comprehensive CLI tools for index management
- π¦ Laravel Integration - Seamless integration with Laravel ecosystem
- π Facade Support - Clean, expressive API
π Requirements
- PHP >= 8.1
- Laravel >= 9.0
- MySQL >= 5.6 (with FULLTEXT support) or MariaDB >= 10.0
π¦ Installation
1. Install via Composer
composer require shammaa/laravel-search
2. Publish Configuration (Optional)
php artisan vendor:publish --tag=search-config
This creates config/search.php with all available options.
3. Configure Environment (Optional)
Add these to your .env file if you want to customize defaults:
# MySQL Search Mode MYSQL_SEARCH_MODE=NATURAL_LANGUAGE # or BOOLEAN # Indexing Settings SEARCH_AUTO_INDEX=true SEARCH_QUEUE_INDEX=true SEARCH_QUEUE_NAME=search # Cache Settings SEARCH_CACHE_ENABLED=true SEARCH_CACHE_TTL=3600 # Analytics SEARCH_ANALYTICS_ENABLED=true
π Quick Start
Step 1: Add Searchable Trait to Your Model
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Shammaa\LaravelSearch\Traits\Searchable; class Article extends Model { use Searchable; /** * Define searchable fields with priority weights. * Higher priority = more important in search results. */ protected $searchable = [ 'title' => ['priority' => 2.0], // 2x more important 'content' => ['priority' => 1.0], // Base importance 'description' => ['priority' => 1.5], // 1.5x more important ]; /** * Define filterable fields for WHERE clauses. */ protected $filterable = [ 'status', 'category_id', 'author_id', 'published_at', 'tags', ]; /** * Define sortable fields. */ protected $sortable = [ 'published_at', 'views', 'created_at', ]; }
Step 2: Create FULLTEXT Index
php artisan search:index "App\Models\Article"
This creates a FULLTEXT index on your searchable fields. The index is created automatically when you first create a model, but you can also create it manually.
Step 3: Start Searching!
// Simple search $results = Article::search('Laravel')->get(); // Advanced search with filters $results = Article::search('Laravel') ->where('status', 'published') ->where('category_id', 5) ->whereBetween('published_at', [$start, $end]) ->orderBy('relevance', 'desc') ->paginate(20); // Autocomplete $suggestions = Article::autocomplete('Lara');
π Usage Guide
Basic Search
// Simple search $articles = Article::search('Laravel')->get(); // Search with pagination $articles = Article::search('Laravel')->paginate(20); // Limit and offset $articles = Article::search('Laravel') ->limit(50) ->offset(100) ->get(); // Count results $count = Article::search('Laravel')->count();
Advanced Filtering
WHERE Clauses
// Simple where Article::search('Laravel') ->where('status', 'published') ->where('category_id', 5) ->where('is_featured', true) ->get(); // Where with operator Article::search('Laravel') ->where('views', '>', 1000) ->get();
WHERE IN / NOT IN
// WhereIn Article::search('Laravel') ->whereIn('tags', ['php', 'laravel', 'symfony']) ->get(); // WhereNotIn Article::search('Laravel') ->whereNotIn('author_id', [1, 2, 3]) ->get();
NULL Checks
// WhereNull Article::search('Laravel') ->whereNull('deleted_at') ->get(); // WhereNotNull Article::search('Laravel') ->whereNotNull('published_at') ->get();
Range Queries
// WhereBetween Article::search('Laravel') ->whereBetween('published_at', ['2024-01-01', '2024-12-31']) ->get(); // WhereBetween with dates Article::search('Laravel') ->whereBetween('created_at', [ now()->subDays(30), now() ]) ->get();
Faceted Search
Faceted search allows you to get aggregated counts for different field values:
$results = Article::search('Laravel') ->facets(['category', 'author', 'tags', 'year']) ->get(); // Access facets $facets = $results->facets; // [ // 'category' => [ // ['value' => 'Tutorial', 'count' => 45], // ['value' => 'News', 'count' => 23], // ], // 'author' => [...], // ... // ] // Facets work with pagination too $paginated = Article::search('Laravel') ->facets(['category', 'author']) ->paginate(20); $facets = $paginated->facets;
Sorting
// Sort by relevance (default) Article::search('Laravel') ->orderBy('relevance', 'desc') ->get(); // Sort by field Article::search('Laravel') ->orderBy('published_at', 'desc') ->get(); // Multiple sorts Article::search('Laravel') ->orderBy('relevance', 'desc') ->orderBy('published_at', 'desc') ->orderBy('views', 'desc') ->get();
Autocomplete
// Get autocomplete suggestions $suggestions = Article::autocomplete('Lara'); // Returns: ['Laravel', 'Laravel Nova', 'Laravel Horizon'] // With custom limit $suggestions = Article::autocomplete('Lara', 20); // Using the facade use Shammaa\LaravelSearch\Facades\Search; $suggestions = Search::autocomplete(Article::class, 'Lara', 10);
Arabic Search
The package automatically supports Arabic text search:
// Search in Arabic $articles = Article::search('Ψ¨Ψ±Ω Ψ¬Ψ©')->get(); // Mixed Arabic and English $articles = Article::search('Laravel Ψ¨Ψ±Ω Ψ¬Ψ©')->get();
Using the Facade
use Shammaa\LaravelSearch\Facades\Search; // Search $results = Search::search(Article::class, 'Laravel') ->where('status', 'published') ->get(); // Autocomplete $suggestions = Search::autocomplete(Article::class, 'Lara'); // Popular searches $popular = Search::popularSearches(10); // Search statistics $stats = Search::stats(); // Clear cache Search::clearCache();
π― Artisan Commands
Index Management
# Create FULLTEXT index for a model php artisan search:index "App\Models\Article" # Use queue for indexing (recommended for large datasets) php artisan search:index "App\Models\Article" --queue # Reindex (drops and recreates FULLTEXT index) php artisan search:reindex "App\Models\Article" # Clear index php artisan search:clear "App\Models\Article"
Statistics & Monitoring
# Show all indexes statistics php artisan search:stats # Show specific model stats php artisan search:stats --model="App\Models\Article" # Show analytics (popular searches, etc.) php artisan search:stats --analytics
βοΈ Configuration
The config/search.php file contains all configuration options:
MySQL Configuration
'mysql' => [ // Search mode: NATURAL_LANGUAGE or BOOLEAN 'search_mode' => env('MYSQL_SEARCH_MODE', 'NATURAL_LANGUAGE'), // Minimum word length for FULLTEXT search 'min_word_length' => env('MYSQL_MIN_WORD_LENGTH', 4), // Index name prefix 'index_prefix' => env('MYSQL_INDEX_PREFIX', 'ft_'), ],
Indexing Configuration
'indexing' => [ // Auto-create indexes when models are created 'auto' => env('SEARCH_AUTO_INDEX', true), // Use queue for indexing operations 'queue' => env('SEARCH_QUEUE_INDEX', true), // Queue name for indexing jobs 'queue_name' => env('SEARCH_QUEUE_NAME', 'search'), // Batch size for bulk operations 'batch_size' => env('SEARCH_BATCH_SIZE', 1000), // Chunk size for processing 'chunk_size' => env('SEARCH_CHUNK_SIZE', 100), ],
Cache Configuration
'cache' => [ // Enable search result caching 'enabled' => env('SEARCH_CACHE_ENABLED', true), // Cache store to use 'store' => env('SEARCH_CACHE_STORE', 'default'), // Cache TTL in seconds (1 hour) 'ttl' => env('SEARCH_CACHE_TTL', 3600), // Popular searches cache TTL (2 hours) 'popular_ttl' => env('SEARCH_CACHE_POPULAR_TTL', 7200), // Autocomplete cache TTL (30 minutes) 'autocomplete_ttl' => env('SEARCH_CACHE_AUTOCOMPLETE_TTL', 1800), ],
Analytics Configuration
'analytics' => [ // Enable search analytics 'enabled' => env('SEARCH_ANALYTICS_ENABLED', true), // Analytics table name 'table' => env('SEARCH_ANALYTICS_TABLE', 'search_analytics'), // Track searches with no results 'track_empty' => env('SEARCH_ANALYTICS_TRACK_EMPTY', false), ],
Performance Configuration
'performance' => [ // Eager load relationships 'eager_load' => env('SEARCH_EAGER_LOAD', true), // Select only needed fields 'select_fields' => env('SEARCH_SELECT_FIELDS', false), // Maximum results per query 'max_results' => env('SEARCH_MAX_RESULTS', 10000), ],
π§ Advanced Usage
Custom Search Modes
MySQL supports two search modes:
Natural Language Mode (Default)
// In config/search.php 'mysql' => [ 'search_mode' => 'NATURAL_LANGUAGE', ],
Best for: Natural language queries, relevance ranking
Boolean Mode
// In config/search.php 'mysql' => [ 'search_mode' => 'BOOLEAN', ],
Allows operators like +, -, *, "phrase":
// Must contain "Laravel" Article::search('+Laravel')->get(); // Must contain "Laravel" but not "Vue" Article::search('+Laravel -Vue')->get(); // Exact phrase Article::search('"Laravel Framework"')->get(); // Wildcard Article::search('Lara*')->get();
Queue Configuration
For large datasets, use queues for indexing:
// In config/search.php 'indexing' => [ 'queue' => true, 'queue_name' => 'search', ],
Make sure your queue worker is running:
php artisan queue:work --queue=search
Manual Index Management
use App\Models\Article; // Manually create index for a model instance $article = Article::find(1); $article->searchable(); // This is automatically called on model creation if auto-indexing is enabled
π Performance
Benchmarks
Based on testing with typical hardware:
| Records | Search Time | Memory Usage |
|---|---|---|
| 10K | 10-50ms | ~2MB |
| 100K | 50-150ms | ~5MB |
| 1M | 100-500ms | ~10MB |
| 10M | 500ms-2s | ~20MB |
Performance varies based on hardware, query complexity, and data characteristics.
Optimization Tips
- Use Caching: Enable caching for frequently searched queries
- Queue Indexing: Use queues for large datasets
- Limit Results: Use
limit()to reduce result set size - Select Fields: Only select needed fields with
select() - Index Optimization: Ensure your MySQL FULLTEXT indexes are optimized
- MySQL Configuration: Adjust
ft_min_word_lenfor shorter words
MySQL FULLTEXT Configuration
To search for words shorter than 4 characters, modify MySQL configuration:
# In my.cnf or my.ini [mysqld] ft_min_word_len = 2
Then rebuild your indexes:
php artisan search:reindex "App\Models\Article"
π Troubleshooting
No Search Results
-
Check if index exists:
php artisan search:stats --model="App\Models\Article" -
Verify minimum word length:
- MySQL default is 4 characters
- Words shorter than this won't be indexed
- Solution: Adjust
ft_min_word_lenin MySQL config
-
Check searchable fields:
// Make sure fields are defined protected $searchable = [ 'title' => ['priority' => 1.0], 'content' => ['priority' => 1.0], ];
Slow Search Performance
-
Enable caching:
SEARCH_CACHE_ENABLED=true
-
Use queue for indexing:
SEARCH_QUEUE_INDEX=true
-
Limit results:
Article::search('query')->limit(100)->get();
-
Check MySQL FULLTEXT index:
SHOW INDEX FROM articles WHERE Index_type = 'FULLTEXT';
Index Creation Fails
-
Check table engine:
- Must be InnoDB or MyISAM
- InnoDB recommended for MySQL 5.6+
-
Check column types:
- FULLTEXT only works with TEXT and VARCHAR columns
-
Check MySQL version:
- MySQL 5.6+ required for InnoDB FULLTEXT
π€ Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Development Setup
# Clone repository git clone https://github.com/shammaa/laravel-search.git cd laravel-search # Install dependencies composer install # Run tests (when available) composer test
π License
This package is open-sourced software licensed under the MIT license.
π¨βπ» Author
Shadi Shammaa
- Email: shadi.shammaa@gmail.com
- GitHub: @shammaa
π Credits
This package uses MySQL Full-Text Search instead of external search engines, making it:
- β Easy to install (no external dependencies)
- β Cost-effective (100% free)
- β Simple to maintain (uses your existing MySQL database)
- β Production-ready (battle-tested MySQL technology)
Perfect for applications that need powerful search without the complexity of managing external search servers like Elasticsearch or Meilisearch.
π Additional Resources
πΊοΈ Roadmap
- Add comprehensive test suite
- Add highlighting support
- Add search suggestions based on analytics
- Add multi-language stemming
- Add search result export
- Add search query builder UI component
- Add Livewire components for search UI
Made with β€οΈ for the Laravel community