PHPackages                             josbeir/cakephp-elastickit - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Search &amp; Filtering](/categories/search)
4. /
5. josbeir/cakephp-elastickit

AbandonedArchivedCakephp-plugin[Search &amp; Filtering](/categories/search)

josbeir/cakephp-elastickit
==========================

A lightweight CakePHP 5 plugin for working with Elasticsearch using the official PHP client.

0.1.3(8mo ago)057MITPHPPHP &gt;=8.2CI failing

Since Aug 16Pushed 6mo agoCompare

[ Source](https://github.com/josbeir/cakephp-elastickit)[ Packagist](https://packagist.org/packages/josbeir/cakephp-elastickit)[ RSS](/packages/josbeir-cakephp-elastickit/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (4)Dependencies (10)Versions (5)Used By (0)

ElasticKit - a CakePHP Elasticsearch plugin
===========================================

[](#elastickit---a-cakephp-elasticsearch-plugin)

[![CI](https://github.com/josbeir/cakephp-elastikit/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/josbeir/cakephp-elastikit/actions/workflows/ci.yml)[![PHPStan](https://camo.githubusercontent.com/f60d96f7c2579690ab6dfa8918f777fe93a02a92301c661eb38a85861a92b780/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c253230382d627269676874677265656e2e7376673f7374796c653d666c6174)](https://phpstan.org/)[![codecov](https://camo.githubusercontent.com/684080310992d9917ebde709da06564ad3d577eb615e9b67b59ada34bc1d74fb/68747470733a2f2f636f6465636f762e696f2f6769746875622f6a6f73626569722f63616b657068702d656c61737469636b69742f67726170682f62616467652e7376673f746f6b656e3d345647574a5154574835)](https://codecov.io/github/josbeir/cakephp-elastickit)[![Minimum PHP Version](https://camo.githubusercontent.com/ec21f169d70b69344c67d6f18fa1a24d20476d2f0cd680e8c4a1534c22f34e5f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253345253344253230382e322d3838393242462e737667)](https://php.net/)[![Packagist Downloads](https://camo.githubusercontent.com/f800d690b2dccdcbec13b62a3c4b30362d40f90f9edc188ac2e751b7f0c4eafd/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6a6f73626569722f63616b657068702d656c61737469636b6974)](https://packagist.org/packages/josbeir/cakephp-elastickit)[![GitHub License](https://camo.githubusercontent.com/52e446e8524a380d775e6ea87e17fff5c91c65875742a91aaf5803b906d62f9f/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6a6f73626569722f63616b657068702d656c61737469636b6974)](https://camo.githubusercontent.com/52e446e8524a380d775e6ea87e17fff5c91c65875742a91aaf5803b906d62f9f/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6a6f73626569722f63616b657068702d656c61737469636b6974)

Important

This plugin is now archived as I have proceeded on maintaining the official CakePHP [elastic-search](https://github.com/cakephp/elastic-search) plugin.

A lightweight CakePHP 5 plugin for working with Elasticsearch using the [official PHP client](https://github.com/elastic/elasticsearch-php).

Table of Contents
-----------------

[](#table-of-contents)

- [Design Philosophy](#design-philosophy)
- [Why this plugin?](#why-this-plugin)
- [How it differs from the original cakephp/elastic-search plugin](#how-it-differs-from-the-original-cakephpelastic-search-plugin)
- [Requirements](#requirements)
- [Installation](#installation)
- [Configuration](#configuration)
- [Defining an Index](#defining-an-index)
- [Document Entities](#document-entities)
- [Querying](#querying)
- [ResultSet API](#resultset-api)
- [CLI: manage indices](#cli-manage-indices)
- [Accessing indices from your code](#accessing-indices-from-your-code)
- [Logging and debugging](#logging-and-debugging)
- [What this plugin does NOT do](#what-this-plugin-does-not-do)
- [Contributing](#contributing)
- [License](#license)

Design Philosophy
-----------------

[](#design-philosophy)

This plugin provides minimal abstraction over the official Elasticsearch client. It handles connection management, index location, and result decoration while leaving persistence and validation to you.

**Not included**: ORM-style persistence, validation, or RepositoryInterface implementation.

**Want full ORM features?** Use [cakephp/elastic-search](https://github.com/cakephp/elastic-search) instead, which provides an ORM similar to CakePHP's database layer.

Why this plugin?
----------------

[](#why-this-plugin)

- **Official client**: Uses `elasticsearch/elasticsearch` instead of Elastica for better compatibility across ES versions
- **Minimal abstraction**: Thin layer over the official client - no CakePHP ORM or persistence logic
- **Flexible querying**: Use Spatie's query builder or the client API directly
- **Upgrade-friendly**: Fewer breaking changes between Elasticsearch major releases

How it differs from the original cakephp/elastic-search plugin
--------------------------------------------------------------

[](#how-it-differs-from-the-original-cakephpelastic-search-plugin)

**cakephp/elastic-search** (Elastica-based) provides a full ORM experience with types, persistence, and validation. **ElasticKit** takes a minimal approach:

- Uses the official Elasticsearch client (no Elastica)
- Thin wrapper with no ORM/persistence layer
- Choose your query method: Spatie's builder or direct client API
- Fewer breaking changes between Elasticsearch versions

Use the original plugin for ORM-style features. Use ElasticKit for clean access to the official client with CakePHP conveniences.

Requirements
------------

[](#requirements)

- PHP &gt;= 8.2
- CakePHP &gt;= 5.2
- Elasticsearch &gt;= 8.5 / 9.x

> **Note**: Lock the `elasticsearch/elasticsearch` package version in your composer file to match your Elasticsearch server version for optimal compatibility:

Installation
------------

[](#installation)

Install the dependencies in your Cake app:

```
composer require josbeir/cakephp-elastickit
```

Ensure the plugin is loaded (one of):

- In `Application::bootstrap()`:

```
$this->addPlugin('ElasticKit');
```

- Or via `config/plugins.php` if you use the plugins file.

Configuration
-------------

[](#configuration)

Register an Elasticsearch connection using the plugin’s connection class. You can do this in `config/bootstrap.php` or in a config file loaded during bootstrap:

```
use Cake\Datasource\ConnectionManager;
use ElasticKit\Datasource\Connection;

ConnectionManager::setConfig('elasticsearch', [
	'className' => Connection::class,
	'hosts' => [
		// Use your cluster endpoints
		'http://localhost:9200',
	],
	// Optional: any PSR-3 logger name registered with Cake\Log\Log or a LoggerInterface instance
	'logger' => 'elasticsearch',

    // All extra arguments are passed to \Elasticsearch\ClientBuilder
]);
```

By default, indices resolve to the `elasticsearch` connection name. You can override the connection per index class via options if needed.

### HTTP Client Configuration

[](#http-client-configuration)

By default, the connection uses CakePHP's Http Client, which makes it easy to mock requests during testing. You can override this behavior using the `httpClient` option:

```
use Cake\Datasource\ConnectionManager;
use ElasticKit\Datasource\Connection;

ConnectionManager::setConfig('elasticsearch', [
	'className' => Connection::class,
	'hosts' => ['http://localhost:9200'],

	// Optional: Use a different HTTP client
	// Default: Uses CakePHP's Http Client (great for testing/mocking, hijacking the request/response)
	// 'httpClient' => new YourPsr18HttpClient(), // Any PSR-18 compatible client
	// 'httpClient' => new Elastic\Transport\Client\Curl, // Use the default cURL client from elasticsearch/elasticsearch
]);
```

Defining an Index
-----------------

[](#defining-an-index)

Create an index class in `src/Model/Index`, e.g. `ArticlesIndex`:

```
namespace App\Model\Index;

use ElasticKit\Index;

class ArticlesIndex extends Index
{
	public function initialize(): void
	{
		// Optional: set index alias/name explicitly; otherwise class name is underscored
		// $this->setIndexName('articles');

		// Optional: provide settings/mappings used by createIndex()/updateIndex()
		$this->setSettings([
			'number_of_shards' => 1,
			'number_of_replicas' => 0,
		]);

		$this->setMappings([
			'properties' => [
				'title' => ['type' => 'text'],
				'created' => ['type' => 'date'],
			],
		]);
	}
}
```

Document Entities
-----------------

[](#document-entities)

Document entities are resolved automatically from your index name. For an index named `articles`, the plugin will try `App\Model\Document\Article`. If not present, it falls back to the generic `ElasticKit\Document`.

```
namespace App\Model\Document;

use ElasticKit\Document;

class Article extends Document
{
	// Add accessors/mutators/virtuals as you like.
}
```

Document entities follow CakePHP's EntityInterface with one key difference: the document ID and score are stored in a reserved property to avoid field name collisions.

Access these properties using:

```
$doc = $Articles->get('some-id');
$id = $doc->getDocumentId();     // Gets the Elasticsearch document ID
$score = $doc->getScore();       // Gets the search score (if from a search result)
```

Querying
--------

[](#querying)

You can query in two ergonomic ways.

### 1) With [Spatie’s](https://github.com/spatie/elasticsearch-query-builder) query builder

[](#1-with-spaties-query-builder)

The `Index::find()` method creates a `Spatie\ElasticsearchQueryBuilder\Builder`, sets the index, executes the search, and returns a `ResultSet` that yields `Document` instances.

```
use Spatie\ElasticsearchQueryBuilder\Builder;
use Spatie\ElasticsearchQueryBuilder\Aggregations\MaxAggregation;
use Spatie\ElasticsearchQueryBuilder\Queries\MatchQuery;

$Articles = $this->fetchIndex('Articles');

// Using a closure
$results = $Articles->find(function (Builder $builder) {
	return $builder
		->addQuery(MatchQuery::create('name', 'elastickit', fuzziness: 'AUTO'))
		->addAggregation(MaxAggregation::create('score'))
});

// Or by creating a builder instance and passing it to the find() function.
$query = $Articles->createBuilder()
	->addQuery(MatchQuery::create('name', 'elastickit', fuzziness: 3));

$results = $Articles->find($query);
```

### 2) Directly via the official client

[](#2-directly-via-the-official-client)

Every unknown method call on your index instance proxies to the underlying `Elastic\Elasticsearch\Client`, so you can use the full API. Note that while `get()` is reserved by the Index class for fetching single documents, you can still access the client's `get()` method via `getClient()->get()`:

```
// Index's get() - returns a Document|null
$doc = $Articles->get('document_id');

// Client's get() - returns raw Elasticsearch response
$response = $Articles->getClient()->get([
	'index' => $Articles->getIndexName(),
	'id' => 'document_id'
]);

$response = $Articles->search([
	'index' => $Articles->getIndexName(),
	'body' => [
		'query' => ['match_all' => ...],
		'size' => 10,
	],
]);

// Convert as needed
$resultset = $Articles->resultSet($response);
$array = $response->asArray();
$object = $response->asObject();
$ok = $response->asBool();
```

### Convenience methods

[](#convenience-methods)

- `Index::get($id)`: Fetch a single document by id as a `Document|null`.
- `Index::resultSet($response)`: Wrap any Elasticsearch response in the plugin’s `ResultSet`.

The `ResultSet` exposes helpers like:

- `getTook()`, `getMaxScore()`, `getShards()`, `getHitsTotal()`
- Iterates documents, handles both search and bulk-style responses.

ResultSet API
-------------

[](#resultset-api)

`ElasticKit\ResultSet` is an iterator over decorated `Document` instances and provides a few helpers around the Elasticsearch response.

- `getTook(): ?int` — The time (ms) the search took (if present).
- `getMaxScore(): ?float` — Max score for hits (if present).
- `getShards(): ?array` — Shard info from the response (if present).
- `getHitsTotal(): ?int` — Reported total hits value (may be `null` depending on ES settings like `track_total_hits`).
- `getAggregations(): ?array` — Aggregation results from the response (if present).
- `hasErrors(): bool` — Indicates whether the underlying response reported errors (useful for bulk responses).
- `getResponse(): ResponseInterface` — Access the raw Elasticsearch response object.
- `getBuilder(): Builder` — The builder instance.

Iteration

```
foreach ($results as $doc) {
	// $doc is \App\Model\Document\YourEntity (if present) or the base Document
}
```

Force a specific document class

```
use App\Model\Document\Article;

$results->setDocumentClass(Article::class);
```

Note: ResultSet also includes common collection utilities via Cake’s CollectionTrait (e.g., `map()`, `filter()`, `toList()`), which can be handy for quick transformations.

CLI: manage indices
-------------------

[](#cli-manage-indices)

The plugin ships a small command to create/update/delete indices based on your index class config (`settings`/`mappings`).

```
bin/cake elasticsearch index articles --create  # create if missing
bin/cake elasticsearch index articles --update  # put mapping
bin/cake elasticsearch index articles --delete  # delete index

# Use a plugin or FQCN-style name if needed
bin/cake elasticsearch index App.Articles --create
```

Use `-v` to print current settings/mappings of the target index.

Accessing indices from your code
--------------------------------

[](#accessing-indices-from-your-code)

Use the `IndexLocatorAwareTrait` to fetch indices by alias (class name without the `Index` suffix):

```
use ElasticKit\Locator\IndexLocatorAwareTrait;

class ArticlesService
{
	use IndexLocatorAwareTrait;

	public function searchByTitle(string $q)
	{
		$Articles = $this->fetchIndex('Articles');

		return $Articles->get(1234);
	}
}
```

### PHPstan notes

[](#phpstan-notes)

When using `IndexLocatorAwareTrait::fetchIndex()`, PHPStan will complain about `assign.propertyType` when assigning the result to a typed property. This happens because PHPStan can't infer the specific index class being returned.

To resolve this while maintaining similarity with `IndexLocatorAwareTrait::fetchTable()`, add the following to your `phpstan.neon` configuration (requires `cakedc/cakephp-phpstan`):

```
# Support IndexLocatorAwareTrait
services:
	-
		factory: CakeDC\PHPStan\Type\BaseTraitExpressionTypeResolverExtension(ElasticKit\Locator\IndexLocatorAwareTrait, fetchIndex, %s\Model\Index\%sIndex)
		tags:
			- phpstan.broker.expressionTypeResolverExtension
```

This extension teaches PHPStan to recognize that `$this->fetchIndex('Articles')` returns an `ArticlesIndex` instance, eliminating type errors.

Logging and debugging
---------------------

[](#logging-and-debugging)

- Pass a PSR-3 logger (or the name of a Cake log engine) to the connection config via `logger` to capture client requests.
- Convert responses with `->asArray()` or `->asObject()` while developing.

### DebugKit panel

[](#debugkit-panel)

This plugin includes a DebugKit panel that displays Elasticsearch requests per configured connection.

- Ensure `cakephp/debug_kit` is installed and enabled in development.
- The panel appears as “Elasticsearch” in the DebugKit toolbar.
- It hooks into `ElasticKit\Datasource\Connection` loggers at runtime and shows:
    - Count of requests per connection
    - Message and a prettified JSON body

To enable the panel, add it to your DebugKit configuration:

```
Configure::write('DebugKit.panels', ['ElasticKit.Elasticsearch']);
```

What this plugin does NOT do
----------------------------

[](#what-this-plugin-does-not-do)

- No ORM-like persistence (no `save()`, no automatic validation). You decide how to index/update/delete documents.
- No type mapping or schema inference. Provide your own index settings/mappings.
- No custom query DSL layer beyond the optional Spatie builder helper.

This is by design to keep the integration thin, explicit, and resilient to upstream changes.

Contributing
------------

[](#contributing)

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

### Development Setup

[](#development-setup)

1. Clone the repository
2. Install dependencies: `composer install`
3. Run tests: `composer test`

Please make sure to update tests as appropriate and follow the existing code style.

License
-------

[](#license)

This project is licensed under the MIT License - see the [LICENSE](LICENSE.md) file for details.

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance64

Regular maintenance activity

Popularity8

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity41

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

4

Last Release

267d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/2899d7bd057eecff34549480753213e1b19652f7f726db2d971b6b0fa69d4c14?d=identicon)[josbeir](/maintainers/josbeir)

---

Top Contributors

[![josbeir](https://avatars.githubusercontent.com/u/26058?v=4)](https://github.com/josbeir "josbeir (35 commits)")

---

Tags

pluginelasticsearchcakephp

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Rector

Type Coverage Yes

### Embed Badge

![Health badge](/badges/josbeir-cakephp-elastickit/health.svg)

```
[![Health](https://phpackages.com/badges/josbeir-cakephp-elastickit/health.svg)](https://phpackages.com/packages/josbeir-cakephp-elastickit)
```

###  Alternatives

[10up/elasticpress

Supercharge WordPress with Elasticsearch.

1.3k374.3k6](/packages/10up-elasticpress)[mailerlite/laravel-elasticsearch

An easy way to use the official PHP ElasticSearch client in your Laravel applications.

934529.3k2](/packages/mailerlite-laravel-elasticsearch)[jeroen-g/explorer

Next-gen Elasticsearch driver for Laravel Scout.

397612.3k](/packages/jeroen-g-explorer)[kvz/elasticsearch

CakePHP Plugin for ElasticSearch

4410.5k](/packages/kvz-elasticsearch)[10up/debug-bar-elasticpress

Extends the Debug Bar plugin for usage with ElasticPress

2917.0k](/packages/10up-debug-bar-elasticpress)[blomstra/search

Replaces Flarum search with one powered by an elastic search server.

114.9k](/packages/blomstra-search)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
