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 Searcher Laravel Package

shureban/laravel-searcher

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Installation:

    composer require shureban/laravel-searcher
    

    Register the service provider in config/app.php:

    Shureban\LaravelSearcher\SearcherServiceProvider::class,
    

    Publish the config file (optional):

    php artisan vendor:publish --provider="Shureban\LaravelSearcher\SearcherServiceProvider"
    
  2. First Use Case: Create a searcher class in app/Http/Searchers (e.g., UserSearcher.php):

    namespace App\Http\Searchers;
    
    use App\Models\User;
    use Illuminate\Database\Eloquent\Builder;
    use Shureban\LaravelSearcher\Filters\Like;
    use Shureban\LaravelSearcher\Searcher;
    
    class UserSearcher extends Searcher
    {
        protected function getQuery(): Builder
        {
            return User::query();
        }
    
        protected function getFilters(): array
        {
            return [
                'name' => new Like('name'),
                'email' => new Like('email'),
            ];
        }
    }
    
  3. First Request Handling: Create a request class (e.g., UserSearchRequest.php) with validation rules:

    namespace App\Http\Requests;
    
    use Illuminate\Foundation\Http\FormRequest;
    use Illuminate\Validation\Rules\In;
    use Shureban\LaravelSearcher\Enums\SortType;
    
    class UserSearchRequest extends FormRequest
    {
        public function rules(): array
        {
            return [
                'name' => 'nullable|string|max:255',
                'email' => 'nullable|email',
                'sort_column' => ['nullable', new In(['name', 'email', 'created_at'])],
                'sort_type' => ['nullable', new In([SortType::ASC, SortType::DESC])],
            ];
        }
    }
    
  4. First Controller Usage:

    namespace App\Http\Controllers;
    
    use App\Http\Requests\UserSearchRequest;
    use App\Http\Searchers\UserSearcher;
    use Illuminate\Http\JsonResponse;
    
    class UserController extends Controller
    {
        public function search(UserSearchRequest $request): JsonResponse
        {
            $searcher = new UserSearcher($request);
            $results = $searcher->paginate(); // or ->get(), ->all()
    
            return response()->json($results);
        }
    }
    

Implementation Patterns

1. Searcher Class Structure

  • Base Class: Extend Shureban\LaravelSearcher\Searcher.

  • Key Methods:

    • getQuery(): Return the base Eloquent query builder.
    • getFilters(): Define request param → filter mappings.
    • sortColumn() (optional): Customize default sort column.
    • applySortBy() (optional): Override sort logic for specific columns.
  • Example Workflow:

    class ProductSearcher extends Searcher
    {
        protected function getQuery(): Builder
        {
            return Product::with(['category', 'reviews']);
        }
    
        protected function getFilters(): array
        {
            return [
                'price' => new BetweenRange('price'),
                'category_id' => new Equal('category_id'),
                'in_stock' => new Boolean('is_active'),
                'name' => new Like('name'),
                'reviews.rating' => new Relation('reviews', new Gte('rating')),
            ];
        }
    }
    

2. Filter Patterns

Basic Filters

Filter Class Use Case Example
Equal Exact match 'id' => new Equal('id')
Like Partial match (LIKE) 'name' => new Like('name')
Between Range (numeric) 'price' => new Between('price')
BetweenRange Range (numeric, inclusive) 'salary' => new BetweenRange('salary')
BetweenDates Date range 'created_at' => new BetweenDates('created_at')
In/NotIn Array of values 'statuses' => new In('status')
Gt/Gte/Lt/Lte Greater/Less than 'age' => new Gt('age')
IsNull NULL checks 'image_id' => new IsNull('image_id')

Advanced Filters

Filter Class Use Case Example
OrNull Match value or NULL 'manager_id' => new OrNull(new Equal('manager_id'))
OrEmpty Match value or empty string 'full_name' => new OrEmpty(new Like('full_name'))
MultipleOr Combine filters with OR logic 'owner_id' => new MultipleOr(new Equal('user_id'), new Like('manager_id'))
Relation Filter nested relations 'reviews.rating' => new Relation('reviews', new Gte('rating'))
Callback Custom SQL logic 'only_every_even' => new Callback(fn($query, $value) => $query->whereRaw('(id % 2 = 0)'))

3. Sorting Patterns

Default Sorting

Override sortColumn() to customize the default sort field:

protected function sortColumn(): ?string
{
    return $this->request->get('sort_column', 'name'); // Default to 'name'
}

Custom Sort Logic

Override applySortBy() for complex sorting (e.g., multi-column sorts):

protected function applySortBy(Builder $query, string $sortColumn, string $sortType): Builder
{
    return match ($sortColumn) {
        'name' => $query->orderBy('name', $sortType)->orderBy('created_at', $sortType),
        'price' => $query->orderByRaw('ABS(price - 100)', $sortType),
        default => parent::applySortBy($query, $sortColumn, $sortType),
    };
}

4. Pagination and Collection Methods

Method Use Case Example
get() Get results as a Collection $searcher->get()
all() Get all results (no pagination) $searcher->all()
paginate() Get paginated LengthAwarePaginator $searcher->paginate(15)

5. Integration with API Resources

Combine with Laravel API Resources for structured responses:

// UserSearcher.php
public function toArray($request): array
{
    return [
        'data' => $this->paginate()->through(fn($user) => new UserResource($user)),
        'meta' => ['page' => $this->paginate()->currentPage()],
    ];
}

6. Testing Patterns

Unit Testing Searchers

public function test_searcher_filters()
{
    $request = new UserSearchRequest(['name' => 'John']);
    $searcher = new UserSearcher($request);

    $query = $searcher->getQuery();
    $query->toSql(); // Should contain `WHERE name LIKE '%John%'`

    $this->assertDatabaseHas('users', ['name' => 'John']);
}

Feature Testing Endpoints

public function test_search_endpoint()
{
    $response = $this->get('/api/users/search?name=John');
    $response->assertStatus(200)
             ->assertJsonStructure(['data', 'meta']);
}

Gotchas and Tips

1. Common Pitfalls

Filter Mismatches

  • Issue: Request param names in getFilters() must exactly match the request input keys.
    // ❌ Fails: 'user_name' !== 'name'
    return ['user_name' => new Like('name')];
    
  • Fix: Ensure consistency between request validation and filter keys.

Null Handling

  • Issue: IsNull may not work as expected with OrNull/OrEmpty due to query precedence.
    // ❌ May not work as intended
    return [
        'id' => new OrNull(new Equal('id')),
        'is_null' => new IsNull('id'), // Conflicts with above
    ];
    
  • Fix: Use IsNull alone or clarify logic with Callback.

Relation Filtering

  • Issue: Nested relation filters (e.g., Relation('reviews', ...)) require the relation to be eager-loaded in getQuery().
    // ❌ Fails: Relation not loaded
    return ['reviews.rating' => new Relation('
    
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.
craftcms/url-validator
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony