Install the Bundle
Add to composer.json:
"require": {
"blast-project/search-bundle": "^1.0"
}
Run composer require blast-project/search-bundle.
Configure ElasticSearch
Ensure ElasticSearch is running (locally via Docker or a remote instance). Update config/packages/blast_search.yaml with your ElasticSearch host:
blast_search:
client:
host: 'http://localhost:9200' # or your ElasticSearch endpoint
First Use Case: Indexing a Model
Define a searchable entity (e.g., Product) and annotate it with #[Searchable]:
use Blast\SearchBundle\Annotation\Searchable;
#[Searchable]
class Product {}
Register the bundle in config/bundles.php:
return [
// ...
Blast\SearchBundle\BlastSearchBundle::class => ['all' => true],
];
Run the indexer command to populate ElasticSearch:
php bin/console blast:search:index
Indexing Data
php bin/console blast:search:index Product
postPersist, postUpdate) via Doctrine listeners to keep ElasticSearch in sync:
use Blast\SearchBundle\Event\IndexerEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ProductIndexSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
IndexerEvent::POST_PERSIST => 'indexProduct',
IndexerEvent::POST_UPDATE => 'indexProduct',
];
}
public function indexProduct(IndexerEvent $event): void
{
$event->getIndexer()->index($event->getEntity());
}
}
Searching Data
SearchQueryBuilder to construct queries:
use Blast\SearchBundle\Query\SearchQueryBuilder;
$query = (new SearchQueryBuilder())
->select('id', 'name')
->from(Product::class)
->where('name', 'LIKE', '%phone%')
->limit(10);
$results = $query->getResults();
Custom Mappings
Override default mappings in config/packages/blast_search.yaml:
blast_search:
mappings:
Product:
properties:
name:
type: text
analyzer: custom_analyzer
price:
type: float
blast_search.client service to fos_elastica.client for compatibility.SearchQueryBuilder::setPage() and setLimit() for paginated results.SearchQueryBuilder to support aggregations:
$query->addAggregation('avg_price', 'avg', 'price');
ElasticSearch Version Mismatch
curl -X GET "http://localhost:9200/"
Ensure the response includes "version" and "tagline".Indexing Delays
$eventDispatcher->dispatch(new IndexerEvent($entity, IndexerEvent::POST_PERSIST));
Indexer::indexMany().Mapping Conflicts
php bin/console blast:search:drop-index Product
php bin/console blast:search:create-index Product
php bin/console blast:search:index Product
Enable Debug Logging
Add to config/packages/dev/blast_search.yaml:
blast_search:
client:
logging: true
Check logs in var/log/dev.log for ElasticSearch queries.
Test Queries
Use Kibana (port 5601 in the Docker setup) to manually test queries against your index.
Custom Indexers
Implement Blast\SearchBundle\Indexer\IndexerInterface for custom logic:
class CustomIndexer implements IndexerInterface
{
public function index($entity): void
{
// Custom indexing logic
}
}
Register it in services.yaml:
services:
Blast\SearchBundle\Indexer\CustomIndexer:
tags: ['blast_search.indexer']
Pre/Post Indexing Hooks Use Symfony events to modify entities before indexing:
# config/services.yaml
services:
App\EventListener\PreIndexListener:
tags:
- { name: kernel.event_listener, event: blast.search.pre_index, method: onPreIndex }
Async Indexing For performance, offload indexing to a queue (e.g., Symfony Messenger):
use Symfony\Component\Messenger\MessageBusInterface;
$bus->dispatch(new IndexMessage($entity));
Create a handler:
class IndexHandler
{
public function __invoke(IndexMessage $message)
{
$indexer->index($message->getEntity());
}
}
How can I help you explore Laravel packages today?