algolia/algolia-search-bundle
## Getting Started
### Minimal Setup
1. **Install the package**:
```bash
composer require algolia/search-bundle
.env:
ALGOLIA_APP_ID=your_app_id
ALGOLIA_API_KEY=your_admin_api_key
config/packages/algolia_search.yaml:
algolia_search:
indices:
- name: products
class: App\Entity\Product
php bin/console search:import
use Algolia\SearchBundle\Service\SearchServiceInterface;
class ProductController
{
public function __construct(
private SearchServiceInterface $searchService,
private EntityManagerInterface $entityManager
) {}
public function search(string $query): Response
{
$products = $this->searchService->search(
$this->entityManager,
Product::class,
$query
);
return $this->render('product/search.html.twig', [
'products' => $products,
]);
}
}
search:import command for one-time bulk imports:
php bin/console search:import --indices=products,articles
php bin/console search:import --indices=products --atomic
algolia_search:
indices:
- name: posts
class: App\Entity\Post
index_if: isPublished # Method or property
algolia_search:
doctrine_subscribed_events:
- onFlush
- onClear
$results = $searchService->search(
$entityManager,
Product::class,
'query',
['hitsPerPage' => 10]
);
$results = $searchService->search(
$entityManager,
Product::class,
'query',
[
'filters' => 'category:electronics',
'attributesToHighlight' => ['name', 'description'],
]
);
$results = $searchService->search(
$entityManager,
Product::class,
'query',
['page' => 2, 'hitsPerPage' => 20]
);
Algolia\SearchBundle\Normalizer\NormalizerInterface:
use Algolia\SearchBundle\Normalizer\NormalizerInterface;
class CustomProductNormalizer implements NormalizerInterface
{
public function normalize($object, string $format = null, array $context = []): array
{
return [
'name' => $object->getName(),
'price' => $object->getPrice(),
'custom_field' => $this->calculateCustomField($object),
];
}
}
services.yaml:
services:
App\Normalizer\CustomProductNormalizer:
tags: ['algolia.normalizer', { class: App\Entity\Product }]
Algolia\SearchBundle\Responses\SearchServiceResponse:
use Algolia\SearchBundle\Responses\SearchServiceResponse;
class CustomSearchResponse extends SearchServiceResponse
{
public function getFormattedResults(): array
{
return array_map(fn($hit) => $this->formatHit($hit), $this->getHits());
}
}
use Algolia\SearchBundle\Client\AlgoliaClient;
$client = $this->createMock(AlgoliaClient::class);
$client->method('search')->willReturn(new SearchResponse([], 0, 0));
$container->set(AlgoliaClient::class, $client);
API Key Permissions
ALGOLIA_API_KEY has both search and add permissions for the index.Proxy/Headers Issues
$requestOptions:
$searchService->search($entityManager, Product::class, 'query', [
'headers' => ['X-Forwarded-For' => '127.0.0.1'],
]);
Circular References in Normalization
User ↔ Post).ignore_attributes in config or custom normalizers.Rate Limits
500. Increase if hitting rate limits:
algolia_search:
batch_size: 1000
Atomic Reindex Failures
moveIndex fails during atomic reindex, manually trigger:
php bin/console search:move-index products products_backup
Enable Debug Logging
Add to config/packages/dev/algolia_search.yaml:
algolia_search:
debug: true
Logs will appear in var/log/dev.log.
Inspect Raw Algolia Responses
Use SearchServiceResponse::getRawResponse():
$rawResponse = $searchService->search($entityManager, Product::class, 'query');
dump($rawResponse->getRawResponse());
Validate Index Structure Use Algolia’s API Console to verify:
searchableAttributes).Partial Indexing
index_if to exclude irrelevant records:
algolia_search:
indices:
- name: active_products
class: App\Entity\Product
index_if: isActive
Async Indexing
algolia_search:
doctrine_subscribed_events: [] # Disable real-time events
use Algolia\SearchBundle\Event\IndexEvent;
$bus->dispatch(new IndexEvent($entity));
Cache Search Results
$cacheKey = 'algolia_products_' . md5($query);
$results = $cache->get($cacheKey, function() use ($searchService, $entityManager, $query) {
return $searchService->search($entityManager, Product::class, $query);
});
Custom Index Names
algolia_search:
indices:
- name: '%env(ALGOLIA_PRODUCTS_INDEX)%'
class: App\Entity\Product
Multi-Tenant Indices
tenant_id suffix:
$indexName = 'products_' . $tenantId;
$searchService->search($entityManager, Product::class, 'query', [], $indexName);
Custom Search Clients
AlgoliaClient:
services:
Algolia\SearchBundle\Client\AlgoliaClient:
class: App\Client\CustomAlgoliaClient
Webhook-Based Indexing
use Algolia\SearchBundle\Event\IndexEvent;
$eventDispatcher->dispatch(new IndexEvent($entity, 'webhook'));
Doctrine Proxy Support
ClassUtils::getClass($entity) for proxies.**Symfony 6
How can I help you explore Laravel packages today?