diff --git a/.editorconfig b/.editorconfig
index 47e735b6..c75f6f91 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -11,7 +11,10 @@ indent_style = space
indent_size = 4
max_line_length = 120
-[*.{yml,json}]
+[*.{yml,yaml}]
+indent_size = 4
+
+[*.json]
indent_size = 2
[*.{neon,neon.dist}]
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 00000000..de409cb2
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Support questions & other
+ url: https://discord.meilisearch.com/
+ about: Support is not handled here but on our Discord
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index 39bb8f02..8a916518 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -1,5 +1,5 @@
---
-name: Feature Request π‘
+name: Feature Request & Enhancement π‘
about: Suggest a new idea for the project.
title: ''
labels: ''
diff --git a/.github/ISSUE_TEMPLATE/other.md b/.github/ISSUE_TEMPLATE/other.md
deleted file mode 100644
index b7a939a9..00000000
--- a/.github/ISSUE_TEMPLATE/other.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: Other
-about: Any other topic you want to talk about.
-title: ''
-labels: ''
-assignees: ''
----
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 0b7f847a..b13403fa 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -4,12 +4,12 @@ updates:
- package-ecosystem: composer
directory: "/"
schedule:
- interval: daily
+ interval: "monthly"
time: "04:00"
open-pull-requests-limit: 10
labels:
- - dependencies
- - skip-changelog
+ - dependencies
+ - skip-changelog
rebase-strategy: disabled
- package-ecosystem: "github-actions"
diff --git a/.github/release-draft-template.yml b/.github/release-draft-template.yml
index 4953c783..e93aa1a0 100644
--- a/.github/release-draft-template.yml
+++ b/.github/release-draft-template.yml
@@ -1,33 +1,37 @@
name-template: 'v$RESOLVED_VERSION π΅'
tag-template: 'v$RESOLVED_VERSION'
exclude-labels:
- - 'skip-changelog'
+ - 'skip-changelog'
version-resolver:
- minor:
- labels:
- - 'breaking-change'
- default: patch
+ minor:
+ labels:
+ - 'breaking-change'
+ default: patch
categories:
- - title: 'β οΈ Breaking changes'
- label: 'breaking-change'
- - title: 'π Enhancements'
- label: 'enhancement'
- - title: 'π Bug Fixes'
- label: 'bug'
- - title: 'π Security'
- label: 'security'
+ - title: 'β οΈ Breaking changes'
+ label: 'breaking-change'
+ - title: 'π Enhancements'
+ label: 'enhancement'
+ - title: 'π Bug Fixes'
+ label: 'bug'
+ - title: 'π Security'
+ label: 'security'
+ - title: 'βοΈ Maintenance/misc'
+ label:
+ - 'maintenance'
+ - 'documentation'
template: |
- $CHANGES
+ $CHANGES
- Thanks again to $CONTRIBUTORS! π
+ Thanks again to $CONTRIBUTORS! π
no-changes-template: 'Changes are coming soon π'
sort-direction: 'ascending'
replacers:
- - search: '/(?:and )?@dependabot-preview(?:\[bot\])?,?/g'
- replace: ''
- - search: '/(?:and )?@dependabot(?:\[bot\])?,?/g'
- replace: ''
- - search: '/(?:and )?@bors(?:\[bot\])?,?/g'
- replace: ''
- - search: '/(?:and )?@meili-bot,?/g'
- replace: ''
+ - search: '/(?:and )?@dependabot-preview(?:\[bot\])?,?/g'
+ replace: ''
+ - search: '/(?:and )?@dependabot(?:\[bot\])?,?/g'
+ replace: ''
+ - search: '/(?:and )?@bors(?:\[bot\])?,?/g'
+ replace: ''
+ - search: '/(?:and )?@meili-bot,?/g'
+ replace: ''
diff --git a/.github/workflows/pre-release-tests.yml b/.github/workflows/pre-release-tests.yml
index 50b88b0b..57f64302 100644
--- a/.github/workflows/pre-release-tests.yml
+++ b/.github/workflows/pre-release-tests.yml
@@ -3,33 +3,33 @@ name: Pre-Release Tests
# Will only run for PRs and pushes to bump-meilisearch-v*
on:
- push:
- branches:
- - bump-meilisearch-v*
- pull_request:
- branches:
- - bump-meilisearch-v*
+ push:
+ branches:
+ - bump-meilisearch-v*
+ pull_request:
+ branches:
+ - bump-meilisearch-v*
jobs:
- integration-tests:
- runs-on: ubuntu-latest
- strategy:
- matrix:
- php-versions: ['7.4', '8.0']
- name: integration-tests-against-rc (PHP ${{ matrix.php-versions }})
- steps:
- - uses: actions/checkout@v3
- - name: Install PHP
- uses: shivammathur/setup-php@v2
- with:
- php-version: ${{ matrix.php-versions }}
- - name: Validate composer.json and composer.lock
- run: composer validate
- - name: Install dependencies
- run: composer install --prefer-dist --no-progress --quiet
- - name: Get the latest Meilisearch RC
- run: echo "MEILISEARCH_VERSION=$(curl https://raw.githubusercontent.com/meilisearch/integration-guides/main/scripts/get-latest-meilisearch-rc.sh | bash)" >> $GITHUB_ENV
- - name: Meilisearch (${{ env.MEILISEARCH_VERSION }}) setup with Docker
- run: docker run -d -p 7700:7700 getmeili/meilisearch:${{ env.MEILISEARCH_VERSION }} meilisearch --master-key=masterKey --no-analytics
- - name: Run test suite
- run: composer test:unit
+ integration-tests:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ php-versions: ['7.4', '8.0']
+ name: integration-tests-against-rc (PHP ${{ matrix.php-versions }})
+ steps:
+ - uses: actions/checkout@v4
+ - name: Install PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-versions }}
+ - name: Validate composer.json and composer.lock
+ run: composer validate
+ - name: Install dependencies
+ run: composer install --prefer-dist --no-progress --quiet
+ - name: Get the latest Meilisearch RC
+ run: echo "MEILISEARCH_VERSION=$(curl https://raw.githubusercontent.com/meilisearch/integration-guides/main/scripts/get-latest-meilisearch-rc.sh | bash)" >> $GITHUB_ENV
+ - name: Meilisearch (${{ env.MEILISEARCH_VERSION }}) setup with Docker
+ run: docker run -d -p 7700:7700 getmeili/meilisearch:${{ env.MEILISEARCH_VERSION }} meilisearch --master-key=masterKey --no-analytics
+ - name: Run test suite
+ run: composer test:unit
diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml
index 477c50ff..20f2d83f 100644
--- a/.github/workflows/release-drafter.yml
+++ b/.github/workflows/release-drafter.yml
@@ -1,16 +1,16 @@
name: Release Drafter
on:
- push:
- branches:
- - main
+ push:
+ branches:
+ - main
jobs:
- update_release_draft:
- runs-on: ubuntu-latest
- steps:
- - uses: release-drafter/release-drafter@v5
- with:
- config-name: release-draft-template.yml
- env:
- GITHUB_TOKEN: ${{ secrets.RELEASE_DRAFTER_TOKEN }}
+ update_release_draft:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: release-drafter/release-drafter@v6
+ with:
+ config-name: release-draft-template.yml
+ env:
+ GITHUB_TOKEN: ${{ secrets.RELEASE_DRAFTER_TOKEN }}
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 72ddc103..528a5b6f 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -9,68 +9,102 @@ on:
- staging
- main
+env:
+ fail-fast: true
+
jobs:
integration-tests:
# Will not run if the event is a PR to bump-meilisearch-v* (so a pre-release PR)
# Will still run for each push to bump-meilisearch-v*
if: github.event_name != 'pull_request' || !startsWith(github.base_ref, 'bump-meilisearch-v')
runs-on: ubuntu-latest
+ services:
+ meilisearch:
+ image: getmeili/meilisearch:latest
+ ports:
+ - 7700:7700
+ env:
+ MEILI_MASTER_KEY: masterKey
+ MEILI_NO_ANALYTICS: true
strategy:
matrix:
- php-version: ['7.4', '8.0', '8.1', '8.2']
- include:
+ php-version: ['7.4', '8.1', '8.2', '8.3']
+ sf-version: ['5.4', '6.4', '7.0', '7.1']
+ exclude:
- php-version: '7.4'
- sf-version: '4.4.*'
+ sf-version: '6.4'
- php-version: '7.4'
- sf-version: '5.4.*'
- - php-version: '8.0'
- sf-version: '6.0.*'
+ sf-version: '7.0'
+ - php-version: '7.4'
+ sf-version: '7.1'
+ - php-version: '8.1'
+ sf-version: '5.4'
- php-version: '8.1'
- sf-version: '6.0.*'
+ sf-version: '7.0'
- php-version: '8.1'
- sf-version: '6.1.*'
+ sf-version: '7.1'
- php-version: '8.2'
- sf-version: '6.2.*'
+ sf-version: '5.4'
+ - php-version: '8.3'
+ sf-version: '5.4'
+ - php-version: '8.3'
+ sf-version: '5.4'
- name: integration-tests (PHP ${{ matrix.php-version }}) (Symfony ${{ matrix.sf-version }})
+ name: integration-tests (PHP ${{ matrix.php-version }}) (Symfony ${{ matrix.sf-version }}.*)
steps:
- - uses: actions/checkout@v3
+ - name: Checkout code
+ uses: actions/checkout@v4
+
- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
- tools: composer:v2, flex
+ tools: composer, flex
+
- name: Validate composer.json and composer.lock
run: composer validate
+
+ - name: Remove doctrine/annotations
+ if: matrix.php-version != '7.4'
+ run: sed -i '/doctrine\/annotations/d' composer.json
+
- name: Install dependencies
+ uses: ramsey/composer-install@v3
env:
- SYMFONY_REQUIRE: ${{ matrix.sf-version }}
- run: composer install --prefer-dist --no-progress --quiet
- - name: "Remove doctrine/annotations"
- if: matrix.php-version != '7.4'
- run: |
- composer remove --dev doctrine/annotations
- - name: Meilisearch setup with Docker
- run: docker run -d -p 7700:7700 getmeili/meilisearch:latest meilisearch --master-key=masterKey --no-analytics
+ SYMFONY_REQUIRE: ${{ matrix.sf-version }}.*
+ with:
+ dependency-versions: 'highest'
+
- name: Run test suite
- run: composer test:unit
+ run: composer test:unit -- --coverage-clover coverage.xml
+
+ - name: Upload coverage file
+ uses: actions/upload-artifact@v4
+ with:
+ name: 'phpunit-${{ matrix.php-version }}-${{ matrix.sf-version }}-coverage'
+ path: 'coverage.xml'
code-style:
runs-on: ubuntu-latest
name: 'Code style'
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Install PHP
uses: shivammathur/setup-php@v2
with:
- php-version: '8.1'
+ php-version: 8.3
- name: Validate composer.json and composer.lock
run: composer validate
- name: Install dependencies
- run: composer install --prefer-dist --no-progress --quiet
+ uses: ramsey/composer-install@v3
+ env:
+ SYMFONY_REQUIRE: 7.1.*
+ with:
+ composer-options: '--no-progress --quiet'
+ dependency-versions: 'highest'
- name: PHP CS Fixer
run: composer lint:check
@@ -79,7 +113,39 @@ jobs:
run: composer phpmd
continue-on-error: true
- - name: PHPstan
+ - name: PHPStan
run: |
vendor/bin/simple-phpunit --version
composer phpstan
+
+ yaml-lint:
+ name: Yaml linting check
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Yaml lint check
+ uses: ibiqlik/action-yamllint@v3
+ with:
+ config_file: .yamllint.yml
+
+ upload-coverage:
+ name: Upload coverage to Codecov
+ runs-on: ubuntu-latest
+ needs:
+ - integration-tests
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 2
+
+ - name: Download coverage files
+ uses: actions/download-artifact@v4
+ with:
+ path: reports
+
+ - name: Upload to Codecov
+ uses: codecov/codecov-action@v4
+ with:
+ directory: reports
diff --git a/.gitignore b/.gitignore
index a0b80ceb..427199d6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
composer.lock
/vendor/
/var/
+phpstan.neon
# Meilisearch
/data.ms/*
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
index 9f927c45..5ea2c32b 100644
--- a/.php-cs-fixer.dist.php
+++ b/.php-cs-fixer.dist.php
@@ -6,21 +6,17 @@
->in(__DIR__.'/src')
->in(__DIR__.'/tests')
->append([__FILE__]);
-$config = new PhpCsFixer\Config();
-$config->setRules([
- '@Symfony' => true,
- '@PHP80Migration:risky' => true,
- 'global_namespace_import' => [
- 'import_classes' => false,
- 'import_functions' => false,
- 'import_constants' => false,
- ],
- 'no_superfluous_phpdoc_tags' => false,
- ]
-)
+return (new PhpCsFixer\Config())
->setRiskyAllowed(true)
->setFinder($finder)
-;
-
-return $config;
+ ->setRules([
+ '@Symfony' => true,
+ '@PHP80Migration:risky' => true,
+ 'global_namespace_import' => [
+ 'import_classes' => false,
+ 'import_functions' => false,
+ 'import_constants' => false,
+ ],
+ 'no_superfluous_phpdoc_tags' => false,
+ ]);
diff --git a/.yamllint.yml b/.yamllint.yml
new file mode 100644
index 00000000..35c43988
--- /dev/null
+++ b/.yamllint.yml
@@ -0,0 +1,9 @@
+extends: default
+ignore: |
+ vendor
+rules:
+ comments-indentation: disable
+ line-length: disable
+ document-start: disable
+ brackets: disable
+ truthy: disable
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3f666fb4..5951e5bd 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -16,7 +16,7 @@ First of all, thank you for contributing to Meilisearch! The goal of this docume
1. **You're familiar with [GitHub](https://github.com) and the [Pull Request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) (PR) workflow.**
2. **You've read the Meilisearch [documentation](https://docs.meilisearch.com) and the [README](/README.md).**
-3. **You know about the [Meilisearch community](https://docs.meilisearch.com/learn/what_is_meilisearch/contact.html). Please use this for help.**
+3. **You know about the [Meilisearch community](https://www.meilisearch.com/docs/learn/what_is_meilisearch/contact.html). Please use this for help.**
## How to Contribute
diff --git a/LICENSE b/LICENSE
index b1f0d22c..971d3878 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2019-2022 Meili SAS
+Copyright (c) 2019-2024 Meili SAS
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index ed2b2655..1323a7d4 100644
--- a/README.md
+++ b/README.md
@@ -6,14 +6,16 @@
+
@@ -26,9 +28,10 @@
**Meilisearch** is an open-source search engine. [Discover what Meilisearch is!](https://github.com/meilisearch/meilisearch)
-## Table of Contents
+## Table of Contents
- [π Documentation](#-documentation)
+- [β‘ Supercharge your Meilisearch experience](#-supercharge-your-meilisearch-experience)
- [π Requirements](#-requirements)
- [π€ Compatibility with Meilisearch](#-compatibility-with-meilisearch)
- [π‘ Learn More](#-learn-more)
@@ -38,13 +41,19 @@
Check out the [Wiki](https://github.com/meilisearch/meilisearch-symfony/wiki) of this repository to get started! π
-Also, see our [Documentation](https://docs.meilisearch.com/learn/tutorials/getting_started.html) or our [API References](https://docs.meilisearch.com/reference/api/).
+Also, see our [Documentation](https://www.meilisearch.com/docs/learn/getting_started/installation) or our [API References](https://www.meilisearch.com/docs/reference/api/overview).
+
+## β‘ Supercharge your Meilisearch experience
+
+Say goodbye to server deployment and manual updates with [Meilisearch Cloud](https://www.meilisearch.com/pricing?utm_campaign=oss&utm_source=integration&utm_medium=meilisearch-symfony). No credit card required.
## π Requirements
* **Require** PHP 7.4 and later.
-* **Compatible** with Symfony 4.0 and later.
-* **Support** Doctrine ORM and Doctrine MongoDB.
+* **Compatible** with Symfony 5.4 and later.
+* **Support** Doctrine ORM.
+
+For support of older versions, see older versions of this bundle.
## π€ Compatibility with Meilisearch
@@ -54,10 +63,10 @@ This package guarantees compatibility with [version v1.x of Meilisearch](https:/
The following sections may interest you:
-- **Manipulate documents**: see the [API references](https://docs.meilisearch.com/reference/api/documents.html) or read more about [documents](https://docs.meilisearch.com/learn/core_concepts/documents.html).
-- **Search**: see the [API references](https://docs.meilisearch.com/reference/api/search.html) or follow our guide on [search parameters](https://docs.meilisearch.com/reference/features/search_parameters.html).
-- **Manage the indexes**: see the [API references](https://docs.meilisearch.com/reference/api/indexes.html) or read more about [indexes](https://docs.meilisearch.com/learn/core_concepts/indexes.html).
-- **Configure the index settings**: see the [API references](https://docs.meilisearch.com/reference/api/settings.html) or follow our guide on [settings parameters](https://docs.meilisearch.com/reference/features/settings.html).
+- **Manipulate documents**: see the [API references](https://www.meilisearch.com/docs/reference/api/documents) or read more about [documents](https://www.meilisearch.com/docs/learn/core_concepts/documents).
+- **Search**: see the [API references](https://www.meilisearch.com/docs/reference/api/search) or follow our guide on [search parameters](https://www.meilisearch.com/docs/reference/api/search#search-parameters).
+- **Manage the indexes**: see the [API references](https://www.meilisearch.com/docs/reference/api/indexes) or read more about [indexes](https://www.meilisearch.com/docs/learn/core_concepts/indexes).
+- **Configure the index settings**: see the [API references](https://www.meilisearch.com/docs/reference/api/settings) or follow our guide on [settings parameters](https://www.meilisearch.com/docs/reference/api/settings#settings_parameters).
π Also, check out the [Wiki](https://github.com/meilisearch/meilisearch-symfony/wiki) of this repository!
diff --git a/bors.toml b/bors.toml
index 330d47fe..45afcecb 100644
--- a/bors.toml
+++ b/bors.toml
@@ -1,8 +1,12 @@
status = [
'integration-tests (PHP 7.4) (Symfony 5.4.*)',
- 'integration-tests (PHP 8.0) (Symfony 6.0.*)',
- 'integration-tests (PHP 8.1) (Symfony 6.1.*)',
- 'integration-tests (PHP 8.2) (Symfony 6.2.*)',
+ 'integration-tests (PHP 8.1) (Symfony 6.4.*)',
+ 'integration-tests (PHP 8.2) (Symfony 6.4.*)',
+ 'integration-tests (PHP 8.3) (Symfony 6.4.*)',
+ 'integration-tests (PHP 8.2) (Symfony 7.0.*)',
+ 'integration-tests (PHP 8.2) (Symfony 7.1.*)',
+ 'integration-tests (PHP 8.3) (Symfony 7.0.*)',
+ 'integration-tests (PHP 8.3) (Symfony 7.1.*)',
'Code style'
]
# 1 hour timeout
diff --git a/composer.json b/composer.json
index cea92a73..c04da0b6 100644
--- a/composer.json
+++ b/composer.json
@@ -20,29 +20,35 @@
"require": {
"php": "^7.4|^8.0",
"ext-json": "*",
- "doctrine/doctrine-bundle": "^2.4",
+ "doctrine/doctrine-bundle": "^2.10",
"meilisearch/meilisearch-php": "^1.0.0",
- "symfony/filesystem": "^4.4 || ^5.0 || ^6.0",
- "symfony/property-access": "^4.4 || ^5.0 || ^6.0",
- "symfony/serializer": "^4.4 || ^5.0 || ^6.0"
+ "symfony/config": "^5.4 || ^6.0 || ^7.0",
+ "symfony/dependency-injection": "^5.4.17 || ^6.0 || ^7.0",
+ "symfony/event-dispatcher": "^5.4 || ^6.0 || ^7.0",
+ "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0",
+ "symfony/polyfill-php80": "^1.27",
+ "symfony/property-access": "^5.4 || ^6.0 || ^7.0",
+ "symfony/serializer": "^5.4 || ^6.0 || ^7.0"
},
"require-dev": {
- "doctrine/annotations": "^2.0",
- "doctrine/orm": "^2.9",
- "phpmd/phpmd": "^2.13",
- "matthiasnoback/symfony-dependency-injection-test": "^4.3",
- "nyholm/psr7": "^1.5.1",
- "php-cs-fixer/shim": "^3.14",
- "phpstan/extension-installer": "^1.2",
- "phpstan/phpstan": "^1.10.6",
- "phpstan/phpstan-doctrine": "^1.3.33",
- "phpstan/phpstan-phpunit": "^1.3.10",
- "phpstan/phpstan-symfony": "^1.2.23",
- "phpunit/php-code-coverage": "^9.2.26",
- "symfony/doctrine-bridge": "^4.4 || ^5.0 || ^6.0",
- "symfony/http-client": "^4.4 || ^5.0 || ^6.0",
- "symfony/phpunit-bridge": "^4.4 || ^5.0 || ^6.0",
- "symfony/yaml": "^4.4 || ^5.0 || ^6.0"
+ "doctrine/annotations": "^2.0.0",
+ "doctrine/orm": "^2.12 || ^3.0",
+ "matthiasnoback/symfony-dependency-injection-test": "^4.3 || ^5.0",
+ "nyholm/psr7": "^1.8.1",
+ "php-cs-fixer/shim": "^3.58.1",
+ "phpmd/phpmd": "^2.15",
+ "phpstan/extension-installer": "^1.4.1",
+ "phpstan/phpstan": "^1.11.4",
+ "phpstan/phpstan-doctrine": "^1.4.3",
+ "phpstan/phpstan-phpunit": "^1.4.0",
+ "phpstan/phpstan-symfony": "^1.4.4",
+ "phpunit/php-code-coverage": "^9.2.31",
+ "symfony/doctrine-bridge": "^5.4.19 || ^6.0.7 || ^7.0",
+ "symfony/filesystem": "^5.4 || ^6.0 || ^7.0",
+ "symfony/framework-bundle": "^5.4.17 || ^6.0 || ^7.0",
+ "symfony/http-client": "^5.4 || ^6.0 || ^7.0",
+ "symfony/phpunit-bridge": "^6.4 || ^7.0",
+ "symfony/yaml": "^5.4 || ^6.0 || ^7.0"
},
"autoload": {
"psr-4": {
@@ -63,7 +69,7 @@
},
"scripts": {
"phpmd": "./vendor/bin/phpmd src text phpmd.xml",
- "phpstan": "./vendor/bin/phpstan --memory-limit=1G --ansi",
+ "phpstan": "./vendor/bin/phpstan",
"test:unit": "SYMFONY_DEPRECATIONS_HELPER='ignoreFile=./tests/baseline-ignore' ./vendor/bin/simple-phpunit --colors=always --verbose",
"test:unit:coverage": "SYMFONY_DEPRECATIONS_HELPER='ignoreFile=./tests/baseline-ignore' XDEBUG_MODE=coverage ./vendor/bin/simple-phpunit --colors=always --coverage-html=tests/coverage",
"lint:check": "./vendor/bin/php-cs-fixer fix -v --using-cache=no --dry-run",
diff --git a/config/services.xml b/config/services.xml
index cf25ac1e..414cfb31 100644
--- a/config/services.xml
+++ b/config/services.xml
@@ -4,13 +4,22 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd">
-
+
+
+
-
+
+
+
+
+
+
+
+
+ The "%alias_id%" service alias is deprecated. Use "meilisearch.service" instead.
+
-
+
@@ -18,12 +27,12 @@
- %meili_url%
- %meili_api_key%
-
-
- %meili_symfony_version%
-
+
+
+
+ null
+
+ null
The "%alias_id%" service alias is deprecated. Use "meilisearch.client" instead.
@@ -34,5 +43,43 @@
The "%alias_id%" service alias is deprecated. Use "meilisearch.client" instead.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/phpstan.neon b/phpstan.neon.dist
similarity index 50%
rename from phpstan.neon
rename to phpstan.neon.dist
index 5246556d..28e5679a 100644
--- a/phpstan.neon
+++ b/phpstan.neon.dist
@@ -5,3 +5,5 @@ parameters:
paths:
- src
- tests
+ ignoreErrors:
+ - '#Call to static method getClass\(\) on an unknown class Doctrine\\Common\\Util\\ClassUtils#'
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 25bcf37c..d50518cb 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -14,6 +14,7 @@
+
diff --git a/src/Collection.php b/src/Collection.php
index e3c0569d..c9a90651 100644
--- a/src/Collection.php
+++ b/src/Collection.php
@@ -65,7 +65,7 @@ public function map(callable $callback)
*
* @return static
*/
- public function filter(callable $callback = null)
+ public function filter(?callable $callback = null)
{
if (null !== $callback) {
return new self(array_filter($this->items, $callback, ARRAY_FILTER_USE_BOTH));
@@ -143,7 +143,7 @@ public function unique($key = null, bool $strict = false)
/**
* Get the first item from the collection passing the given truth test.
*/
- public function first(callable $callback = null, $default = null)
+ public function first(?callable $callback = null, $default = null)
{
if (is_null($callback)) {
if (empty($this->items)) {
@@ -339,7 +339,7 @@ private static function existsInArray($array, $key): bool
return array_key_exists($key, $array);
}
- private function operatorForWhere(string $key, string $operator = null, $value = null): \Closure
+ private function operatorForWhere(string $key, ?string $operator = null, $value = null): \Closure
{
if (1 === func_num_args()) {
$value = true;
diff --git a/src/Command/IndexCommand.php b/src/Command/IndexCommand.php
index 5b54d373..e9f37d2b 100644
--- a/src/Command/IndexCommand.php
+++ b/src/Command/IndexCommand.php
@@ -10,14 +10,14 @@
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-/**
- * Class IndexCommand.
- */
abstract class IndexCommand extends Command
{
- private string $prefix;
+ protected const DEFAULT_RESPONSE_TIMEOUT = 5000;
+
protected SearchService $searchService;
+ private string $prefix;
+
public function __construct(SearchService $searchService)
{
$this->searchService = $searchService;
diff --git a/src/Command/MeilisearchClearCommand.php b/src/Command/MeilisearchClearCommand.php
index ffbb465d..54a35caa 100644
--- a/src/Command/MeilisearchClearCommand.php
+++ b/src/Command/MeilisearchClearCommand.php
@@ -8,14 +8,11 @@
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
-/**
- * Class MeilisearchClearCommand.
- */
final class MeilisearchClearCommand extends IndexCommand
{
public static function getDefaultName(): string
{
- return 'meili:clear';
+ return 'meilisearch:clear|meili:clear';
}
public static function getDefaultDescription(): string
diff --git a/src/Command/MeilisearchCreateCommand.php b/src/Command/MeilisearchCreateCommand.php
index d2c32157..7ec47a1b 100644
--- a/src/Command/MeilisearchCreateCommand.php
+++ b/src/Command/MeilisearchCreateCommand.php
@@ -5,30 +5,35 @@
namespace Meilisearch\Bundle\Command;
use Meilisearch\Bundle\Collection;
-use Meilisearch\Bundle\Exception\InvalidSettingName;
-use Meilisearch\Bundle\Exception\TaskException;
+use Meilisearch\Bundle\EventListener\ConsoleOutputSubscriber;
use Meilisearch\Bundle\Model\Aggregator;
use Meilisearch\Bundle\SearchService;
-use Meilisearch\Bundle\SettingsProvider;
+use Meilisearch\Bundle\Services\SettingsUpdater;
use Meilisearch\Client;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
final class MeilisearchCreateCommand extends IndexCommand
{
private Client $searchClient;
+ private SettingsUpdater $settingsUpdater;
+ private EventDispatcherInterface $eventDispatcher;
- public function __construct(SearchService $searchService, Client $searchClient)
+ public function __construct(SearchService $searchService, Client $searchClient, SettingsUpdater $settingsUpdater, EventDispatcherInterface $eventDispatcher)
{
parent::__construct($searchService);
$this->searchClient = $searchClient;
+ $this->settingsUpdater = $settingsUpdater;
+ $this->eventDispatcher = $eventDispatcher;
}
public static function getDefaultName(): string
{
- return 'meili:create';
+ return 'meilisearch:create|meili:create';
}
public static function getDefaultDescription(): string
@@ -40,33 +45,32 @@ protected function configure(): void
{
$this
->setDescription(self::getDefaultDescription())
- ->addOption('indices', 'i', InputOption::VALUE_OPTIONAL, 'Comma-separated list of index names');
- }
-
- private function entitiesToIndex($indexes): array
- {
- foreach ($indexes as $key => $index) {
- $entityClassName = $index['class'];
- if (is_subclass_of($entityClassName, Aggregator::class)) {
- $indexes->forget($key);
-
- $indexes = new Collection(array_merge(
- $indexes->all(),
- array_map(
- static fn ($entity) => ['name' => $index['name'], 'class' => $entity],
- $entityClassName::getEntities()
- )
- ));
- }
- }
-
- return array_unique($indexes->all(), SORT_REGULAR);
+ ->addOption('indices', 'i', InputOption::VALUE_OPTIONAL, 'Comma-separated list of index names')
+ ->addOption(
+ 'update-settings',
+ null,
+ InputOption::VALUE_NEGATABLE,
+ 'Update settings related to indices to the search engine',
+ true
+ )
+ ->addOption(
+ 'response-timeout',
+ 't',
+ InputOption::VALUE_REQUIRED,
+ 'Timeout (in ms) to get response from the search engine',
+ self::DEFAULT_RESPONSE_TIMEOUT
+ )
+ ;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
+ $this->eventDispatcher->addSubscriber(new ConsoleOutputSubscriber(new SymfonyStyle($input, $output)));
+
$indexes = $this->getEntitiesFromArgs($input, $output);
$entitiesToIndex = $this->entitiesToIndex($indexes);
+ $updateSettings = $input->getOption('update-settings');
+ $responseTimeout = ((int) $input->getOption('response-timeout')) ?: self::DEFAULT_RESPONSE_TIMEOUT;
/** @var array $index */
foreach ($entitiesToIndex as $index) {
@@ -79,39 +83,38 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$output->writeln('Creating index '.$index['name'].' for '.$entityClassName.'');
$task = $this->searchClient->createIndex($index['name']);
- $this->searchClient->waitForTask($task['taskUid']);
- $indexInstance = $this->searchClient->index($index['name']);
+ $this->searchClient->waitForTask($task['taskUid'], $responseTimeout);
- if (isset($index['settings']) && is_array($index['settings'])) {
- foreach ($index['settings'] as $variable => $value) {
- $method = sprintf('update%s', ucfirst($variable));
+ if ($updateSettings) {
+ $this->settingsUpdater->update($index['name'], $responseTimeout);
+ }
+ }
- if (!method_exists($indexInstance, $method)) {
- throw new InvalidSettingName(sprintf('Invalid setting name: "%s"', $variable));
- }
+ $output->writeln('Done!');
- if (isset($value['_service']) && $value['_service'] instanceof SettingsProvider) {
- $value = $value['_service']();
- }
+ return 0;
+ }
- // Update
- $task = $indexInstance->{$method}($value);
+ private function entitiesToIndex($indexes): array
+ {
+ foreach ($indexes as $key => $index) {
+ $entityClassName = $index['class'];
- // Get task information using uid
- $indexInstance->waitForTask($task['taskUid']);
- $task = $indexInstance->getTask($task['taskUid']);
+ if (!is_subclass_of($entityClassName, Aggregator::class)) {
+ continue;
+ }
- if ('failed' === $task['status']) {
- throw new TaskException($task['error']);
- }
+ $indexes->forget($key);
- $output->writeln('Settings updated of "'.$index['name'].'".');
- }
- }
+ $indexes = new Collection(array_merge(
+ $indexes->all(),
+ array_map(
+ static fn ($entity) => ['name' => $index['name'], 'prefixed_name' => $index['prefixed_name'], 'class' => $entity],
+ $entityClassName::getEntities()
+ )
+ ));
}
- $output->writeln('Done!');
-
- return 0;
+ return array_unique($indexes->all(), SORT_REGULAR);
}
}
diff --git a/src/Command/MeilisearchDeleteCommand.php b/src/Command/MeilisearchDeleteCommand.php
index a316ed19..04bffc27 100644
--- a/src/Command/MeilisearchDeleteCommand.php
+++ b/src/Command/MeilisearchDeleteCommand.php
@@ -10,14 +10,11 @@
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
-/**
- * Class MeilisearchDeleteCommand.
- */
final class MeilisearchDeleteCommand extends IndexCommand
{
public static function getDefaultName(): string
{
- return 'meili:delete';
+ return 'meilisearch:delete|meili:delete';
}
public static function getDefaultDescription(): string
diff --git a/src/Command/MeilisearchImportCommand.php b/src/Command/MeilisearchImportCommand.php
index 8bf1a2e7..fe0a0555 100644
--- a/src/Command/MeilisearchImportCommand.php
+++ b/src/Command/MeilisearchImportCommand.php
@@ -6,38 +6,39 @@
use Doctrine\Persistence\ManagerRegistry;
use Meilisearch\Bundle\Collection;
-use Meilisearch\Bundle\Exception\InvalidSettingName;
+use Meilisearch\Bundle\EventListener\ConsoleOutputSubscriber;
use Meilisearch\Bundle\Exception\TaskException;
use Meilisearch\Bundle\Model\Aggregator;
use Meilisearch\Bundle\SearchService;
-use Meilisearch\Bundle\SettingsProvider;
+use Meilisearch\Bundle\Services\SettingsUpdater;
use Meilisearch\Client;
use Meilisearch\Exceptions\TimeOutException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-/**
- * Class MeilisearchImportCommand.
- */
final class MeilisearchImportCommand extends IndexCommand
{
- private const DEFAULT_RESPONSE_TIMEOUT = 5000;
+ private Client $searchClient;
+ private ManagerRegistry $managerRegistry;
+ private SettingsUpdater $settingsUpdater;
+ private EventDispatcherInterface $eventDispatcher;
- protected Client $searchClient;
- protected ManagerRegistry $managerRegistry;
-
- public function __construct(SearchService $searchService, ManagerRegistry $managerRegistry, Client $searchClient)
+ public function __construct(SearchService $searchService, ManagerRegistry $managerRegistry, Client $searchClient, SettingsUpdater $settingsUpdater, EventDispatcherInterface $eventDispatcher)
{
parent::__construct($searchService);
$this->managerRegistry = $managerRegistry;
$this->searchClient = $searchClient;
+ $this->settingsUpdater = $settingsUpdater;
+ $this->eventDispatcher = $eventDispatcher;
}
public static function getDefaultName(): string
{
- return 'meili:import';
+ return 'meilisearch:import|meili:import';
}
public static function getDefaultDescription(): string
@@ -53,8 +54,9 @@ protected function configure(): void
->addOption(
'update-settings',
null,
- InputOption::VALUE_NONE,
- 'Update settings related to indices to the search engine'
+ InputOption::VALUE_NEGATABLE,
+ 'Update settings related to indices to the search engine',
+ true
)
->addOption('batch-size', null, InputOption::VALUE_REQUIRED)
->addOption(
@@ -76,25 +78,12 @@ protected function configure(): void
protected function execute(InputInterface $input, OutputInterface $output): int
{
+ $this->eventDispatcher->addSubscriber(new ConsoleOutputSubscriber(new SymfonyStyle($input, $output)));
+
$indexes = $this->getEntitiesFromArgs($input, $output);
+ $entitiesToIndex = $this->entitiesToIndex($indexes);
$config = $this->searchService->getConfiguration();
-
- foreach ($indexes as $key => $index) {
- $entityClassName = $index['class'];
- if (is_subclass_of($entityClassName, Aggregator::class)) {
- $indexes->forget($key);
-
- $indexes = new Collection(array_merge(
- $indexes->all(),
- array_map(
- fn ($entity) => ['class' => $entity],
- $entityClassName::getEntities()
- )
- ));
- }
- }
-
- $entitiesToIndex = array_unique($indexes->all(), SORT_REGULAR);
+ $updateSettings = $input->getOption('update-settings');
$batchSize = $input->getOption('batch-size') ?? '';
$batchSize = ctype_digit($batchSize) ? (int) $batchSize : $config->get('batchSize');
$responseTimeout = ((int) $input->getOption('response-timeout')) ?: self::DEFAULT_RESPONSE_TIMEOUT;
@@ -102,6 +91,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
/** @var array $index */
foreach ($entitiesToIndex as $index) {
$entityClassName = $index['class'];
+
if (!$this->searchService->isSearchable($entityClassName)) {
continue;
}
@@ -151,34 +141,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
);
}
- if (isset($index['settings'])
- && is_array($index['settings'])
- && count($index['settings']) > 0) {
- $indexInstance = $this->searchClient->index($index['name']);
- foreach ($index['settings'] as $variable => $value) {
- $method = sprintf('update%s', ucfirst($variable));
-
- if (!method_exists($indexInstance, $method)) {
- throw new InvalidSettingName(sprintf('Invalid setting name: "%s"', $variable));
- }
-
- if (isset($value['_service']) && $value['_service'] instanceof SettingsProvider) {
- $value = $value['_service']();
- }
-
- // Update
- $task = $indexInstance->{$method}($value);
-
- // Get task information using uid
- $indexInstance->waitForTask($task['taskUid'], $responseTimeout);
- $task = $indexInstance->getTask($task['taskUid']);
-
- if ('failed' === $task['status']) {
- throw new TaskException($task['error']);
- }
-
- $output->writeln('Settings updated of "'.$index['name'].'".');
- }
+ if ($updateSettings) {
+ $this->settingsUpdater->update($index['prefixed_name'], $responseTimeout);
}
++$page;
@@ -221,4 +185,27 @@ private function formatIndexingResponse(array $batch, int $responseTimeout): arr
return $formattedResponse;
}
+
+ private function entitiesToIndex($indexes): array
+ {
+ foreach ($indexes as $key => $index) {
+ $entityClassName = $index['class'];
+
+ if (!is_subclass_of($entityClassName, Aggregator::class)) {
+ continue;
+ }
+
+ $indexes->forget($key);
+
+ $indexes = new Collection(array_merge(
+ $indexes->all(),
+ array_map(
+ static fn ($entity) => ['name' => $index['name'], 'prefixed_name' => $index['prefixed_name'], 'class' => $entity],
+ $entityClassName::getEntities()
+ )
+ ));
+ }
+
+ return array_unique($indexes->all(), SORT_REGULAR);
+ }
}
diff --git a/src/DataCollector/MeilisearchDataCollector.php b/src/DataCollector/MeilisearchDataCollector.php
new file mode 100644
index 00000000..73c8fb3f
--- /dev/null
+++ b/src/DataCollector/MeilisearchDataCollector.php
@@ -0,0 +1,40 @@
+
+ */
+final class MeilisearchDataCollector extends AbstractDataCollector
+{
+ private TraceableMeilisearchService $meilisearchService;
+
+ public function __construct(TraceableMeilisearchService $meilisearchService)
+ {
+ $this->meilisearchService = $meilisearchService;
+ }
+ public function collect(Request $request, Response $response, \Throwable $exception = null): void
+ {
+ $data = $this->meilisearchService->getData();
+
+ $this->data[$this->getName()] = !empty($data) ? $this->cloneVar($data) : null;
+ }
+
+ public function getName(): string
+ {
+ return 'meilisearch';
+ }
+
+ /** @internal used in the DataCollector view template */
+ public function getMeilisearch(): mixed
+ {
+ return $this->data[$this->getName()] ?? null;
+ }
+}
diff --git a/src/Debug/TraceableMeilisearchService.php b/src/Debug/TraceableMeilisearchService.php
new file mode 100644
index 00000000..f23875b2
--- /dev/null
+++ b/src/Debug/TraceableMeilisearchService.php
@@ -0,0 +1,110 @@
+
+ */
+final class TraceableMeilisearchService implements SearchService
+{
+ private SearchService $searchService;
+ private Stopwatch $stopwatch;
+ private array $data = [];
+
+ public function __construct(SearchService $searchService, Stopwatch $stopwatch)
+ {
+ $this->searchService = $searchService;
+ $this->stopwatch = $stopwatch;
+ }
+
+ public function index(ObjectManager $objectManager, $searchable): array
+ {
+ return $this->innerSearchService(__FUNCTION__, \func_get_args());
+ }
+
+ public function remove(ObjectManager $objectManager, $searchable): array
+ {
+ return $this->innerSearchService(__FUNCTION__, \func_get_args());
+ }
+
+ public function clear(string $className): array
+ {
+ return $this->innerSearchService(__FUNCTION__, \func_get_args());
+ }
+
+ public function deleteByIndexName(string $indexName): ?array
+ {
+ return $this->innerSearchService(__FUNCTION__, \func_get_args());
+ }
+
+ public function delete(string $className): ?array
+ {
+ return $this->innerSearchService(__FUNCTION__, \func_get_args());
+ }
+
+ public function search(ObjectManager $objectManager, string $className, string $query = '', array $searchParams = []): array
+ {
+ return $this->innerSearchService(__FUNCTION__, \func_get_args());
+ }
+
+ public function rawSearch(string $className, string $query = '', array $searchParams = []): array
+ {
+ return $this->innerSearchService(__FUNCTION__, \func_get_args());
+ }
+
+ public function count(string $className, string $query = '', array $searchParams = []): int
+ {
+ return $this->innerSearchService(__FUNCTION__, \func_get_args());
+ }
+
+ public function isSearchable($className): bool
+ {
+ return $this->searchService->isSearchable($className);
+ }
+
+ public function getSearchable(): array
+ {
+ return $this->searchService->getSearchable();
+ }
+
+ public function getConfiguration(): Collection
+ {
+ return $this->searchService->getConfiguration();
+ }
+
+ public function searchableAs(string $className): string
+ {
+ return $this->searchService->searchableAs($className);
+ }
+
+ /** @internal used in the DataCollector class */
+ public function getData(): array
+ {
+ return $this->data;
+ }
+
+ private function innerSearchService(string $function, array $args): mixed
+ {
+ $this->stopwatch->start($function);
+
+ $result = $this->searchService->{$function}(...$args);
+
+ $event = $this->stopwatch->stop($function);
+
+ $this->data[$function] = [
+ '_params' => $args,
+ '_results' => $result,
+ '_duration' => $event->getDuration(),
+ '_memory' => $event->getMemory(),
+ ];
+
+ return $result;
+ }
+}
diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php
index 4999bfb8..83464d59 100644
--- a/src/DependencyInjection/Configuration.php
+++ b/src/DependencyInjection/Configuration.php
@@ -17,15 +17,15 @@ public function getConfigTreeBuilder(): TreeBuilder
$rootNode
->children()
- ->scalarNode('url')->end()
- ->scalarNode('api_key')->end()
+ ->scalarNode('url')->defaultValue('http://localhost:7700')->end()
+ ->scalarNode('api_key')->defaultNull()->end()
->scalarNode('prefix')
- ->defaultValue(null)
+ ->defaultNull()
->end()
- ->scalarNode('nbResults')
+ ->integerNode('nbResults')
->defaultValue(20)
->end()
- ->scalarNode('batchSize')
+ ->integerNode('batchSize')
->defaultValue(500)
->end()
->arrayNode('doctrineSubscribedEvents')
@@ -60,7 +60,21 @@ public function getConfigTreeBuilder(): TreeBuilder
->defaultNull()
->end()
->arrayNode('settings')
- ->info('Configure indices settings, see: https://docs.meilisearch.com/guides/advanced_guides/settings.html')
+ ->info('Configure indices settings, see: https://www.meilisearch.com/docs/reference/api/settings')
+ ->beforeNormalization()
+ ->always()
+ ->then(static function (array $value) {
+ $stringSettings = ['distinctAttribute', 'proximityPrecision', 'searchCutoffMs'];
+
+ foreach ($stringSettings as $setting) {
+ if (isset($value[$setting]) && !is_array($value[$setting])) {
+ $value[$setting] = (array) $value[$setting];
+ }
+ }
+
+ return $value;
+ })
+ ->end()
->arrayPrototype()
->variablePrototype()->end()
->end()
diff --git a/src/DependencyInjection/MeilisearchExtension.php b/src/DependencyInjection/MeilisearchExtension.php
index bc07379a..002977d0 100644
--- a/src/DependencyInjection/MeilisearchExtension.php
+++ b/src/DependencyInjection/MeilisearchExtension.php
@@ -4,19 +4,18 @@
namespace Meilisearch\Bundle\DependencyInjection;
-use Meilisearch\Bundle\Engine;
+use Meilisearch\Bundle\DataCollector\MeilisearchDataCollector;
+use Meilisearch\Bundle\Debug\TraceableMeilisearchService;
use Meilisearch\Bundle\MeilisearchBundle;
-use Meilisearch\Bundle\Services\MeilisearchService;
+use Meilisearch\Bundle\SearchService;
+use Meilisearch\Bundle\Services\UnixTimestampNormalizer;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
-use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Reference;
-use Symfony\Component\HttpKernel\DependencyInjection\Extension;
+use Symfony\Component\HttpKernel\Kernel;
-/**
- * Class MeilisearchExtension.
- */
final class MeilisearchExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container): void
@@ -32,6 +31,7 @@ public function load(array $configs, ContainerBuilder $container): void
}
foreach ($config['indices'] as $index => $indice) {
+ $config['indices'][$index]['prefixed_name'] = $config['prefix'].$indice['name'];
$config['indices'][$index]['settings'] = $this->findReferences($config['indices'][$index]['settings']);
}
@@ -50,15 +50,31 @@ public function load(array $configs, ContainerBuilder $container): void
$container->removeDefinition('meilisearch.search_indexer_subscriber');
}
- $engineDefinition = new Definition(Engine::class, [new Reference('meilisearch.client')]);
+ $container->findDefinition('meilisearch.client')
+ ->replaceArgument(0, $config['url'])
+ ->replaceArgument(1, $config['api_key'])
+ ->replaceArgument(4, [MeilisearchBundle::qualifiedVersion()]);
- $searchDefinition = (new Definition(
- MeilisearchService::class,
- [new Reference($config['serializer']), $engineDefinition, $config]
- ));
+ $container->findDefinition('meilisearch.service')
+ ->replaceArgument(0, new Reference($config['serializer']))
+ ->replaceArgument(2, $config);
- $container->setDefinition('meilisearch.service', $searchDefinition->setPublic(true));
- $container->setAlias('search.service', 'meilisearch.service')->setPublic(true);
+ if ($container->getParameter('kernel.debug')) {
+ $container->register('debug.meilisearch.service', TraceableMeilisearchService::class)
+ ->setDecoratedService(SearchService::class)
+ ->addArgument(new Reference('debug.meilisearch.service.inner'))
+ ->addArgument(new Reference('debug.stopwatch'));
+ $container->register('data_collector.meilisearch', MeilisearchDataCollector::class)
+ ->addArgument(new Reference('debug.meilisearch.service'))
+ ->addTag('data_collector', [
+ 'id' => 'meilisearch',
+ 'template' => '@Meilisearch/DataCollector/meilisearch.html.twig',
+ ]);
+ }
+
+ if (Kernel::VERSION_ID >= 70100) {
+ $container->removeDefinition(UnixTimestampNormalizer::class);
+ }
}
/**
diff --git a/src/Document/Aggregator.php b/src/Document/Aggregator.php
index 0f45cdf7..336e3bcb 100644
--- a/src/Document/Aggregator.php
+++ b/src/Document/Aggregator.php
@@ -6,9 +6,6 @@
use Meilisearch\Bundle\Model\Aggregator as BaseAggregator;
-/**
- * Class Aggregator.
- */
abstract class Aggregator extends BaseAggregator
{
}
diff --git a/src/Engine.php b/src/Engine.php
index 9fb960ed..1bd47662 100644
--- a/src/Engine.php
+++ b/src/Engine.php
@@ -7,9 +7,6 @@
use Meilisearch\Client;
use Meilisearch\Exceptions\ApiException;
-/**
- * Class Engine.
- */
final class Engine
{
private Client $client;
@@ -104,7 +101,7 @@ public function remove($searchableEntities): array
/**
* Clear the records of an index.
* This method enables you to delete an indexβs contents (records).
- * Will fail if the index does not exists.
+ * Will fail if the index does not exist.
*
* @throws ApiException
*/
diff --git a/src/Entity/Aggregator.php b/src/Entity/Aggregator.php
index 0d89d70a..6bad4094 100644
--- a/src/Entity/Aggregator.php
+++ b/src/Entity/Aggregator.php
@@ -6,9 +6,6 @@
use Meilisearch\Bundle\Model\Aggregator as BaseAggregator;
-/**
- * Class Aggregator.
- */
abstract class Aggregator extends BaseAggregator
{
}
diff --git a/src/Event/SettingsUpdatedEvent.php b/src/Event/SettingsUpdatedEvent.php
new file mode 100644
index 00000000..0c77670c
--- /dev/null
+++ b/src/Event/SettingsUpdatedEvent.php
@@ -0,0 +1,46 @@
+index = $index;
+ $this->class = $class;
+ }
+
+ /**
+ * @return class-string
+ */
+ public function getClass(): string
+ {
+ return $this->class;
+ }
+
+ /**
+ * @return non-empty-string
+ */
+ public function getIndex(): string
+ {
+ return $this->index;
+ }
+}
diff --git a/src/EventListener/ConsoleOutputSubscriber.php b/src/EventListener/ConsoleOutputSubscriber.php
new file mode 100644
index 00000000..5aaf51f7
--- /dev/null
+++ b/src/EventListener/ConsoleOutputSubscriber.php
@@ -0,0 +1,31 @@
+io = $io;
+ }
+
+ public function afterSettingsUpdate(SettingsUpdatedEvent $event): void
+ {
+ $this->io->writeln('Settings updated of "'.$event->getIndex().'".');
+ }
+
+ public static function getSubscribedEvents(): array
+ {
+ return [
+ SettingsUpdatedEvent::class => 'afterSettingsUpdate',
+ ];
+ }
+}
diff --git a/src/Exception/EntityNotFoundInObjectID.php b/src/Exception/EntityNotFoundInObjectID.php
index f8081660..d9e1b16a 100644
--- a/src/Exception/EntityNotFoundInObjectID.php
+++ b/src/Exception/EntityNotFoundInObjectID.php
@@ -4,9 +4,6 @@
namespace Meilisearch\Bundle\Exception;
-/**
- * Class EntityNotFoundInObjectID.
- */
final class EntityNotFoundInObjectID extends \LogicException
{
}
diff --git a/src/Exception/InvalidIndiceException.php b/src/Exception/InvalidIndiceException.php
new file mode 100644
index 00000000..a7ce9aef
--- /dev/null
+++ b/src/Exception/InvalidIndiceException.php
@@ -0,0 +1,13 @@
+ $this->objectID], $normalizer->normalize($this->entity, $format, $context));
}
diff --git a/src/SearchService.php b/src/SearchService.php
index 8e5e023b..9fbdcfef 100644
--- a/src/SearchService.php
+++ b/src/SearchService.php
@@ -6,9 +6,6 @@
use Doctrine\Persistence\ObjectManager;
-/**
- * Interface SearchService.
- */
interface SearchService
{
public const RESULT_KEY_HITS = 'hits';
diff --git a/src/Searchable.php b/src/Searchable.php
index 47e4dd35..b4e3da0a 100644
--- a/src/Searchable.php
+++ b/src/Searchable.php
@@ -4,9 +4,6 @@
namespace Meilisearch\Bundle;
-/**
- * Class Searchable.
- */
final class Searchable
{
public const NORMALIZATION_FORMAT = 'searchableArray';
diff --git a/src/SearchableEntity.php b/src/SearchableEntity.php
index 85f77048..7b072d55 100644
--- a/src/SearchableEntity.php
+++ b/src/SearchableEntity.php
@@ -6,13 +6,12 @@
use Doctrine\ORM\Mapping\ClassMetadata;
use Symfony\Component\Config\Definition\Exception\Exception;
+use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Serializer\Exception\ExceptionInterface;
+use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
use Symfony\Component\Serializer\Normalizer\NormalizableInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
-/**
- * Class SearchableEntity.
- */
final class SearchableEntity
{
private string $indexUid;
@@ -34,8 +33,6 @@ final class SearchableEntity
private $id;
/**
- * SearchableEntity constructor.
- *
* @param object $entity
* @param ClassMetadata