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

Elasticsearch Laravel Package

api-platform/elasticsearch

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require api-platform/elasticsearch
    

    Ensure your elasticsearch PHP client is installed (ext-elasticsearch or elasticsearch/elasticsearch).

  2. Configure Elasticsearch Connection Add to .env:

    ELASTICSEARCH_DSN=elasticsearch://localhost:9200
    

    Or configure via config/services.php:

    'elasticsearch' => [
        'dsn' => env('ELASTICSEARCH_DSN', 'elasticsearch://localhost:9200'),
    ],
    
  3. Enable Elasticsearch for a Resource Annotate your entity with @ApiResource and add searchable: true:

    use ApiPlatform\Metadata\ApiResource;
    use ApiPlatform\Metadata\GetCollection;
    
    #[ApiResource(
        operations: [new GetCollection()],
        searchable: true,
    )]
    class Book {}
    
  4. First Search Request Trigger a search via API:

    curl -X GET "http://your-api/books?search=query"
    

    The package automatically indexes and searches your data.


Implementation Patterns

Workflow: Indexing and Searching

  1. Automatic Indexing

    • Elasticsearch indexes are created automatically when you fetch a collection with ?search=....
    • No manual index management required for basic use.
  2. Customizing Search Behavior Override the default search behavior via a custom Search operation:

    use ApiPlatform\Metadata\Operation;
    use ApiPlatform\Metadata\GetCollection;
    
    #[ApiResource(
        operations: [
            new GetCollection(
                uriTemplate: '/books/search',
                method: 'GET',
                name: 'search_books',
                // Customize Elasticsearch query via `processor`
                processor: MyCustomSearchProcessor::class,
            ),
        ],
    )]
    class Book {}
    
  3. Pagination and Sorting Leverage Elasticsearch’s capabilities:

    # Pagination
    curl "http://your-api/books?search=query&page=2&limit=10"
    
    # Sorting
    curl "http://your-api/books?search=query&[sort]=title,asc"
    
  4. Filtering with Elasticsearch Use Elasticsearch’s query DSL via ?search[query]=...:

    curl "http://your-api/books?search[query]={\"bool\":{\"must\":[{\"match\":{\"title\":\"Laravel\"}}]}}"
    
  5. Integration with API Platform Filters Combine with API Platform’s built-in filters (e.g., SearchFilter, DateFilter):

    use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
    
    #[ApiResource(
        operations: [new GetCollection()],
        searchable: true,
        filters: [new SearchFilter()],
    )]
    class Book {}
    

Gotchas and Tips

Pitfalls

  1. Index Naming Conflicts

    • Elasticsearch indexes are named after the fully qualified class name (e.g., App\Entity\Book).
    • If you rename an entity, manually delete the old index or update the mapping:
      curl -X DELETE "http://localhost:9200/App_Entity_Book"
      
  2. Mapping Inconsistencies

    • Elasticsearch mappings are generated dynamically. If your entity schema changes (e.g., adding a new field), you may need to reindex:
      curl -X POST "http://your-api/books/_reindex"
      
    • For complex types (e.g., nested objects), manually define mappings via Elasticsearch\Client::putMapping().
  3. Performance with Large Datasets

    • Avoid real-time indexing for large datasets. Use bulk operations or schedule reindexing during low-traffic periods.
    • Monitor Elasticsearch cluster health:
      curl -X GET "http://localhost:9200/_cluster/health"
      
  4. CORS and Authentication

    • Elasticsearch’s default port (9200) is not secure. Use elasticsearch:9200 (TLS) in production.
    • If behind a proxy, configure ELASTICSEARCH_DSN with the proxy URL (e.g., http://proxy:9200).

Debugging Tips

  1. Enable Elasticsearch Logging Add to config/logging.php:

    'channels' => [
        'elasticsearch' => [
            'driver' => 'monolog',
            'handler' => 'stream',
            'path' => storage_path('logs/elasticsearch.log'),
            'level' => 'debug',
        ],
    ],
    

    Then log queries in your SearchProcessor:

    $this->logger->debug('Elasticsearch query:', ['query' => $query]);
    
  2. Inspect Index Mappings Dump mappings for debugging:

    curl -X GET "http://localhost:9200/App_Entity_Book/_mapping"
    
  3. Test Locally with Docker Use docker.elastic.co/elasticsearch/elasticsearch:8.5.0 for local development:

    # docker-compose.yml
    services:
      elasticsearch:
        image: docker.elastic.co/elasticsearch/elasticsearch:8.5.0
        environment:
          - discovery.type=single-node
          - xpack.security.enabled=false
        ports:
          - "9200:9200"
    

Extension Points

  1. Custom Search Processors Extend ApiPlatform\Elasticsearch\Processor\SearchProcessor to modify queries:

    use ApiPlatform\Elasticsearch\Processor\SearchProcessorInterface;
    
    class CustomSearchProcessor implements SearchProcessorInterface {
        public function process($data, Operation $operation, array $uriVariables, array $context): array {
            $query = $data['query'] ?? [];
            $query['bool']['must'][] = ['term' => ['active' => true]]; // Add custom filter
            return $data;
        }
    }
    
  2. Async Indexing Use Laravel Queues to defer indexing:

    use ApiPlatform\Elasticsearch\Indexer\IndexerInterface;
    
    class AsyncIndexer implements IndexerInterface {
        public function index($data, Operation $operation, array $context) {
            IndexElasticsearchJob::dispatch($data, $operation, $context);
        }
    }
    
  3. Multi-Tenancy Override index naming logic to include tenant IDs:

    use ApiPlatform\Elasticsearch\Indexer\IndexerInterface;
    
    class TenantAwareIndexer implements IndexerInterface {
        public function getIndexName(string $resourceClass, array $context): string {
            $tenantId = $context['tenant_id'] ?? 'default';
            return sprintf('%s_%s', $tenantId, $resourceClass);
        }
    }
    
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.
datacore/hub-sdk
alengo/sulu-http-cache-bundle
croct/coding-standard
croct/plug-php
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
imbo/imbo-coding-standard
visualbuilder/filament-lottie
servicioslineaonce/starter-kit
atomcoder/laravel-reorderable
irajul/filament-shadcn-theme
agtp/agtp-php
agtp/mod-php
centraldesktop/protobuf-php
trappistes/laravel-custom-fields