Download the PHP package php-es-orm/es-orm without Composer
On this page you can find all versions of the php package php-es-orm/es-orm. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download php-es-orm/es-orm
More information about php-es-orm/es-orm
Files in php-es-orm/es-orm
Package es-orm
Short Description An Eloquent-style, type-safe, production-ready Elasticsearch ORM for PHP, with full Query DSL, Aggregations, Search After, PIT, Bulk, Alias and Reindex support.
License MIT
Informations about the package es-orm
php-es-orm
An Eloquent-style, type-safe, production-ready Elasticsearch ORM for PHP.
php-es-orm gives you a Laravel Eloquent-like developer experience on top of
Elasticsearch, without hiding what Elasticsearch can do. It keeps the native
Query DSL, Aggregations, search_after, Point In Time (PIT), Bulk, Aliases,
Reindex and everything else within reach — and never pretends Elasticsearch is
MySQL.
- Eloquent-style models:
Model,find,create,save,update,delete, … - A fluent, chainable Query Builder
- Full Elasticsearch Query DSL, including Bool and Nested queries
- A first-class raw DSL escape hatch, mixable with the ORM API
- Aggregations, Highlight, Suggest, Geo, Scroll, Search After, PIT
- Bulk API for batch create/update/delete (never a loop of single calls)
- Index / Mapping / Alias / Reindex / Migration management
- Casts, accessors & mutators, scopes, soft deletes, events, observers, relations
- Laravel integration as an optional adapter: the core has zero Laravel dependency
- PHP 8.2+, PSR-4 / PSR-12, PHPStan clean
Table of contents
- Requirements
- Installation
- Configuration
- Connecting to Elasticsearch
- Creating a Model
- CRUD
- Query Builder
- Query DSL
- Bool queries
- Nested queries
- Raw DSL
- Source filtering
- Sorting
- Operators
- Pagination
- Aggregations
- Highlight
- Suggest
- Geo search
- Scroll
- Bulk
- MGET & Multi Search
- Casts
- Accessors & Mutators
- Fillable / Guarded
- Scopes
- Soft deletes
- Events & Observers
- Relations
- Mapping
- Index management
- Alias management
- Reindex
- Index migrations
- Caching
- Debugging
- Error handling
- Laravel integration
- Docker & tooling
- Testing
- FAQ
- Architecture
Requirements
- PHP 8.2+
ext-json- The official
elasticsearch/elasticsearchclient (^9.0), which is installed by Composer - Elasticsearch 8.x (9.x compatibility is preserved where possible)
Installation
You also need a PSR-18 HTTP client (Guzzle is the usual choice):
Configuration
The package ships with a configuration file you can copy into your project:
Supported connection keys: hosts, cloud_id, api_key (+ optional
api_key_id), username/password, bearer_token, http_client,
http_client_options, timeout, connect_timeout, ssl_certificate,
ssl_key, ssl_ca, ssl_verification, logger.
Authentication recap — Basic Auth (
username+password), API Key (api_key), Bearer Token (bearer_token), Cloud ID (cloud_id) and TLS (ssl_*) are all supported.
Connecting to Elasticsearch
Standalone PHP
Models resolve a shared connection manager lazily from config/es_orm.php
(relative to the current working directory) or from the file pointed at by the
ES_ORM_CONFIG environment variable:
You can also inject the manager explicitly (recommended in tests and in custom bootstrapping):
Laravel
Nothing to do beyond installing the package — the service provider is auto-discovered. See Laravel integration.
Creating a Model
The index defaults to the snake-cased class name plus s when $index is not
set.
CRUD
Find-or-create helpers
Atomic counters
increment() / decrement() write the change with a single Painless script
update (retry_on_conflict included), so concurrent writers never lose an
update, and the in-memory attributes stay in sync:
Batch operations (Bulk API)
All batch helpers use the Elasticsearch Bulk API in a single request per chunk — they never loop over single-document calls:
The chunk size defaults to bulk.chunk_size (1000) and can be overridden per
call: User::bulkCreate($docs, 500).
Query Builder
Every where() appends to the current AND group; every orWhere() starts a new
group. Nested closures reuse the exact same builder:
Available where helpers:
Execution helpers
sole() throws ModelNotFoundException when nothing matches and
MultipleRecordsFoundException when more than one document matches.
Query DSL
The native Elasticsearch queries are first-class citizens:
Bool queries
The Eloquent-style closure form and the explicit bool-occurrence form both
compile to the Elasticsearch bool DSL:
Nested queries
Raw DSL
Anything the ORM does not wrap is still reachable, and it can be mixed with the ORM API in the same query. Raw DSL is an advanced API — your input is sent as-is.
Source filtering
Sorting
Operators
| ORM operator | Elasticsearch DSL |
|---|---|
=, == |
term |
!=, <> |
bool.must_not / term |
>, >=, <, <= |
range |
like |
wildcard (% → *) |
not like |
bool.must_not / wildcard |
in |
terms |
not in |
bool.must_not / terms |
Pagination
Deep pagination primitives:
Elasticsearch's
from + sizepagination is capped (index.max_result_window, 10 000 by default). PrefercursorPaginate()/search_after()/pit()for large result sets.
Aggregations
Shorthand builders:
Complex, nested aggregations:
Highlight
Suggest
Geo search
Scroll
each() scrolls automatically when no searchAfter()/pit() is configured,
and uses search_after (with a PIT) otherwise. Scroll handles are always
cleared:
Bulk
Individual failures are surfaced through EsOrm\Exceptions\BulkException
(->failures()).
MGET & Multi Search
Casts
Supported cast names: integer/int, float/double/decimal, boolean/bool,
string, array, json, object/map, datetime/date_time/timestamp, date.
Accessors & Mutators
The getter also receives the whole attribute array as its second argument, so
cross-field accessors are possible. The method must declare an Attribute
return type to be recognised.
Fillable / Guarded
Scopes
Local scopes are plain methods prefixed with scope:
Object scopes implement EsOrm\Scope\Scope; global scopes are registered on the
model and applied to every query:
Soft deletes
Events & Observers
Model events are dispatched through EsOrm\Events\EventDispatcher:
creating, created, saving, saved, updating, updated, deleting,
deleted, restoring, restored, forceDeleting, forceDeleted.
A Laravel application may replace the dispatcher with a bridge to the framework
event system via Model::setEventDispatcher().
Relations
Relations are a batch-aware convenience layer (not SQL joins) designed so eager loading never triggers an N+1:
Available: HasOne, HasMany, BelongsTo. Nested eager loads are supported via
dot notation (Article::with('author.company')).
Mapping
A model declares its mapping; convert it to an index body with
mappingDefinition() or hand the raw array to the IndexManager.
Or build a mapping fluently:
Index management
Alias management
Reindex
Index migrations
Run them through the framework-agnostic runner:
Or via Artisan (Laravel): php artisan es:migrate,
php artisan es:migrate:rollback, php artisan es:migrate:status.
Caching
Query caching is disabled by default. Enable it with an opt-in per query and
a configurable driver implementing EsOrm\Contracts\CacheStoreInterface:
Debugging
The connection records every request (HTTP method, endpoint, index, body,
duration and errors) into EsOrm\Support\QueryLog when logging.enabled is on.
Error handling
| Exception | Thrown when |
|---|---|
ConnectionException |
transport failure, server 5xx, retry exhaustion |
QueryException |
a non-index / non-bulk request failed |
IndexException |
an index-level request failed |
BulkException |
a bulk request failed (->failures() exposes per-item errors) |
MappingException |
an invalid mapping or unsupported cast type |
InvalidQueryException |
an invalid builder call / unknown operator |
ModelNotFoundException |
findOrFail() / firstOrFail() found nothing |
ValidationException |
invalid input rejected before hitting Elasticsearch |
SearchException, PaginationException, DslException, ReindexException |
other specific failures |
All extend EsOrm\Exceptions\EsOrmException.
Laravel integration
The core has no Laravel dependency; the integration is an adapter registered by package discovery.
Publish the config:
Models work unchanged inside a Laravel project.
Docker & tooling
docker-compose.yml provides Elasticsearch 8.15 and Kibana (profile kibana).
Testing
FAQ
Do I need Laravel to use this package? No. The core ORM is framework agnostic. Laravel is an optional adapter.
Does it replace the Elasticsearch Query DSL?
No. The DSL is fully reachable, and rawQuery() / raw() let you pass any DSL
the ORM does not wrap.
How do I avoid deep pagination problems?
Use cursorPaginate(), searchAfter() or pit() instead of large offset()
values.
Are bulk operations really batched?
Yes — every bulkCreate()/bulkUpdate()/bulkDelete() call issues Bulk API
requests, one per chunk.
How do I change the default page size?
Set pagination.default_size in config/es_orm.php, or pass it to
paginate().
Is rawQuery() safe?
It is an advanced API: input is forwarded to Elasticsearch as-is. Use it only
with trusted input; normal user input should go through the DSL builder.
Architecture
- Model is a thin, typed façade: it never performs HTTP.
- Query Builder accumulates DSL value objects and compiles a single request body.
- DSL value objects (
MatchQuery,TermsQuery,NestedQuery, aggregations, sorts, …) each exposetoArray(). - Connection owns transport concerns: retry, logging, exception mapping.
- Client is a thin adapter over the official Elasticsearch client.
- Laravel integration is a separate adapter on top.
This separation keeps the API stable and lets new Elasticsearch features be added without breaking existing code.
License
MIT — see LICENSE.
All versions of es-orm with dependencies
ext-json Version *
elasticsearch/elasticsearch Version ^9.5
psr/log Version ^1.1 || ^2.0 || ^3.0