Changelog
v2.0.0
Major release adding OpenSearch support and hardening the query builder. See the Upgrade Guide for migration steps.
Added
- Nested attributes — casts, accessors, and mutators work on dot-notation paths (
'hotel.location.lat' => 'float'); nested values are assigned/retrieved by their dotted key and serialized in place intoArray()/toJson(). - Multi-index queries — read from a wildcard/comma index pattern (
$index = 'logs-*') while writing to a concrete index ($writeIndex/getWriteIndex()). Documents write back to their origin_index, andfrom()/into()override the read/write index per call. - Attribute casting — Eloquent-style
$castscovering the full Laravel catalog (primitives, dates,decimal, enums + enum collections,encrypted*,hashed, array-object/ collection casts, and customCastsAttributes), plus accessors & mutators viaAttribute::makeand$appends. - Bulk insert & upsert —
Model::bulk([...])andModel::upsert([...])with automatic chunking, a configurable record cap (bulk.max/bulk.chunk_size), and aBulkResultDTO reporting per-item successes and failures. - OpenSearch driver selectable via
SEARCH_DRIVER— the same fluent API works across Elasticsearch and OpenSearch. - OpenSearch authentication: basic-auth, API key, and AWS SigV4 (
aws/aws-sdk-phpis an optional dependency, installed only when SigV4 is used). - Multi-host clusters via a comma-separated
SEARCH_HOST. Elasticsearch load-balances across all hosts; OpenSearch uses the first (single-endpoint by design — front a cluster with a load balancer or managed endpoint). - Active query validation: invalid bool clauses,
match/terms_setshapes, and order/range operators now throwInvalidQuerywhen the query is built.
Changed
- Environment variables renamed
ELASTICSEARCH_*→SEARCH_*(no fallback). ConnectionInterfacenow exposessearch(),count(),index(),update()instead of a driver-specificgetClient().BridgeBuilder::all()is nowall(int $perPage = 15, array $columns = ['*'])and returns a bounded first page.- Bool clauses (
must,should,must_not,filter) always render as arrays of clause objects, so chaining multiple clauses of the same type is valid. multiMatch()andmatchPhrase()nest asboolmustclauses (noasRaw()needed).count()sends only thequeryto the count API.- Aggregation results are stored per collection instance instead of a global
Collectionmacro; multiple aggregations coexist and no longer leak across requests.
Removed
- Deprecated
from/torange operators — onlygt/gte/lt/lteare valid.
Fixed
getAttribute()no longer errors when a hit has no_source.PaginatedCollection::links()no longer fails on empty result sets (returnstotal: 0with empty cursors).- Filters are no longer silently dropped outside a bool context — the query is promoted to a
boolwith the filters attached. ::fake()no longer references a test-only class; the fake connection is driver-agnostic.save()no longer mutates shared query-builder state during its existence check.
For older releases, switch to the v1.x docs using the version selector above.