Installation
composer require ursusarctosua/search-helper
Add the service provider to config/app.php:
Ursusarctosua\SearchHelper\SearchHelperServiceProvider::class,
Basic Usage
Inject the SearchHelper class into your controller/service:
use Ursusarctosua\SearchHelper\SearchHelper;
public function __construct(private SearchHelper $searchHelper) {}
First Query
Define a DTO (Data Transfer Object) for your entity filters (e.g., UserSearchDTO):
class UserSearchDTO {
public ?string $name;
public ?int $age;
public ?string $email;
}
Use it in a repository/service:
$query = $this->searchHelper->applyFilters(
User::class,
new UserSearchDTO($request->all())
);
$results = $query->get();
class ProductSearchDTO {
public ?string $name;
public ?string $category;
public ?int $minPrice;
public ?int $maxPrice;
}
class UserRepository {
public function search(UserSearchDTO $dto) {
return $this->searchHelper->applyFilters(User::class, $dto)->get();
}
}
SearchHelper into repositories.$query = $this->searchHelper->applyFilters(User::class, $dto);
$query = $this->searchHelper->applySort($query, $request->get('sort'));
$query = $this->searchHelper->applyPagination($query, $request->get('page'));
$this->searchHelper->addFilterRule('age', function ($query, $value) {
return $query->where('age', '>=', $value);
});
return UserResource::collection(
$this->searchHelper->applyFilters(User::class, $dto)->paginate()
);
Case Sensitivity in Filters
str_contains or lower() for case-insensitive searches:
$this->searchHelper->addFilterRule('name', function ($query, $value) {
return $query->where('name', 'LIKE', "%{$value}%");
});
Null Handling
null DTO properties may break queries. Explicitly filter them:
$dto = new UserSearchDTO($request->all());
$dto->name = $dto->name ?? null; // Ensure null instead of empty string
Performance with Large Datasets
LIKE on indexed columns (e.g., WHERE name LIKE '%term%'). Use full-text search or prefix matching:
$query->where('name', 'LIKE', "{$value}%");
Caching Query Builders
$query = $this->searchHelper->applyFilters(User::class, $dto);
// Reuse $query for multiple operations (e.g., count + paginate).
$query = $this->searchHelper->applyFilters(User::class, $dto);
\DB::enableQueryLog();
$results = $query->get();
dd(\DB::getQueryLog());
spatie/laravel-data to validate DTOs before passing them to SearchHelper.Custom Filter Rules: Override or extend default rules via service provider:
$this->app->make('Ursusarctosua\SearchHelper\SearchHelper')->addFilterRule('custom_field', ...);
Integration with Eloquent: If using Eloquent, wrap Doctrine queries:
$query = $this->searchHelper->applyFilters(User::class, $dto);
return User::fromQuery($query)->get();
Localization: For multilingual apps, add locale-aware filters:
$this->searchHelper->addFilterRule('name', function ($query, $value) {
return $query->where('name', 'LIKE', "%" . trans('search.term') . "%");
});
Testing:
Mock SearchHelper in tests:
$mockHelper = Mockery::mock(SearchHelper::class);
$mockHelper->shouldReceive('applyFilters')
->once()
->andReturn(User::query()->where('active', true));
How can I help you explore Laravel packages today?