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 Form Bundle Laravel Package

alamirault/elasticsearch-form-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require alamirault/elasticsearch-form-bundle
    

    Register the bundle in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3):

    Alamirault\ElasticsearchBundle\AlamiraultElasticsearchFormBundle::class => ['all' => true],
    
  2. Configure Elasticsearch Client (config/packages/alamirault_elasticsearch_form.yaml):

    alamirault_elasticsearch_form:
        clients:
            default:
                connections:
                    - { host: "localhost", port: 9200 }
                logger: "@logger"
                indexes:
                    users:
                        mapping: "%kernel.project_dir%/config/elasticsearch/mapping/users.yml"
    
  3. Create a Form Type:

    // src/Form/ExampleFilterType.php
    use Alamirault\ElasticsearchBundle\Form\ElasticFilterTypeInterface;
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    
    class ExampleFilterType extends AbstractType implements ElasticFilterTypeInterface
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->add('uuid', TextType::class, [
                'elastic_filter_condition' => function (?string $value) {
                    return new \Elastica\Query\Match('uuid', $value);
                },
            ]);
        }
    }
    
  4. First Use Case: Inject ElasticsearchMaker in a controller and handle form submission:

    use Alamirault\ElasticsearchBundle\Maker\ElasticsearchMakerInterface;
    
    public function index(Request $request, ElasticsearchMakerInterface $elasticsearchMaker, FormFactoryInterface $formFactory)
    {
        $form = $formFactory->create(ExampleFilterType::class);
        $form->handleRequest($request);
    
        if ($form->isSubmitted() && $form->isValid()) {
            $results = $elasticsearchMaker->manageForm($form, $request, 'users');
            // Render results
        }
    }
    

Implementation Patterns

Form-Driven Query Building

  1. Field-Specific Elasticsearch Conditions: Attach query builders to form fields via elastic_filter_condition:

    $builder->add('name', TextType::class, [
        'elastic_filter_condition' => function (?string $value) {
            return $value ? new \Elastica\Query\QueryString($value) : null;
        },
    ]);
    
    • Common Patterns:
      • Exact Match: new \Elastica\Query\Term('field', $value)
      • Wildcard Search: new \Elastica\Query\Wildcard('field', $value . '*')
      • Range Queries: new \Elastica\Query\Range('age', ['gte' => 18])
      • Boolean Logic: Combine with new \Elastica\Query\BoolQuery() for AND/OR/NOT.
  2. Dynamic Query Composition: Use ElasticsearchMaker::manageForm() to merge all field conditions into a single query:

    $query = $elasticsearchMaker->manageForm($form, $request, 'index_name');
    $results = $elasticsearchMaker->makeSearch('index_name', $query);
    
  3. Pagination and Sorting: Leverage Symfony’s Paginator with Elasticsearch’s from/size:

    $query->setFrom($page * $limit)->setSize($limit);
    $sort = new \Elastica\Sort('timestamp', \Elastica\Sort::DESC);
    $query->addSort($sort);
    
  4. Integration with Serialization: Use Symfony’s Serializer to normalize/denormalize documents:

    $normalized = $serializer->normalize($entity);
    $doc = new \Elastica\Document($id, $normalized);
    $index->addDocument($doc);
    

Gotchas and Tips

Pitfalls

  1. Elasticsearch Version Mismatch:

    • The bundle uses ruflin/elastica v6.x, which may not support Elasticsearch 7+ features (e.g., _doc type).
    • Fix: Explicitly set the type to _doc for ES <7.2.0:
      $type = new \Elastica\Type($index, '_doc'); // Only for ES <7.2.0
      
  2. Null Handling in Filters:

    • Uninitialized form fields (null) may break queries. Always check:
      'elastic_filter_condition' => function (?string $value) {
          return $value ? new \Elastica\Query\Match('field', $value) : null;
      },
      
  3. Mapping Configuration:

    • If mappings are missing, Elasticsearch will default to dynamic: true, which may cause performance issues.
    • Tip: Predefine mappings in config/elasticsearch/mapping/*.yml and reference them in the bundle config.
  4. Circular References in Serialization:

    • Normalizing entities with circular references (e.g., User->Posts->User) will fail.
    • Fix: Use @Ignore annotations or customize the serializer context:
      $normalized = $serializer->normalize($entity, null, [
          'ignored_attributes' => ['posts'],
      ]);
      
  5. Proxy Configuration:

    • If Elasticsearch is behind a proxy, ensure the proxy option is set in the bundle config:
      connections:
          - { host: "proxy.example.com", port: 8080, proxy: "http://real-es:9200" }
      

Debugging Tips

  1. Log Raw Queries: Enable debug logging for the logger.api channel to inspect queries:

    services:
        logger.api:
            class: Monolog\Logger
            arguments: ["elasticsearch"]
            calls:
                - [pushHandler, ["@monolog.handler"]]
    
  2. Test Queries Manually: Use ElasticsearchMaker::makeSearch() directly to test queries:

    $query = new \Elastica\Query\MatchAll();
    $results = $elasticsearchMaker->makeSearch('users', $query);
    
  3. Handle Deprecation Warnings: Elasticsearch 7+ emits deprecation warnings for legacy APIs. Suppress them in the client config:

    $client->getConnection()->setDeprecationMode(\Elastica\Connection::DEPRECATION_MODE_SILENT);
    

Extension Points

  1. Custom Query Builders: Extend the ElasticFilterTypeInterface to add reusable conditions:

    class CustomFilterType extends AbstractType implements ElasticFilterTypeInterface
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->add('date_range', RangeType::class, [
                'elastic_filter_condition' => [$this, 'buildDateRangeQuery'],
            ]);
        }
    
        public function buildDateRangeQuery(?array $range)
        {
            if (!$range) return null;
            return new \Elastica\Query\Range('created_at', $range);
        }
    }
    
  2. Post-Processing Results: Use Symfony’s event system to modify results before rendering:

    $eventDispatcher->addListener(
        'elasticsearch.results',
        function (ResultsEvent $event) {
            $event->setResults($event->getResults()->map(...));
        }
    );
    
  3. Bulk Operations: Batch document updates using IndexMaker:

    $index = $elasticsearchMaker->getIndex('users', IndexMaker::WRITE);
    $bulk = new \Elastica\Bulk();
    foreach ($users as $user) {
        $bulk->addDocument($index, $user->getId(), $user->getData());
    }
    $bulk->send();
    
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.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor