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

Algolia Search Bundle Laravel Package

algolia/algolia-search-bundle

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Install the package**:
   ```bash
   composer require algolia/search-bundle
  1. Configure environment variables in .env:
    ALGOLIA_APP_ID=your_app_id
    ALGOLIA_API_KEY=your_admin_api_key
    
  2. Define indices in config/packages/algolia_search.yaml:
    algolia_search:
      indices:
        - name: products
          class: App\Entity\Product
    
  3. Index existing data via CLI:
    php bin/console search:import
    

First Use Case: Searching Products

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,
        ]);
    }
}

Implementation Patterns

1. Indexing Workflows

Batch Indexing

  • Use search:import command for one-time bulk imports:
    php bin/console search:import --indices=products,articles
    
  • For atomic reindexing (zero-downtime):
    php bin/console search:import --indices=products --atomic
    

Conditional Indexing

  • Skip indexing unpublished entities:
    algolia_search:
      indices:
        - name: posts
          class: App\Entity\Post
          index_if: isPublished  # Method or property
    

Event-Driven Indexing

  • Subscribe to Doctrine events for real-time updates:
    algolia_search:
      doctrine_subscribed_events:
        - onFlush
        - onClear
    

2. Search Patterns

Basic Search

$results = $searchService->search(
    $entityManager,
    Product::class,
    'query',
    ['hitsPerPage' => 10]
);

Advanced Querying

  • Use Algolia’s query parameters:
    $results = $searchService->search(
        $entityManager,
        Product::class,
        'query',
        [
            'filters' => 'category:electronics',
            'attributesToHighlight' => ['name', 'description'],
        ]
    );
    

Pagination

  • Leverage Algolia’s pagination:
    $results = $searchService->search(
        $entityManager,
        Product::class,
        'query',
        ['page' => 2, 'hitsPerPage' => 20]
    );
    

3. Customization

Custom Normalizers

  • Extend 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),
            ];
        }
    }
    
  • Register in services.yaml:
    services:
        App\Normalizer\CustomProductNormalizer:
            tags: ['algolia.normalizer', { class: App\Entity\Product }]
    

Custom Search Responses

  • Extend 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());
        }
    }
    

4. Testing

  • Mock Algolia Client:
    use Algolia\SearchBundle\Client\AlgoliaClient;
    
    $client = $this->createMock(AlgoliaClient::class);
    $client->method('search')->willReturn(new SearchResponse([], 0, 0));
    
    $container->set(AlgoliaClient::class, $client);
    

Gotchas and Tips

Pitfalls

  1. API Key Permissions

    • Ensure your ALGOLIA_API_KEY has both search and add permissions for the index.
    • Debug: Check Algolia’s API key dashboard for missing permissions.
  2. Proxy/Headers Issues

    • If behind a proxy, configure headers in $requestOptions:
      $searchService->search($entityManager, Product::class, 'query', [
          'headers' => ['X-Forwarded-For' => '127.0.0.1'],
      ]);
      
  3. Circular References in Normalization

    • Avoid normalizing entities with circular references (e.g., UserPost).
    • Fix: Use ignore_attributes in config or custom normalizers.
  4. Rate Limits

    • Batch size defaults to 500. Increase if hitting rate limits:
      algolia_search:
          batch_size: 1000
      
  5. Atomic Reindex Failures

    • If moveIndex fails during atomic reindex, manually trigger:
      php bin/console search:move-index products products_backup
      

Debugging Tips

  1. Enable Debug Logging Add to config/packages/dev/algolia_search.yaml:

    algolia_search:
        debug: true
    

    Logs will appear in var/log/dev.log.

  2. Inspect Raw Algolia Responses Use SearchServiceResponse::getRawResponse():

    $rawResponse = $searchService->search($entityManager, Product::class, 'query');
    dump($rawResponse->getRawResponse());
    
  3. Validate Index Structure Use Algolia’s API Console to verify:

    • Index settings (e.g., searchableAttributes).
    • Sample records.

Performance Tips

  1. Partial Indexing

    • Use index_if to exclude irrelevant records:
      algolia_search:
          indices:
              - name: active_products
                class: App\Entity\Product
                index_if: isActive
      
  2. Async Indexing

    • Offload indexing to a queue (e.g., Symfony Messenger):
      algolia_search:
          doctrine_subscribed_events: []  # Disable real-time events
      
    • Process events via a worker:
      use Algolia\SearchBundle\Event\IndexEvent;
      
      $bus->dispatch(new IndexEvent($entity));
      
  3. Cache Search Results

    • Cache responses in Symfony’s cache system:
      $cacheKey = 'algolia_products_' . md5($query);
      $results = $cache->get($cacheKey, function() use ($searchService, $entityManager, $query) {
          return $searchService->search($entityManager, Product::class, $query);
      });
      

Extension Points

  1. Custom Index Names

    • Dynamically set index names per environment:
      algolia_search:
          indices:
              - name: '%env(ALGOLIA_PRODUCTS_INDEX)%'
                class: App\Entity\Product
      
  2. Multi-Tenant Indices

    • Use a tenant_id suffix:
      $indexName = 'products_' . $tenantId;
      $searchService->search($entityManager, Product::class, 'query', [], $indexName);
      
  3. Custom Search Clients

    • Replace the default AlgoliaClient:
      services:
          Algolia\SearchBundle\Client\AlgoliaClient:
              class: App\Client\CustomAlgoliaClient
      
  4. Webhook-Based Indexing

    • Trigger indexing via Algolia’s webhooks:
      use Algolia\SearchBundle\Event\IndexEvent;
      
      $eventDispatcher->dispatch(new IndexEvent($entity, 'webhook'));
      

Configuration Quirks

  1. Doctrine Proxy Support

    • The bundle avoids proxies by default (see #341).
    • Workaround: Use ClassUtils::getClass($entity) for proxies.
  2. **Symfony 6

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.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui