Download the PHP package matchory/elasticsearch without Composer

On this page you can find all versions of the php package matchory/elasticsearch. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package elasticsearch

Latest Stable Version Total Downloads Latest Unstable Version License

Laravel Elasticsearch Integration

This is a fork of the excellent library by @basemkhirat, who sadly seems to have abandoned it by now.
As we rely on this library quite heavily, we will attempt to keep it up to date and compatible with newer Laravel and Elasticsearch versions.

Changes in this fork:

If you're interested in contributing, please submit a PR or open an issue!

Features:

Table of Contents

Requirements

Installation

This section describes the installation process for all supported application types.

Install package using composer

Whether you're using Laravel or another framework, start by installing the package using composer:

Laravel Installation

If you have package autodiscovery disabled, add the service provider and facade to your config/app.php:

Lastly, publish the service provider to your configuration directory:

Generic app installation

You can install package with any composer-based application. While we can't provide general instructions, the following example should give you an idea of how it works:

Configuration (Laravel)

After publishing the service provider, a configuration file has been created at config/elasticsearch.php. Here, you can add one or more Elasticsearch connections, with multiple servers each. Take a look at the following example:

If you'd like to use Elastic\Elasticsearch with Laravel Scout, you can find the scout specific settings in config/scout.php.

Artisan commands (Laravel)

With the artisan commands included with this package, you can create or update settings, mappings and aliases. Note that all commands use the default connection by default. You can change this by passing the --connection <your_connection_name> option.

The following commands are available:

es:indices:list: List all indices on server

es:indices:create: Create indices defined in config/es.php

Note that creating operation skips the index if exists.

es:indices:update: Update indices defined in config/es.php

Note that updating operation updates indices setting, aliases and mapping and doesn't delete the indexed data.

es:indices:drop: Drop index

Be careful when using this command, as you will lose your index data!
Running drop command with --force option will skip all confirmation messages.

Reindexing data (with zero downtime)

First, why reindexing?
Changing index mapping doesn't reflect without data reindexing, otherwise your search results will not work on the right way.
To avoid down time, your application should work with index alias not index name.
The index alias is a constant name that application should work with to avoid change index names.

Assume that we want to change mapping for my_index, this is how to do that:

  1. Add alias as example my_index_alias to my_index configuration and make sure your application is working with it.

  2. Update index with command:

  3. Create a new index as example my_new_index with your new mapping in configuration file.

  4. Reindex data from my_index into my_new_index with command:

  5. Remove my_index_alias alias from my_index and add it to my_new_index in configuration file and update with command:

Usage as a Laravel Scout driver

First, follow Laravel Scout installation.
All you have to do is updating the following lines in config/scout.php:

Have a look at Laravel Scout documentation, too!

Elasticsearch models

Each index type has a corresponding "Model" which is used to interact with that type. Models allow you to query for data in your types or indices, as well as insert new documents into the type. Elasticsearch Models mimic Eloquent models as closely as possible: You can use model events, route bindings, advanced attribute methods and more. If there is any Eloquent functionality you're missing, open an issue, and we'll be happy to add it!.

Supported features:

  • Attributes
  • Events
  • Route bindings
  • Global and Local Query Scopes
  • Replicating models

A minimal model might look like this:

Index Names

This model is not specifically bound to any index and will simply use the index configured for the given Elasticsearch connection. To specifically target an index, you may define an index property on the model:

Connection Names

By default, all Elasticsearch models will use the default connection that's configured for your application. If you would like to specify a different connection that should be used when interacting with a particular model, you should define a $connection property on the model:

Mapping type

If you're still using mapping types, you may add a type property to your model to indicate the mapping _type to be used for queries.

Mapping Types are deprecated:
Please note that Elastic has deprecated mapping types and will remove them in the next major release. You should not rely on them to continue working.

Default Attribute Values

By default, a newly instantiated model instance will not contain any attribute values. If you would like to define the default values for some of your model's attributes, you may define an attributes property on your model:

Retrieving Models

Once you have created a model and its associated index type, you are ready to start retrieving data from your index. You can think of your Elasticsearch model as a powerful query builder allowing you to fluently query the index associated with the model. The model's all method will retrieve all the documents from the model's associated Elasticsearch index:

Adding additional constraints

The all method will return all the results in the model's index. However, since each Elasticsearch model serves as a query builder, you may add additional constraints to queries, and then invoke the get() method to retrieve the results:

Collections

As we have seen, Elasticsearch methods like all and get retrieve multiple documents from the index. However, these methods don't return a plain PHP array. Instead, an instance of Matchory\Elasticsearch\Collection is returned.

The Elasticsearch Collection class extends Laravel's base Illuminate\Support\Collection class, which provides a variety of helpful methods for interacting with data collections. For example, the reject method may be used to remove models from a collection based on the results of an invoked closure:

In addition to the methods provided by Laravel's base collection class, the Elasticsearch collection class provides a few extra methods that are specifically intended for interacting with collections of Elasticsearch models:

Result Meta data

Elasticsearch provides a few additional fields in addition to the hits of a query, like the total result amount, or the query execution time. The Elasticsearch collection provides getters for these properties:

Iterating

Since all of Laravel's collections implement PHP's iterable interfaces, you may loop over collections as if they were an array:

Chunking Results

Elasticsearch indices can grow quite huge. Your application may run out of memory if you would attempt to load tens of thousands of Elasticsearch documents via the all or get methods without an upper bound. Therefore, the default amount of documents fetched is set to 10. To change this, use the take method:

Retrieving individual Models

In addition to retrieving all the documents matching a given query, you may also retrieve single documents using the find, first, or firstWhere methods. Instead of returning a collection of models, these methods return a single model instance:

$posts = Post::ofType('news')->get(); php ES::index("my_index")->where("views", "<", 150)->get(); php ES::index("my_index")->where("views", "<=", 150)->get(); php ES::index("my_index")->where("title", "like", "foo")->get(); php ES::index("my_index")->where("hobbies", "exists", true)->get();

or

ES::index("my_index")->whereExists("hobbies", true)->get(); php ES::index("my_index")->whereIn("id", [100, 150])->get(); php ES::index("my_index")->whereBetween("id", 100, 150)->get();

or

ES::index("my_index")->whereBetween("id", [100, 150])->get(); php ES::index("my_index")->whereNot("status", "published")->get();

or

ES::index("my_index")->whereNot("status", "=", "published")->get(); php ES::index("my_index")->whereNot("views", ">", 150)->get(); php ES::index("my_index")->whereNot("views", ">=", 150)->get(); php ES::index("my_index")->whereNot("views", "<", 150)->get(); php ES::index("my_index")->whereNot("views", "<=", 150)->get(); php ES::index("my_index")->whereNot("title", "like", "foo")->get(); php ES::index("my_index")->whereNot("hobbies", "exists", true)->get();

or

ES::index("my_index")->whereExists("hobbies", true)->get(); php ES::index("my_index")->whereNotIn("id", [100, 150])->get(); php ES::index("my_index")->whereNotBetween("id", 100, 150)->get();

or

ES::index("my_index")->whereNotBetween("id", [100, 150])->get(); php

Find documents where status is "published" OR "featured"

ES::index("my_index") ->orWhere("status", "published") ->orWhere("status", "featured") ->get();

Combine AND and OR conditions

This finds documents where (category = "tech") AND (status = "published" OR status = "featured")

ES::index("my_index") ->where("category", "tech") ->orWhere("status", "published") ->orWhere("status", "featured") ->get();

orWhere supports all the same operators as where

ES::index("my_index")->orWhere("views", ">", 1000)->get(); ES::index("my_index")->orWhere("title", "like", "elasticsearch")->get(); ES::index("my_index")->orWhere("featured", "exists", true)->get(); php

At least 2 of the OR conditions must match

ES::index("my_index") ->orWhere("tag", "php") ->orWhere("tag", "laravel") ->orWhere("tag", "elasticsearch") ->minimumShouldMatch(2) ->get();

Can also use percentages

ES::index("my_index") ->orWhere("tag", "php") ->orWhere("tag", "laravel") ->orWhere("tag", "elasticsearch") ->minimumShouldMatch("75%") ->get(); php ES::index("my_index")->distance("location", ["lat" => -33.8688197, "lon" => 151.20929550000005], "10km")->get();

or

ES::index("my_index")->distance("location", "-33.8688197,151.20929550000005", "10km")->get();

or

ES::index("my_index")->distance("location", [151.20929550000005, -33.8688197], "10km")->get();
php ES::index("my_index")->body([ "query" => [ "bool" => [ "must" => [ [ "match" => [ "address" => "mill" ] ], [ "match" => [ "address" => "lane" ] ] ] ] ] ])->get();

Note that you can mix between query builder and array queries.

The query builder will will be merged with the array query.

ES::index("my_index")->body([ "_source" => ["content"]

"query" => [
     "bool" => [
         "must" => [
             [ "match" => [ "address" => "mill" ] ]
         ]
     ]
],

"sort" => [
    "_score"
]

])->select("name")->orderBy("created_at", "desc")->take(10)->skip(5)->get();

The result query will be

/ Array ( [index] => my_index [type] => my_type [body] => Array ( [_source] => Array ( [0] => content [1] => name ) [query] => Array ( [bool] => Array ( [must] => Array ( [0] => Array ( [match] => Array ( [address] => mill ) ) ) ) ) [sort] => Array ( [0] => _score [1] => Array ( [created_at] => desc ) ) ) [from] => 5 [size] => 10 [client] => Array ( [ignore] => Array ( ) ) ) / php ES::index("my_index")->search("hello")->get();

search with Boost = 2

ES::index("my_index")->search("hello", 2)->get();

search within specific fields with different weights

ES::index("my_index")->search("hello", function($search){ $search->boost(2)->fields(["title" => 2, "content" => 1]) })->get(); php $doc = ES::index("my_index")->highlight("title")->search("hello")->first();

Multiple fields Highlighting is allowed.

$doc = ES::index("my_index")->highlight("title", "content")->search("hello")->first();

Return all highlights as array using $doc->getHighlights() method.

$doc->getHighlights();

Also you can return only highlights of specific field.

$doc->getHighlights("title"); php ES::index("my_index")->search("hello")->first(); php ES::index("my_index")->search("hello")->count(); php

These queries are suitable for large amount of data.

A scrolled search allows you to do an initial search and to keep pulling batches of results

from Elasticsearch until there are no more results left.

It’s a bit like a cursor in a traditional database

$documents = ES::index("my_index")->search("hello") ->scroll("2m") ->take(1000) ->get();

Response will contain a hashed code scroll_id will be used to get the next result by running

$documents = ES::index("my_index")->search("hello") ->scroll("2m") ->scrollID("DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAFMFlJQOEtTdnJIUklhcU1FX2VqS0EwZncAAAAAAAABSxZSUDhLU3ZySFJJYXFNRV9laktBMGZ3AAAAAAAAAU4WUlA4S1N2ckhSSWFxTUVfZWpLQTBmdwAAAAAAAAFPFlJQOEtTdnJIUklhcU1FX2VqS0EwZncAAAAAAAABTRZSUDhLU3ZySFJJYXFNRV9laktBMGZ3") ->get();

And so on ...

Note that you don't need to write the query parameters in every scroll. All you need the scroll_id and query scroll time.

To clear scroll_id

ES::index("my_index")->scrollID("DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAFMFlJQOEtTdnJIUklhcU1FX2VqS0EwZncAAAAAAAABSxZSUDhLU3ZySFJJYXFNRV9laktBMGZ3AAAAAAAAAU4WUlA4S1N2ckhSSWFxTUVfZWpLQTBmdwAAAAAAAAFPFlJQOEtTdnJIUklhcU1FX2VqS0EwZncAAAAAAAABTRZSUDhLU3ZySFJJYXFNRV9laktBMGZ3") ->clear(); php $documents = ES::index("my_index")->search("hello")->paginate(5);

Getting pagination links

$documents->links();

Bootstrap 4 pagination

$documents->links("bootstrap-4");

Simple bootstrap 4 pagination

$documents->links("simple-bootstrap-4");

Simple pagination

$documents->links("simple-default"); php $documents->count() $documents->currentPage() $documents->firstItem() $documents->hasMorePages() $documents->lastItem() $documents->lastPage() $documents->nextPageUrl() $documents->perPage() $documents->previousPageUrl() $documents->total() $documents->url($page) php ES::index("my_index")->search("hello")->where("views", ">", 150)->toArray(); php ES::index("my_index")->search("hello")->where("views", ">", 150)->response(); php ES::index("my_index")->ignore(404, 500)->key(5)->first(); php ES::index("my_index")->search("hello")->remember(10)->get();

Specify a custom cache key

ES::index("my_index")->search("hello")->remember(10, "last_documents")->get();

Caching using other available driver

ES::index("my_index")->search("hello")->cacheDriver("redis")->remember(10, "last_documents")->get();

Caching with cache key prefix

ES::index("my_index")->search("hello")->cacheDriver("redis")->cachePrefix("docs")->remember(10, "last_documents")->get(); php

Basic fuzzy search

ES::index("my_index")->fuzzy("name", "jonh")->get();

With fuzziness control (AUTO, 0, 1, 2)

ES::index("my_index")->fuzzy("name", "jonh", "AUTO")->get();

With prefix length and max expansions

ES::index("my_index")->fuzzy("name", "jonh", "AUTO", prefixLength: 2, maxExpansions: 50)->get(); php

Exact phrase match

ES::index("my_index")->matchPhrase("content", "quick brown fox")->get();

With slop (allows words between)

ES::index("my_index")->matchPhrase("content", "quick fox", slop: 2)->get(); php ES::index("my_index")->matchPhrasePrefix("title", "elastic sea")->get();

With max expansions

ES::index("my_index")->matchPhrasePrefix("title", "elastic sea", maxExpansions: 10)->get(); php ES::index("my_index")->search("hello")->minScore(0.5)->get(); php

First page

$page1 = ES::index("my_index") ->orderBy("created_at", "desc") ->orderBy("_id") ->take(10) ->get();

Get sort values from last document

$lastDoc = $page1->last(); $sortValues = [$lastDoc->created_at, $lastDoc->_id];

Next page using search_after

$page2 = ES::index("my_index") ->orderBy("created_at", "desc") ->orderBy("_id") ->searchAfter($sortValues) ->take(10) ->get(); php

Disable total hit counting (faster for large datasets)

ES::index("my_index")->search("hello")->trackTotalHits(false)->get();

Track up to a specific number

ES::index("my_index")->search("hello")->trackTotalHits(10000)->get();

Track all hits (default)

ES::index("my_index")->search("hello")->trackTotalHits(true)->get(); php

Basic completion suggestion

$results = ES::index("my_index") ->suggest("title-suggest", "ela", "title.suggest") ->get();

Get suggestions from results

$suggestions = $results->getSuggestions();

With size limit

ES::index("my_index") ->suggest("title-suggest", "ela", "title.suggest", size: 10) ->get();

With fuzzy matching

ES::index("my_index") ->suggest("title-suggest", "ela", "title.suggest", fuzzy: "AUTO") ->get();

With context filtering

ES::index("my_index") ->suggest("title-suggest", "ela", "title.suggest", contexts: [ "category" => ["tech", "science"] ]) ->get();

Skip duplicate suggestions

ES::index("my_index") ->suggest("title-suggest", "ela", "title.suggest", skipDuplicates: true) ->get(); php $results = ES::index("my_index") ->suggestTerm("spell-check", "helo wrld", "content") ->get();

$suggestions = $results->getSuggestions(); php

Average

ES::index("my_index")->avgAgg("avg_price", "price")->get();

Sum

ES::index("my_index")->sumAgg("total_sales", "amount")->get();

Min

ES::index("my_index")->minAgg("min_price", "price")->get();

Max

ES::index("my_index")->maxAgg("max_price", "price")->get();

Cardinality (distinct count)

ES::index("my_index")->cardinalityAgg("unique_users", "user_id")->get();

Value count

ES::index("my_index")->valueCountAgg("doc_count", "status")->get();

Stats (min, max, sum, count, avg)

ES::index("my_index")->statsAgg("price_stats", "price")->get(); php

Terms aggregation

ES::index("my_index")->termsAgg("categories", "category", size: 20)->get();

Date histogram

ES::index("my_index") ->dateHistogramAgg("sales_over_time", "created_at", "month", format: "yyyy-MM") ->get();

Numeric histogram

ES::index("my_index")->histogramAgg("price_ranges", "price", interval: 50)->get();

Range aggregation

ES::index("my_index")->rangeAgg("price_buckets", "price", [ ["to" => 50], ["from" => 50, "to" => 100], ["from" => 100] ])->get();

Filter aggregation

ES::index("my_index")->filterAgg("active_users", [ "term" => ["status" => "active"] ])->get(); php

Add sub-aggregation before the parent

ES::index("my_index") ->subAgg("categories", "avg_price", ["avg" => ["field" => "price"]]) ->termsAgg("categories", "category") ->get();

Multiple sub-aggregations

ES::index("my_index") ->subAgg("categories", "avg_price", ["avg" => ["field" => "price"]]) ->subAgg("categories", "max_price", ["max" => ["field" => "price"]]) ->termsAgg("categories", "category") ->get(); php

Update with script

ES::index("my_index") ->where("status", "old") ->updateByQuery("ctx._source.status = 'archived'");

With parameters

ES::index("my_index") ->where("status", "pending") ->updateByQuery("ctx._source.status = params.new_status", [ "new_status" => "processed" ]);

Complex script

ES::index("my_index") ->where("views", ">", 1000) ->updateByQuery([ "source" => "ctx._source.popular = true; ctx._source.views_bucket = 'high'", "lang" => "painless" ]);

Async execution (returns task ID)

$task = ES::index("my_index") ->where("status", "old") ->updateByQuery("ctx._source.status = 'archived'", waitForCompletion: false); php

Delete matching documents

ES::index("my_index") ->where("status", "deleted") ->deleteByQuery();

Async execution (returns task ID)

$task = ES::index("my_index") ->where("created_at", "<", "2020-01-01") ->deleteByQuery(waitForCompletion: false); php

Retry up to 3 times with 100ms initial delay

ES::index("my_index") ->retry(3, 100) ->search("hello") ->get(); php $results = ES::index("my_index") ->profile() ->search("hello") ->get();

Access profiling information from the raw response

$response = ES::index("my_index") ->profile() ->search("hello") ->response();

$profileData = $response['profile']; php ES::raw()->search([ "index" => "my_index", "type" => "my_type", "body" => [ "query" => [ "bool" => [ "must" => [ [ "match" => [ "address" => "mill" ] ], [ "match" => [ "address" => "lane" ] ] ] ] ] ] ]); php ES::index("my_index")->key(3)->insert([ "title" => "Test document", "content" => "Sample content" ]);

A new document will be inserted with _id = 3.

[id is optional] if not specified, a unique hash key will be generated.

php

Main query

ES::index("my_index")->bulk(function ($bulk){

# Sub queries
$bulk->index("my_index_1")->key(10)->insert(["title" => "Test document 1","content" => "Sample content 1"]);
$bulk->index("my_index_2")->key(11)->insert(["title" => "Test document 2","content" => "Sample content 2"]);
$bulk->key(12)->insert(["title" => "Test document 3", "content" => "Sample content 3"]);

});

Notes from the above query:

Index names are extendable. This means that:

If index() is not specified in subquery:

-- The builder will get index name from the main query.

-- If index is not specified in main query, the builder will get index name from configuration file.

You can also use the array-based bulk code style using multidimensional array of [id => data] pairs

ES::index("my_index")->bulk([

10 => [
    "title" => "Test document 1",
    "content" => "Sample content 1"
],

11 => [
    "title" => "Test document 2",
    "content" => "Sample content 2"
]

]);

The two given documents will be inserted with its associated ids

php ES::index("my_index")->key(3)->update([ "title" => "Test document", "content" => "sample content" ]);

Document has _id = 3 will be updated.

[id is required]

php

Bulk update

ES::index("my_index")->bulk(function ($bulk){ $bulk->key(10)->update(["title" => "Test document 1","content" => "Sample content 1"]); $bulk->key(11)->update(["title" => "Test document 2","content" => "Sample content 2"]); }); php ES::index("my_index")->key(3)->increment("views");

Document has _id = 3 will be incremented by 1.

ES::index("my_index")->key(3)->increment("views", 3);

Document has _id = 3 will be incremented by 3.

[id is required]

php ES::index("my_index")->key(3)->decrement("views");

Document has _id = 3 will be decremented by 1.

ES::index("my_index")->key(3)->decrement("views", 3);

Document has _id = 3 will be decremented by 3.

[id is required]

php

increment field by script

ES::index("my_index")->key(3)->script( "ctx._source.$field += params.count", ["count" => 1] );

add php tag to tags array list

ES::index("my_index")->key(3)->script( "ctx._source.tags.add(params.tag)", ["tag" => "php"] );

delete the doc if the tags field contain mongodb, otherwise it does nothing (noop)

ES::index("my_index")->key(3)->script( "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'none' }", ["tag" => "mongodb"] ); php ES::index("my_index")->key(3)->delete();

Document has _id = 3 will be deleted.

[id is required]

php

Bulk delete

ES::index("my_index")->bulk(function ($bulk){ $bulk->key(10)->delete(); $bulk->key(11)->delete(); }); php use Matchory\Elasticsearch\Facades\Elasticsearch; use Matchory\Elasticsearch\Testing\Responses\SearchResponse;

$fake = Elasticsearch::fake( SearchResponse::fromDocuments([ ['title' => 'Widget', 'price' => 9.99], ['title' => 'Gadget', 'price' => 19.99], ])->toArray(), );

// Your application code runs normally: $results = Product::where('category', 'electronics')->get();

$this->assertCount(2, $results); $this->assertSame('Widget', $results[0]->title);

// When done, restore the real client: Elasticsearch::unfake(); php use Matchory\Elasticsearch\Testing\Responses\SearchResponse;

// From plain document arrays (most common): SearchResponse::fromDocuments([ ['title' => 'Post 1', 'status' => 'published'], ['title' => 'Post 2', 'status' => 'draft'], ])->toArray();

// With a custom index name: SearchResponse::fromDocuments($docs, 'my_index')->toArray();

// Empty results: SearchResponse::empty()->toArray();

// From raw hit arrays (when you need control over _id, _score, etc.): SearchResponse::make([ ['_index' => 'posts', '_id' => 'abc', '_score' => 2.5, '_source' => ['title' => 'Post']], ])->toArray();

// Override total count (e.g., for pagination): SearchResponse::make($hits, total: 1000)->toArray();

// With aggregations or suggestions: SearchResponse::fromDocuments($docs) ->withAggregations(['status' => ['buckets' => [['key' => 'published', 'doc_count' => 10]]]]) ->withSuggestions(['title_suggest' => [['text' => 'test', 'options' => []]]]) ->toArray(); php use Matchory\Elasticsearch\Testing\Responses\CountResponse;

CountResponse::make(42)->toArray(); php use Matchory\Elasticsearch\Testing\Responses\IndexResponse;

IndexResponse::created('doc-1', 'my_index')->toArray(); IndexResponse::updated('doc-1', 'my_index')->toArray(); IndexResponse::deleted('doc-1', 'my_index')->toArray(); php use Matchory\Elasticsearch\Testing\Responses\BulkResponse;

BulkResponse::allSuccessful(count: 5, index: 'my_index')->toArray(); BulkResponse::make(items: [...], errors: true)->toArray(); php $response = SearchResponse::empty()->merge(['took' => 500]); php $fake = Elasticsearch::fake( SearchResponse::empty()->toArray(), );

Product::where('status', 'active')->get();

// Assert a method was called: $fake->assertSent('search');

// Assert with parameter matching: $fake->assertSent('search', fn(array $params) => $params['index'] === 'products' );

// Assert a method was NOT called: $fake->assertNotSent('index');

// Assert nothing was sent at all: // $fake->assertNothingSent();

// Assert exact call count: $fake->assertSentCount('search', 1);

// Access raw recorded calls for custom inspection: $calls = $fake->recorded('search'); // array of param arrays $all = $fake->recorded(); // all calls keyed by method php use Matchory\Elasticsearch\Testing\ResponseSequence; use Matchory\Elasticsearch\Testing\Responses\SearchResponse;

$fake = Elasticsearch::fake( new ResponseSequence( SearchResponse::fromDocuments([['title' => 'First page']]), SearchResponse::fromDocuments([['title' => 'Second page']]), SearchResponse::empty(), ), );

Product::all(); // Returns "First page" Product::all(); // Returns "Second page" Product::all(); // Returns empty results php $sequence = new ResponseSequence( SearchResponse::fromDocuments([['title' => 'Only first call']]), ); $sequence->whenEmpty(SearchResponse::empty()); php $fake = Elasticsearch::fake();

$fake->getClient()->stubMethod('search', SearchResponse::fromDocuments([['title' => 'Always this']])->toArray() );

$fake->getClient()->stubMethod('count', CountResponse::make(99)->toArray() );

// Every search() call returns the same response Product::all(); // "Always this" Product::all(); // "Always this" php $fake = Elasticsearch::fake( fn(string $method, array $params) => match ($method) { 'search' => SearchResponse::fromDocuments([ ['title' => 'Result for: ' . ($params['index'] ?? 'unknown')], ])->toArray(), 'count' => CountResponse::make(42)->toArray(), default => [], }, ); php namespace Tests\Feature;

use Matchory\Elasticsearch\Testing\FakesElasticsearch; use Matchory\Elasticsearch\Testing\Responses\SearchResponse; use Tests\TestCase;

class ProductSearchTest extends TestCase { use FakesElasticsearch;

public function test_search_returns_results(): void
{
    $this->fakeElasticsearch(
        SearchResponse::fromDocuments([
            ['title' => 'Widget', 'price' => 9.99],
        ])->toArray(),
    );

    $response = $this->get('/api/products?q=widget');

    $response->assertOk();
    $response->assertJsonCount(1, 'data');
}

public function test_empty_search(): void
{
    $this->fakeElasticsearch(
        SearchResponse::empty()->toArray(),
    );

    $response = $this->get('/api/products?q=nothing');

    $response->assertOk();
    $response->assertJsonCount(0, 'data');
}

// No manual cleanup needed -- unfake() is called automatically after each test

}



Releases
--------
See the [release page](https://github.com/matchory/elasticsearch/releases).

Authors
-------
[Basem Khirat](http://basemkhirat.com) - [[email protected]](mailto:[email protected]) - [@basemkhirat](https://twitter.com/basemkhirat)  
[Moritz Friedrich](https://www.matchory.com) - [[email protected]](mailto:[email protected])

Bugs, Suggestions and Contributions
-----------------------------------
Thanks to [everyone](https://github.com/basemkhirat/elasticsearch/graphs/contributors) who has contributed to the
original project and
[everyone else](https://github.com/matchory/elasticsearch/graphs/contributors) who has contributed to this fork!  
Please use [Github](https://github.com/matchory/elasticsearch) for reporting bugs, and making comments or suggestions.

If you're interested in helping out, the most pressing issues would be modernizing the query builder to provide better
support for Elasticsearch features as
well as completing the test suite!

License
-------
MIT

`Have a happy searching..`

All versions of elasticsearch with dependencies

PHP Build Version
Package Version
Requires php Version ^8.3
ext-json Version *
elasticsearch/elasticsearch Version ^9.0
illuminate/pagination Version ^v12.49.0
illuminate/support Version ^v12.49.0
monolog/monolog Version *
symfony/var-dumper Version *
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package matchory/elasticsearch contains the following files

Loading the files please wait ...