{"id":36954678,"url":"https://github.com/bonu-dev/php-elasticsearch-builder","last_synced_at":"2026-01-13T13:00:56.224Z","repository":{"id":326735622,"uuid":"1105213848","full_name":"bonu-dev/php-elasticsearch-builder","owner":"bonu-dev","description":"PHP Query Builder for Elasticsearch","archived":false,"fork":false,"pushed_at":"2025-12-30T15:06:32.000Z","size":637,"stargazers_count":57,"open_issues_count":0,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-01T22:57:27.661Z","etag":null,"topics":["builder","elasticsearch","php","query"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bonu-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-27T09:44:11.000Z","updated_at":"2026-01-01T03:36:16.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/bonu-dev/php-elasticsearch-builder","commit_stats":null,"previous_names":["bonu-dev/php-elasticsearch-builder"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/bonu-dev/php-elasticsearch-builder","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bonu-dev%2Fphp-elasticsearch-builder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bonu-dev%2Fphp-elasticsearch-builder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bonu-dev%2Fphp-elasticsearch-builder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bonu-dev%2Fphp-elasticsearch-builder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bonu-dev","download_url":"https://codeload.github.com/bonu-dev/php-elasticsearch-builder/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bonu-dev%2Fphp-elasticsearch-builder/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28385798,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T12:01:30.995Z","status":"ssl_error","status_checked_at":"2026-01-13T12:00:09.625Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["builder","elasticsearch","php","query"],"created_at":"2026-01-13T13:00:26.629Z","updated_at":"2026-01-13T13:00:56.216Z","avatar_url":"https://github.com/bonu-dev.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PHP Query Builder for Elasticsearch\n\n[![PHPUnit](https://github.com/bonu-dev/php-elasticsearch-builder/actions/workflows/phpunit.yaml/badge.svg?branch=main)](https://github.com/bonu-dev/php-elasticsearch-builder/actions/workflows/phpunit.yaml)\n[![Latest Stable Version](https://poser.pugx.org/bonu/php-elasticsearch-builder/v)](https://packagist.org/packages/bonu/php-elasticsearch-builder)\n[![License](https://poser.pugx.org/bonu/php-elasticsearch-builder/license)](https://packagist.org/packages/bonu/php-elasticsearch-builder)\n[![PHP Version](https://img.shields.io/packagist/php-v/bonu/php-elasticsearch-builder.svg)](https://packagist.org/packages/bonu/php-elasticsearch-builder)\n\n---\n\n**A clean, fluent, immutable, and type-safe query builder for Elasticsearch** - built from the ground up to work seamlessly with the [official Elasticsearch PHP client](https://github.com/elastic/elasticsearch-php).\n\nNo extra dependencies. No magic. Just expressive, readable, and maintainable Elasticsearch queries in PHP.\n\n```php\nuse Elastic\\Elasticsearch\\ClientBuilder;\nuse Bonu\\ElasticsearchBuilder\\QueryBuilder;\nuse Bonu\\ElasticsearchBuilder\\Query\\TermQuery;\nuse Bonu\\ElasticsearchBuilder\\Query\\BoolQuery;\nuse Bonu\\ElasticsearchBuilder\\Query\\MatchQuery;\n\n$builder = new QueryBuilder('products')\n    -\u003equery(new TermQuery('ean', 'foo_bar_123')-\u003eboost(12))\n    -\u003equery(new BoolQuery()\n        -\u003eshould(new MatchQuery('name', 'foo'))\n        -\u003eshould(new MatchQuery('description', 'bar'))\n        -\u003eboost(5)\n    )\n    -\u003esize(20);\n\n$client = ClientBuilder::create()-\u003ebuild();\n$products = $client-\u003esearch($builder-\u003ebuild());\n```\n\n## Features\n\n- Fully fluent \u0026 chainable API\n- Zero dependencies beyond the official Elasticsearch PHP SDK\n- Easy creation of reusable composite queries\n- 100% type-hinted and IDE-friendly\n\n## Requirements\n\n- PHP ≥ 8.4\n\n## Installation\n\n```bash\ncomposer require bonu/php-elasticsearch-builder\n```\n\n## Using query builder\n\nThe `Bonu\\ElasticsearchBuilder\\QueryBuilder` class provides a fluent interface for building Elasticsearch queries.\nConstructor of this class accepts a single argument - name of the index to query, which may be used for searching in specific index.\n\nOut of box it supports:\n- Chaining queries using `query()` method\n- Chaining aggregations using `aggregation()` method\n- Configuring pagination of results using `from()` and `size()` methods\n\n## Queries\n\n\u003e [!CAUTION]\n\u003e Queries are immutable.\n\nThis package comes with a set of ready-to-use queries which is documented below.\n\nIt is also possible to create reusable composite queries using abstract `Bonu\\ElasticsearchBuilder\\Query\\CompositeQuery` class.\n\nExample of composite query:\n\n```php\nuse Bonu\\ElasticsearchBuilder\\Query\\BoolQuery;\nuse Bonu\\ElasticsearchBuilder\\Query\\TermQuery;\nuse Bonu\\ElasticsearchBuilder\\Query\\CompositeQuery;\n\nclass PubliclyVisibleProductsQuery extends CompositeQuery\n{\n    /**\n     * @inheritDoc\n     */\n    public function query(): QueryInterface\n    {\n        return new BoolQuery()\n            -\u003emust(new TermQuery('is_active', true))\n            -\u003emustNot(new TermQuery('is_out_of_stock', false));\n    }\n}\n\n$builder = new QueryBuilder('products')\n    -\u003equery(new PubliclyVisibleProductsQuery());\n```\n\n### TermQuery\n\nhttps://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-term-query\n\n```php\nuse Bonu\\ElasticsearchBuilder\\Query\\TermQuery;\n\nnew TermQuery('field', 'value')-\u003eboost(10)\n```\n\n### MatchQuery\n\nhttps://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-match-query\n\n```php\nuse Bonu\\ElasticsearchBuilder\\Query\\MatchQuery;\n\n// Default operator is OR\nnew MatchQuery('field', 'some text')\n    -\u003eboost(2)\n    -\u003eanalyzer('standard')\n\n// With AND operator\nnew MatchQuery('field', 'some text', MatchQuery::OPERATOR_AND)\n```\n\n### MatchPhraseQuery\n\nhttps://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-match-query-phrase\n\n```php\nuse Bonu\\ElasticsearchBuilder\\Query\\MatchPhraseQuery;\n\n// Optional third argument is slop\nnew MatchPhraseQuery('field', 'exact phrase', 2)\n    -\u003eboost(1.5)\n    -\u003eanalyzer('standard')\n```\n\n### BoolQuery\n\nhttps://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-bool-query\n\n```php\nuse Bonu\\ElasticsearchBuilder\\Query\\BoolQuery;\nuse Bonu\\ElasticsearchBuilder\\Query\\TermQuery;\nuse Bonu\\ElasticsearchBuilder\\Query\\MatchQuery;\n\nnew BoolQuery()\n    -\u003emust(new TermQuery('status', 'active'))\n    -\u003efilter(new TermQuery('stock', 1))\n    -\u003eshould(new MatchQuery('title', 'awesome product'))\n    -\u003emustNot(new TermQuery('blocked', true))\n    -\u003eboost(3)\n```\n\n### NestedQuery\n\nhttps://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-nested-query\n\n```php\nuse Bonu\\ElasticsearchBuilder\\Query\\NestedQuery;\nuse Bonu\\ElasticsearchBuilder\\Query\\MatchQuery;\n\n// Query nested field path, inner query must be provided via -\u003equery()\nnew NestedQuery('variants')\n    -\u003equery(new MatchQuery('variants.name', 'red'))\n```\n\n### RangeQuery\n\nhttps://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-range-query\n\nRange queries can be used for filtering by multiple data types. For this reason, each data type has its own query class to fully support type-hinting.\n\n```php\nuse Bonu\\ElasticsearchBuilder\\Query\\NumericRangeQuery;\nuse Bonu\\ElasticsearchBuilder\\Query\\DatetimeRangeQuery;\n\nnew NumericRangeQuery('price', gte: 100)\n    -\u003eboost(10);\n\nnew DatetimeRangeQuery('created_at', lt: date('Y-m-d'), format: 'yyyy-MM-dd', timeZone: 'Europe/Prague')\n    -\u003eboost(20);\n```\n\n## Aggregations\n\n\u003e [!CAUTION]\n\u003e Aggregations are immutable.\n\nSimilar to queries, it is also possible to create reusable composite aggregations using abstract `Bonu\\ElasticsearchBuilder\\Aggregation\\CompositeAggregation` class.\n\nExample of composite aggregation:\n\n```php\nuse Bonu\\ElasticsearchBuilder\\Aggregation\\TermsAggregation;\nuse Bonu\\ElasticsearchBuilder\\Aggregation\\NestedAggregation;\nuse Bonu\\ElasticsearchBuilder\\Aggregation\\CompositeAggregation;\n\nclass CategoryBrandAggregation extends CompositeAggregation\n{\n    /**\n     * @param string|\\Stringable $name\n     */\n    public function __construct(\n        private readonly string | Stringable $name,\n    ) {}\n\n    /**\n     * @inheritDoc\n     */\n    public function aggregation(): AggregationInterface\n    {\n        return new NestedAggregation($this-\u003ename, 'products')\n            -\u003eaggregation(new TermsAggregation('by_brand', 'products.brand_id'));\n    }\n}\n```\n\n### ContainerAggregation\n\nContainer aggregation is used to group sub-aggregations. It requires either global or at least one filter (query) to be set, but not both.\n\n```php\nuse Bonu\\ElasticsearchBuilder\\Query\\TermQuery;\nuse Bonu\\ElasticsearchBuilder\\Aggregation\\TermsAggregation;\nuse Bonu\\ElasticsearchBuilder\\Aggregation\\ContainerAggregation;\n\n// Container with a filter\nnew ContainerAggregation('my_container')\n    -\u003equery(new TermQuery('status', 'active'))\n    -\u003eaggregation(new TermsAggregation('by_brand', 'brand.keyword'));\n\n// Global container\nnew ContainerAggregation('global_container')\n    -\u003easGlobal()\n    -\u003eaggregation(new TermsAggregation('all_brands', 'brand.keyword'));\n```\n\n### TermsAggregation\n\nhttps://www.elastic.co/docs/reference/aggregations/search-aggregations-bucket-terms-aggregation\n\n```php\nuse Bonu\\ElasticsearchBuilder\\Aggregation\\TermsAggregation;\nuse Bonu\\ElasticsearchBuilder\\Query\\TermQuery;\n\n// Top 10 brands, filtered to active products\nnew TermsAggregation('by_brand', 'brand.keyword')\n    -\u003esize(10)\n    -\u003equery(new TermQuery('status', 'active'));\n\n// Make the aggregation global (ignores the top-level query)\nnew TermsAggregation('all_categories', 'category.keyword')\n    -\u003easGlobal();\n```\n\n### StatsAggregation\n\nhttps://www.elastic.co/docs/reference/aggregations/search-aggregations-metrics-stats-aggregation\n\n```php\nuse Bonu\\ElasticsearchBuilder\\Aggregation\\StatsAggregation;\nuse Bonu\\ElasticsearchBuilder\\Query\\TermQuery;\n\n// Basic stats for the price field, filtered by currency\nnew StatsAggregation('price_stats', 'price')\n    -\u003equery(new TermQuery('currency', 'USD'));\n\n// Make the aggregation global (ignores the top-level query)\nnew StatsAggregation('global_price_stats', 'price')\n    -\u003easGlobal();\n```\n\n### NestedAggregation\n\nhttps://www.elastic.co/docs/reference/aggregations/search-aggregations-bucket-nested-aggregation\n\n```php\nuse Bonu\\ElasticsearchBuilder\\Aggregation\\NestedAggregation;\n\nnew NestedAggregation('categories', 'products')\n    -\u003eaggregation(new StatsAggregation('product_price', 'products.price'))\n```\n\n### MultiTermsAggregation\n\nhttps://www.elastic.co/docs/reference/aggregations/search-aggregations-bucket-multi-terms-aggregation\n\n```php\nuse Bonu\\ElasticsearchBuilder\\Aggregation\\MultiTermsAggregation;\n\nnew MultiTermsAggregation('foo', ['product', 'category'])\n    -\u003esize(10)\n    -\u003equery(new TermQuery('status', 'active'));\n```\n\n### HistogramAggregation\n\nhttps://www.elastic.co/docs/reference/aggregations/search-aggregations-bucket-histogram-aggregation\n\n```php\nuse Bonu\\ElasticsearchBuilder\\Aggregation\\HistogramAggregation;\n\n// Prices in $10 intervals\nnew HistogramAggregation('price_histogram', 'price', 10);\n\n// With custom interval and min_doc_count\nnew HistogramAggregation('price_histogram', 'price', 50, 1);\n```\n\n## Sorts\n\n### FieldSort\n\n```php\n\nuse Bonu\\ElasticsearchBuilder\\Sort\\FieldSort;\nuse Bonu\\ElasticsearchBuilder\\Sort\\SortDirectionEnum;\n\nnew FieldSort('my_field', SortDirectionEnum::ASC)\n```\n\n### ScoreSort\n\n```php\n\nuse Bonu\\ElasticsearchBuilder\\Sort\\ScoreSort;\nuse Bonu\\ElasticsearchBuilder\\Sort\\SortDirectionEnum;\n\nnew ScoreSort(SortDirectionEnum::DESC)\n```\n\n## License\n\nThis package is licensed under the MIT License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbonu-dev%2Fphp-elasticsearch-builder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbonu-dev%2Fphp-elasticsearch-builder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbonu-dev%2Fphp-elasticsearch-builder/lists"}