Install the package:
composer require araise/search-bundle
Enable MySQL MATCH AGAINST in Doctrine:
Add to config/packages/doctrine.yaml:
doctrine:
orm:
dql:
string_functions:
MATCH_AGAINST: araise\SearchBundle\Extension\Doctrine\Query\Mysql\MatchAgainst
Update schema:
php bin/console doctrine:schema:update --force
Annotate fields in your entity:
use araise\SearchBundle\Annotation\Index;
#[ORM\Entity]
class Post {
#[Index] // Marks this field for full-text search
private string $title;
}
Populate the index:
php bin/console araise:search:populate
Search for posts in a controller:
use araise\SearchBundle\Repository\IndexRepository;
#[Route('/search', name: 'search_posts')]
public function search(IndexRepository $indexRepo, Request $request) {
$query = $request->query->get('q');
$postIds = $indexRepo->search($query, Post::class);
// Fetch full entities via PostRepository
}
@Index on Doctrine entity properties.araise:search:populate (cron-friendly for large datasets).CustomSearchPopulateQueryBuilderInterface for filtered indexing.$ids = $indexRepo->search('query', Post::class);
$results = $indexRepo->searchEntities('query');
// Map results to objects manually
$options = new SearchOptions(['groups' => ['posts']]);
$ids = $indexRepo->search($query, Post::class, $options);
setMaxResults()/setFirstResult() on the fetched entities after retrieving IDs.araise:search:populate after entity CRUD operations (e.g., via event listeners).MySQL Dependency:
MATCH AGAINST requires MySQL. Test on your target DB early.Index Population:
--limit:
php bin/console araise:search:populate --limit=1000
--chunk-size for incremental updates.Case Sensitivity:
MATCH AGAINST is case-insensitive by default. Use BOOLEAN MODE for control:
// In a custom QueryBuilder hook
$qb->andWhere("MATCH_AGAINST($alias.title, :query) > 0")
->setParameter('query', $query . ' WITH QUERY EXPANSION');
Wildcards:
asterisk_search_enabled in araise_search.yaml if you don’t need * wildcards (improves performance).Field Formatting:
araise\CoreBundle\Formatter\FormatterInterface.php bin/console araise:search:status
MATCH AGAINST queries.preSearch/postSearch hooks to debug query results:
// In UserPreSearch::preSearch()
$qb->andWhere("MATCH_AGAINST($alias.title, :query) > 5"); // Boost relevance
Custom Scoring:
postSearch to filter/rank results:
public function postSearch(array $results, string $query): array {
return array_filter($results, fn($r) => $r['_matchQuote'] > 10);
}
Dynamic Indexing:
araise\SearchBundle\Event\SearchPopulateEventListener to skip entities conditionally.Alternative Backends:
MatchAgainst with a custom DQL function for non-MySQL databases (requires extending the bundle).text fields unless necessary.asterisk_search_enabled: Set to true only if you need wildcard searches (e.g., *term).araise:search:populate after adding/removing @Index fields.How can I help you explore Laravel packages today?