Weave 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

Elastically Laravel Package

jolicode/elastically

jolicode/elastically is an elegant Elasticsearch client for PHP. It simplifies index management, document indexing, and query building with a fluent API, making search integration cleaner and more maintainable in Symfony and other PHP applications.

Deep Wiki
Context7

Getting Started

  • Install with composer require jolicode/elastically. Add symfony/serializer only if you want automatic model hydration, and doctrine/orm only if you plan to use Doctrine populators. The Symfony Flex recipe creates config/packages/elastically.yaml.
  • First thing to read: the generated elastically.yaml and one index config file. That is where the whole integration lives.
  • Minimal setup: one client + one index whose settings/mappings/aliases are externalized.
# config/packages/elastically.yaml
elastically:
    clients:
        default:
            hosts: ['%env(ELASTICSEARCH_DSN)%']
    indices:
        articles:
            client: default
            config: '%kernel.project_dir%/config/elastically/articles.yaml'
# config/elastically/articles.yaml
settings:
    number_of_shards: 1
mappings:
    properties:
        title:       { type: text }
        publishedAt: { type: date }
aliases:
    - articles
  • Create and inspect the index:
php bin/console elastically:index:create articles
php bin/console elastically:index:list
  • First use case — search from a service. Bind the logical index in services.yaml instead of injecting the client everywhere:
services:
    _defaults:
        bind:
            Elastica\Index $articlesIndex: '@elastica.index.articles'
final class ArticleSearch
{
    public function __construct(private Elastica\Index $articlesIndex) {}

    public function search(string $term): array
    {
        $query = new Elastica\Query\MatchQuery('title', $term);

        return array_map(
            fn ($result) => $result->getData(),
            $this->articlesIndex->search($query)->getResults()
        );
    }
}

Implementation Patterns

  • Inject indices/finders, not the client. Register one binding per index (Elastica\Index $articlesIndex: '@elastica.index.articles'). Keep JoliCode\Elastically\Client only in code that manages indices or populates them.
  • Use IndexBuilder for lifecycle operations rather than calling Elastica directly. It applies your YAML config and handles aliases:
$builder = $client->getIndexBuilder();

$builder->createIndex('articles');  // raw creation
$builder->buildIndex('articles');   // create from config, alias-aware
$builder->reindex('articles');      // build a fresh index and swap the alias
  • Always query through the alias. Readers target articles (alias), writers build articles_<timestamp> (physical index). This is what makes zero-downtime reindexing possible.
  • Bulk indexing is the default, not the exception. Use the bulk indexer / IndexBuilder for imports, flush in chunks, and check the bulk response for per-item errors — a bulk call can return HTTP 200 while individual documents failed.
  • Populators for Doctrine-driven data. Implement the populator interface, tag it, and drive it with elastically:index:populate articles --populator=.... Make populators idempotent and chunked so they can be re-run during reindexes.
  • Model hydration. Configure a Serializer normalizer/denormalizer for your DTOs and read Result::getModel(); keep getData() / getDocument() for cases where you only need raw source. This separates search plumbing from domain objects.
  • Wrap queries in a repository/service per index. Query DSL in controllers becomes unmaintainable fast. A dedicated ArticleSearch/ArticleRepository also gives you a clean seam for tests.
  • Reindex workflow. Edit YAML → elastically:index:create articles in fresh environments; for running environments use the “live”/reindex flow (elastically:index:live articles or IndexBuilder::reindex()), which builds the new index, populates it, and swaps aliases atomically.

Gotchas and Tips

  • Mapping changes are not applied by elastically:index:update. Elasticsearch only permits additive mapping changes; changing a field type requires a new index plus alias swap. Plan reindexes, don't patch.
  • Alias naming is the classic trap. If the alias has the same name as the physical index, the reindex/live flow gets confusing. Use articles_v1 physically and articles as the alias.
  • No type-based autowiring for multiple indices. Elastica\Index and Elastica\Finder need explicit named bindings, otherwise Symfony cannot decide which index to inject.
  • Refresh semantics bite in tests and UX. Newly indexed documents are not searchable until refresh. Use refresh=wait_for on writes when immediacy matters; otherwise batch and refresh explicitly.
  • Clear the Symfony cache after editing index YAML (bin/console cache:clear). Stale config in commands is a common source of “my mappings didn't change”.
  • Pin compatible versions. Package, Elastica, and Elasticsearch versions move together (6.x/7.x/8.x). Copied snippets from a different major version are the most frequent source of weird failures.
  • ES 7+ has no mapping types. Avoid Elastica\Type-based code and index/type-style service IDs; use index-level searches.
  • Populators can exhaust memory. Use Doctrine iterators, flush the bulk buffer regularly, and tune chunk size. Watch for documents that silently fail in the bulk response.
  • Prefixing affects physical names only. index_prefix changes what is created in the cluster; commands and service IDs still use the logical name. When confused, run elastically:index:list and compare with _cat/indices?v / _cat/aliases?v.
  • Debugging aids: the elasticsearch Monolog channel for the PHP client, _cat APIs for cluster state, and elastically:index:list for the package's own view. For zero-downtime reindexes, verify search results on the new alias before deleting the old physical index.
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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource