diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8047248..0ed845d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,27 +52,27 @@ jobs: - php-version: "8.0" symfony-version: "5.4.*" composer-flags: "--prefer-lowest" - es-version: "7.17.3" + es-version: "7.17.25" # Every lowest supported version && Symfony 6 - php-version: "8.1" symfony-version: "6.2.*" composer-flags: "" - es-version: "7.17.3" + es-version: "7.17.25" # PHP 8.1, latest SF 6, ES 7 - php-version: "8.1" symfony-version: "6.*" composer-flags: "" - es-version: "7.17.3" + es-version: "7.17.25" # PHP 8.2, latest SF 6, ES 8 - php-version: "8.2" symfony-version: "6.*" composer-flags: "" - es-version: "8.2.0" + es-version: "8.16.0" # PHP 8.3, latest SF 7, ES 8 - php-version: "8.3" symfony-version: "7.*" composer-flags: "" - es-version: "8.2.0" + es-version: "8.16.0" steps: - name: Checkout uses: actions/checkout@v4 @@ -115,72 +115,3 @@ jobs: - name: Run Tests run: make test - - tests_opensearch: - name: Test PHP ${{ matrix.php-version }} & Symfony ${{ matrix.symfony-version }} ${{ matrix.composer-flags }} & OpenSearch ${{ matrix.os-version }} - runs-on: ubuntu-latest - env: - SYMFONY_REQUIRE: ${{ matrix.symfony-version }} - strategy: - fail-fast: false - matrix: - include: - - php-version: "8.3" - symfony-version: "6.*" - composer-flags: "" - os-version: 1.3.6 - os-image: opensearchproject/opensearch:1.3.6 - - php-version: "8.3" - symfony-version: "6.*" - composer-flags: "" - os-version: 2.3.0 - os-image: opensearchproject/opensearch:2.3.0 - - php-version: "8.3" - symfony-version: "7.*" - composer-flags: "" - os-version: 2.3.0 - os-image: opensearchproject/opensearch:2.3.0 - services: - search-server: - image: ${{ matrix.os-image }} - ports: - - 9999:9999 - env: - discovery.type: single-node - plugins.security.disabled: true - http.port: 9999 - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup PHP, with composer and extensions - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-version }} - - # We need Flex to enfore Symfony version with `SYMFONY_REQUIRE` env var - - name: Install Symfony Flex - run: composer global require --no-progress --no-scripts --no-plugins symfony/flex - - - name: Enable Symfony Flex - run: composer global config --no-plugins allow-plugins.symfony/flex true - - - name: Install Composer dependencies - run: composer update --prefer-dist --no-interaction --no-ansi ${{ matrix.composer-flags }} - - - name: Configure sysctl limits - run: | - sudo swapoff -a - sudo sysctl -w vm.swappiness=1 - sudo sysctl -w fs.file-max=262144 - sudo sysctl -w vm.max_map_count=262144 - - - name: Wait for OpenSearch to be ready - run: | - while ! curl -s -X GET http://127.0.0.1:9999/_cluster/health\?wait_for_status\=green\&timeout\=60s | grep -q '"status":"green"' - do - echo "==> Waiting for cluster green status" && sleep 1 - done - - - name: Run Tests - run: make test diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b6ba13..7d5ee3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + ## 2.0.0 +Massive release with added support for Elastica 8 and all deprecated code removed. + ### Added -- Updated `ruflin/elastica` to v8 (Breaking Change) +- Upgraded `ruflin/elastica` to v8 (Breaking Change) + +### Removed + +- Dropped OpenSearch support (Breaking Change) - Dropped `HttpClientTransport` (Breaking Change) +- All depreacted code from 1.x, see [UPGRADE.md](UPGRADE.md) for the full list ## 1.9.1 diff --git a/Makefile b/Makefile index be61188..82bf09e 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,20 @@ test: ## Run test suite ./vendor/bin/simple-phpunit -start: ## Start testing tools (Elasticsearch) - docker run --rm -d --name "elastically_es" -p 9999:9200 -e "discovery.type=single-node" -e "xpack.security.enabled=false" -e "action.destructive_requires_name=false" -it -m 1GB docker.elastic.co/elasticsearch/elasticsearch:8.14.2 +start_7: ## Start testing tools (Elasticsearch 7) + docker run --rm -d --name "elastically_es" -p 9999:9200 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:7.17.25 -start_opensearch: ## Start testing tools (OpenSearch) - docker run --rm -d --name "elastically_es" -p 9999:9200 -e "discovery.type=single-node" -e "plugins.security.disabled=true" opensearchproject/opensearch:2.3.0 +start: ## Start testing tools (Elasticsearch 8) + docker run --rm -d --name "elastically_es" -p 9999:9200 -e "discovery.type=single-node" -e "xpack.security.enabled=false" -e "action.destructive_requires_name=false" -it -m 1GB docker.elastic.co/elasticsearch/elasticsearch:8.16.0 + +#start_opensearch: ## Start testing tools (OpenSearch) +# docker run --rm -d --name "elastically_es" -p 9999:9200 -e "discovery.type=single-node" -e "DISABLE_SECURITY_PLUGIN=true" opensearchproject/opensearch:2 stop: ## Stop testing tools docker stop "elastically_es" kibana: ## Start debug tools (Kibana) - docker run -e "ELASTICSEARCH_HOSTS=http://127.0.0.1:9999/" --network host docker.elastic.co/kibana/kibana-oss:7.8.0 + docker run -e "ELASTICSEARCH_HOSTS=http://127.0.0.1:9999/" --network host docker.elastic.co/kibana/kibana:7.17.25 cs: ## Fix PHP CS ./vendor/bin/php-cs-fixer fix --verbose diff --git a/README.md b/README.md index fa928e6..2b2d7c3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Elastically, **Elastica** based framework -Opinionated [Elastica](https://github.com/ruflin/Elastica) based framework to bootstrap PHP and Elasticsearch / OpenSearch implementations. +Opinionated [Elastica](https://github.com/ruflin/Elastica) based framework to bootstrap PHP and Elasticsearch implementations. Main features: @@ -17,11 +17,11 @@ Main features: - Symfony Messenger Handler support (with or without spool); > [!IMPORTANT] -> Require PHP 8.0+ and Elasticsearch 7+. +> Require PHP 8.0+ and Elasticsearch 8+. -Works with **Elasticsearch 8+** but is not officially supported by Elastica yet. Use with caution. +Works with **Elasticsearch 7** as well but is not officially supported by Elastica 8. Use with caution. -Works with **OpenSearch 1 and 2**. +Version 2+ does not work with **OpenSearch** anymore due to restrictions added by Elastic on their client. You can check the [changelog](CHANGELOG.md) and the [upgrade](UPGRADE.md) documents. @@ -252,7 +252,6 @@ elastically: default: client: host: '%env(ELASTICSEARCH_HOST)%' - # If you want to use the Symfony HttpClient (you MUST create this service) # Path to the mapping directory (in YAML) mapping_directory: '%kernel.project_dir%/config/elasticsearch' @@ -339,10 +338,12 @@ JoliCode\Elastically\Client: arguments: $config: host: '%env(ELASTICSEARCH_HOST)%' - transport: 'JoliCode\Elastically\Transport\HttpClientTransport' - # ... + transport_client: + client: '@my_custom_psr18_client' # An instance of Symfony\Component\HttpClient\Psr18Client (Or any PSR 18 compliant one) ``` +See the [official documentation on how to get a PSR-18 client](https://symfony.com/doc/current/http_client.html#psr-18-and-psr-17). + #### Reference You can run the following command to get the default configuration reference: diff --git a/UPGRADE.md b/UPGRADE.md index b2a4921..6a2248c 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -2,7 +2,8 @@ ## From v1.9.0 to v2.0.0 -HttpClientTransport has been removed: +HttpClientTransport has been removed, you must replace it with [a PSR-18 client](https://symfony.com/doc/current/http_client.html#psr-18-and-psr-17): + ```diff JoliCode\Elastically\Client: arguments: @@ -14,6 +15,29 @@ HttpClientTransport has been removed: + client: '@my_custom_psr18_client' # An instance of Symfony\Component\HttpClient\Psr18Client (Or any PSR 18 compliant one) ``` +Code has been cleaned of deprecations: + +- Removed `\JoliCode\Elastically\Index::getBuilder` method, use `\JoliCode\Elastically\Factory::buildIndexBuilder` if needed +- Removed all const in `\JoliCode\Elastically\Client`, use the one in `\JoliCode\Elastically\Factory` instead: + - `\JoliCode\Elastically\Client::CONFIG_MAPPINGS_DIRECTORY` => `\JoliCode\Elastically\Factory::CONFIG_MAPPINGS_DIRECTORY` + - `\JoliCode\Elastically\Client::CONFIG_SERIALIZER_CONTEXT_PER_CLASS` => `\JoliCode\Elastically\Factory::CONFIG_SERIALIZER_CONTEXT_PER_CLASS` + - `\JoliCode\Elastically\Client::CONFIG_SERIALIZER` => `\JoliCode\Elastically\Factory::CONFIG_SERIALIZER` + - `\JoliCode\Elastically\Client::CONFIG_BULK_SIZE` => `\JoliCode\Elastically\Factory::CONFIG_BULK_SIZE` + - `\JoliCode\Elastically\Client::CONFIG_INDEX_PREFIX` => `\JoliCode\Elastically\Factory::CONFIG_INDEX_PREFIX` + - `\JoliCode\Elastically\Client::CONFIG_INDEX_CLASS_MAPPING` => `\JoliCode\Elastically\Factory::CONFIG_INDEX_CLASS_MAPPING` +- `\JoliCode\Elastically\Client::__construct` now requires ResultSetBuilder and IndexNameMapper, use dependency injection +- Removed `\JoliCode\Elastically\Client::getPrefixedIndex`, use `\JoliCode\Elastically\IndexNameMapper::getPrefixedIndex` +- Removed `\JoliCode\Elastically\Client::getIndexNameFromClass`, use `\JoliCode\Elastically\IndexNameMapper::getIndexNameFromClass` +- Removed `\JoliCode\Elastically\Client::getClassFromIndexName`, use `\JoliCode\Elastically\IndexNameMapper::getClassFromIndexName` +- Removed `\JoliCode\Elastically\Client::getPureIndexName`, use `\JoliCode\Elastically\IndexNameMapper::getPureIndexName` +- Removed `\JoliCode\Elastically\Client::getIndexBuilder`, use the Factory (`\JoliCode\Elastically\Factory`) or DIC +- Removed `\JoliCode\Elastically\Client::getIndexer`, use the Factory (`\JoliCode\Elastically\Factory`) or DIC +- Removed `\JoliCode\Elastically\Client::getBuilder`, use the Factory (`\JoliCode\Elastically\Factory`) or DIC +- Removed `\JoliCode\Elastically\Client::getSerializer`, use the Factory (`\JoliCode\Elastically\Factory`) or DIC +- Removed `\JoliCode\Elastically\Client::getDenormalizer`, use the Factory (`\JoliCode\Elastically\Factory`) or DIC +- Removed `\JoliCode\Elastically\Client::getSerializerContext`, use the Factory (`\JoliCode\Elastically\Factory`) or DIC +- Using `\Elastica\Document::setData` to store your DTO will not work anymore, you must use `\JoliCode\Elastically\Model\Document` instead +- ## From v1.3.0 to v1.4.0 If you're using Symfony, here are the changes to apply: diff --git a/composer.json b/composer.json index 2a90a4f..74ccdc7 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "symfony/deprecation-contracts": "^2.4 || ^3.0", "symfony/property-access": "^5.4 || ^6.0 || ^7.0", "symfony/property-info": "^5.4 || ^6.0 || ^7.0", - "symfony/psr-http-message-bridge": "^7.1", + "symfony/psr-http-message-bridge": "^2.3 || ^6.0 || ^7.0", "symfony/serializer": "^5.4 || ^6.0 || ^7.0", "symfony/yaml": "^5.4 || ^6.0 || ^7.0" }, @@ -32,7 +32,7 @@ "jane-php/json-schema": "^7.4", "jane-php/json-schema-runtime": "^7.4", "phpstan/phpstan": "^1.9", - "symfony/browser-kit": "^5.4 || ^6.0", + "symfony/browser-kit": "^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/http-foundation": "^5.4 || ^6.0 || ^7.0", diff --git a/src/Client.php b/src/Client.php index a1dd4f5..a267350 100644 --- a/src/Client.php +++ b/src/Client.php @@ -12,45 +12,30 @@ namespace JoliCode\Elastically; use Elastica\Client as ElasticaClient; -use Elastica\Exception\ExceptionInterface; use Psr\Log\LoggerInterface; -use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; -use Symfony\Component\Serializer\SerializerInterface; class Client extends ElasticaClient { - // Elastically config keys // BC Layer, to remove in 2.0 - public const CONFIG_MAPPINGS_DIRECTORY = Factory::CONFIG_MAPPINGS_DIRECTORY; - public const CONFIG_SERIALIZER_CONTEXT_PER_CLASS = Factory::CONFIG_SERIALIZER_CONTEXT_PER_CLASS; - public const CONFIG_SERIALIZER = Factory::CONFIG_SERIALIZER; - public const CONFIG_BULK_SIZE = Factory::CONFIG_BULK_SIZE; - public const CONFIG_INDEX_PREFIX = Factory::CONFIG_INDEX_PREFIX; - public const CONFIG_INDEX_CLASS_MAPPING = Factory::CONFIG_INDEX_CLASS_MAPPING; - - private Factory $factory; private ResultSetBuilder $resultSetBuilder; private IndexNameMapper $indexNameMapper; + /** + * @see \JoliCode\Elastically\Factory::buildClient + */ public function __construct($config = [], ?LoggerInterface $logger = null, ?ResultSetBuilder $resultSetBuilder = null, ?IndexNameMapper $indexNameMapper = null) { parent::__construct($config, $logger); - // BC Layer, to remove in 2.0 - $this->factory = new Factory($config); - $this->factory->setClient($this); - if (!$resultSetBuilder) { - trigger_deprecation('jolicode/elastically', '1.4.0', 'Passing null as #4 argument of %s() is deprecated. Inject a %s instance instead.', __METHOD__, ResultSetBuilder::class); - } - $this->resultSetBuilder = $resultSetBuilder ?? $this->factory->buildBuilder(); - if (!$indexNameMapper) { - trigger_deprecation('jolicode/elastically', '1.4.0', 'Passing null as #5 argument of %s() is deprecated. Inject a %s instance instead.', __METHOD__, IndexNameMapper::class); + if (!$resultSetBuilder || !$indexNameMapper) { + throw new \InvalidArgumentException('Missing argument "resultSetBuilder" and "indexNameMapper", use `\JoliCode\Elastically\Factory::buildClient` to create this Client.'); } - $this->indexNameMapper = $indexNameMapper ?? $this->factory->buildIndexNameMapper(); - // End of BC Layer + + $this->resultSetBuilder = $resultSetBuilder; + $this->indexNameMapper = $indexNameMapper; } /** - * Return an elastically index. + * Return an Elastically index. * * @return Index */ @@ -60,80 +45,4 @@ public function getIndex(string $name): \Elastica\Index return new Index($this, $name, $this->resultSetBuilder); } - - public function getPrefixedIndex(string $name): string - { - trigger_deprecation('jolicode/elastically', '1.4.0', 'Method %s() is deprecated. Use %s::%s() instead.', __METHOD__, IndexNameMapper::class, __FUNCTION__); - - return $this->indexNameMapper->getPrefixedIndex($name); - } - - /** - * @throws ExceptionInterface - */ - public function getIndexNameFromClass(string $className): string - { - trigger_deprecation('jolicode/elastically', '1.4.0', 'Method %s() is deprecated. Use %s::%s() instead.', __METHOD__, IndexNameMapper::class, __FUNCTION__); - - return $this->indexNameMapper->getIndexNameFromClass($className); - } - - /** - * @throws ExceptionInterface - */ - public function getClassFromIndexName(string $indexName): string - { - trigger_deprecation('jolicode/elastically', '1.4.0', 'Method %s() is deprecated. Use %s::%s() instead.', __METHOD__, IndexNameMapper::class, __FUNCTION__); - - return $this->indexNameMapper->getClassFromIndexName($indexName); - } - - public function getPureIndexName(string $fullIndexName): string - { - trigger_deprecation('jolicode/elastically', '1.4.0', 'Method %s() is deprecated. Use %s::%s() instead.', __METHOD__, IndexNameMapper::class, __FUNCTION__); - - return $this->indexNameMapper->getPureIndexName($fullIndexName); - } - - public function getIndexBuilder(): IndexBuilder - { - trigger_deprecation('jolicode/elastically', '1.4.0', 'Method %s() is deprecated. Inject a IndexBuilder instance in your code directly using dependency injection or call the %s.', __METHOD__, Factory::class); - - return $this->factory->buildIndexBuilder(); - } - - public function getIndexer(): Indexer - { - trigger_deprecation('jolicode/elastically', '1.4.0', 'Method %s() is deprecated. Inject a Indexer instance in your code directly using dependency injection or call the %s.', __METHOD__, Factory::class); - - return $this->factory->buildIndexer(); - } - - public function getBuilder(): ResultSetBuilder - { - trigger_deprecation('jolicode/elastically', '1.4.0', 'Method %s() is deprecated. Inject a ResultSetBuilder instance in your code directly using dependency injection or call the %s.', __METHOD__, Factory::class); - - return $this->factory->buildBuilder(); - } - - public function getSerializer(): SerializerInterface - { - trigger_deprecation('jolicode/elastically', '1.4.0', 'Method %s() is deprecated. Inject a SerializerInterface instance in your code directly using dependency injection or call the %s.', __METHOD__, Factory::class); - - return $this->factory->buildSerializer(); - } - - public function getDenormalizer(): DenormalizerInterface - { - trigger_deprecation('jolicode/elastically', '1.4.0', 'Method %s() is deprecated. Inject a DenormalizerInterface instance in your code directly using dependency injection or call the %s.', __METHOD__, Factory::class); - - return $this->factory->buildDenormalizer(); - } - - public function getSerializerContext(string $class): array - { - trigger_deprecation('jolicode/elastically', '1.4.0', 'Method %s() is deprecated. Inject a ContextBuilderInterface instance in your code directly using dependency injection or call the %s.', __METHOD__, Factory::class); - - return $this->factory->buildSerializerContext($class); - } } diff --git a/src/Index.php b/src/Index.php index 256760f..e8f6e15 100644 --- a/src/Index.php +++ b/src/Index.php @@ -11,6 +11,10 @@ namespace JoliCode\Elastically; +use Elastic\Elasticsearch\Exception\ClientResponseException; +use Elastic\Elasticsearch\Exception\MissingParameterException; +use Elastic\Elasticsearch\Exception\ServerResponseException; +use Elastic\Transport\Exception\NoNodeAvailableException; use Elastica\Exception\ExceptionInterface; use Elastica\Index as ElasticaIndex; use Elastica\ResultSet\BuilderInterface; @@ -29,10 +33,14 @@ public function __construct(Client $client, string $name, ResultSetBuilder $resu } /** + * @throws ClientResponseException * @throws ExceptionInterface + * @throws MissingParameterException * @throws SerializerExceptionInterface + * @throws ServerResponseException + * @throws NoNodeAvailableException */ - public function getModel($id) + public function getModel($id): mixed { $document = $this->getDocument($id); @@ -44,13 +52,6 @@ public function createSearch($query = '', $options = null, ?BuilderInterface $bu return parent::createSearch($query, $options, $builder ?? $this->resultSetBuilder); } - public function getBuilder(): ResultSetBuilder - { - trigger_deprecation('jolicode/elastically', '1.3.0', 'Method %s() is deprecated. Use %s::getBuilder() instead', __METHOD__, Client::class); - - return $this->resultSetBuilder; - } - public function getClient(): Client { return parent::getClient(); diff --git a/src/IndexBuilder.php b/src/IndexBuilder.php index 54aa2b2..0204bea 100644 --- a/src/IndexBuilder.php +++ b/src/IndexBuilder.php @@ -11,6 +11,11 @@ namespace JoliCode\Elastically; +use Elastic\Elasticsearch\Exception\ClientResponseException; +use Elastic\Elasticsearch\Exception\MissingParameterException; +use Elastic\Elasticsearch\Exception\ServerResponseException; +use Elastic\Transport\Exception\NoNodeAvailableException; +use Elastica\Exception\ClientException; use Elastica\Exception\ExceptionInterface; use Elastica\Exception\RuntimeException; use Elastica\Reindex; @@ -33,6 +38,10 @@ public function __construct(MappingProviderInterface $mappingProvider, Client $c /** * @throws ExceptionInterface + * @throws ClientResponseException + * @throws ServerResponseException + * @throws MissingParameterException + * @throws NoNodeAvailableException */ public function createIndex(string $indexName, array $context = []): Index { @@ -51,7 +60,9 @@ public function createIndex(string $indexName, array $context = []): Index } /** - * @throws ExceptionInterface + * @throws ClientResponseException + * @throws ServerResponseException + * @throws NoNodeAvailableException */ public function markAsLive(Index $index, string $indexName): Response { @@ -68,7 +79,10 @@ public function markAsLive(Index $index, string $indexName): Response } /** - * @throws ExceptionInterface + * @throws ClientResponseException + * @throws ClientException + * @throws ServerResponseException + * @throws NoNodeAvailableException */ public function slowDownRefresh(Index $index): void { @@ -76,7 +90,10 @@ public function slowDownRefresh(Index $index): void } /** - * @throws ExceptionInterface + * @throws ClientResponseException + * @throws ClientException + * @throws ServerResponseException + * @throws NoNodeAvailableException */ public function speedUpRefresh(Index $index): void { @@ -85,6 +102,10 @@ public function speedUpRefresh(Index $index): void /** * @throws ExceptionInterface + * @throws ClientResponseException + * @throws ServerResponseException + * @throws MissingParameterException + * @throws NoNodeAvailableException */ public function migrate(Index $currentIndex, array $params = [], array $context = []): Index { @@ -113,7 +134,11 @@ public function migrate(Index $currentIndex, array $params = [], array $context } /** - * @throws ExceptionInterface + * @throws ClientResponseException + * @throws ClientException + * @throws ServerResponseException + * @throws MissingParameterException + * @throws NoNodeAvailableException */ public function purgeOldIndices(string $indexName, bool $dryRun = false): array { @@ -133,7 +158,7 @@ public function purgeOldIndices(string $indexName, bool $dryRun = false): array continue; } - // Check suffix (it must contains a valid date) + // Check suffix (it must contain a valid date) $indexSuffixName = substr($realIndexName, \strlen($indexName) + 1); $date = \DateTime::createFromFormat('Y-m-d-His', $indexSuffixName); if (!$date) { @@ -143,7 +168,7 @@ public function purgeOldIndices(string $indexName, bool $dryRun = false): array } $data['date'] = $date; - $data['is_live'] = false !== array_search($indexName, $data['aliases'], true); + $data['is_live'] = \in_array($indexName, $data['aliases'], true); } // Newest first diff --git a/src/Indexer.php b/src/Indexer.php index 504c644..7bfbf23 100644 --- a/src/Indexer.php +++ b/src/Indexer.php @@ -11,9 +11,14 @@ namespace JoliCode\Elastically; +use Elastic\Elasticsearch\Exception\ClientResponseException; +use Elastic\Elasticsearch\Exception\MissingParameterException; +use Elastic\Elasticsearch\Exception\ServerResponseException; +use Elastic\Transport\Exception\NoNodeAvailableException; use Elastica\Bulk; use Elastica\Document as ElasticaDocument; -use Elastica\Exception\ExceptionInterface; +use Elastica\Exception\Bulk\ResponseException; +use Elastica\Exception\ClientException; use Elastica\Index; use JoliCode\Elastically\Model\Document; use JoliCode\Elastically\Serializer\ContextBuilderInterface; @@ -42,9 +47,14 @@ public function __construct(Client $client, SerializerInterface $serializer, int } /** - * @throws ExceptionInterface + * @throws ClientResponseException + * @throws ServerResponseException + * @throws MissingParameterException + * @throws NoNodeAvailableException + * @throws ResponseException + * @throws ClientException */ - public function scheduleIndex($index, ElasticaDocument $document) + public function scheduleIndex($index, ElasticaDocument $document): void { $document->setIndex($index instanceof Index ? $index->getName() : $index); $this->updateDocumentData($document); @@ -55,9 +65,14 @@ public function scheduleIndex($index, ElasticaDocument $document) } /** - * @throws ExceptionInterface + * @throws ClientResponseException + * @throws ServerResponseException + * @throws MissingParameterException + * @throws NoNodeAvailableException + * @throws ResponseException + * @throws ClientException */ - public function scheduleDelete($index, string $id) + public function scheduleDelete($index, string $id): void { $document = new Document($id); $document->setIndex($index instanceof Index ? $index->getName() : $index); @@ -67,9 +82,14 @@ public function scheduleDelete($index, string $id) } /** - * @throws ExceptionInterface + * @throws ClientResponseException + * @throws ServerResponseException + * @throws MissingParameterException + * @throws NoNodeAvailableException + * @throws ResponseException + * @throws ClientException */ - public function scheduleUpdate($index, ElasticaDocument $document) + public function scheduleUpdate($index, ElasticaDocument $document): void { $document->setIndex($index instanceof Index ? $index->getName() : $index); $this->updateDocumentData($document); @@ -80,9 +100,14 @@ public function scheduleUpdate($index, ElasticaDocument $document) } /** - * @throws ExceptionInterface + * @throws ClientResponseException + * @throws ServerResponseException + * @throws MissingParameterException + * @throws NoNodeAvailableException + * @throws ResponseException + * @throws ClientException */ - public function scheduleCreate($index, ElasticaDocument $document) + public function scheduleCreate($index, ElasticaDocument $document): void { $document->setIndex($index instanceof Index ? $index->getName() : $index); $this->updateDocumentData($document); @@ -93,7 +118,12 @@ public function scheduleCreate($index, ElasticaDocument $document) } /** - * @throws ExceptionInterface + * @throws ClientException + * @throws ResponseException + * @throws ServerResponseException + * @throws ClientResponseException + * @throws MissingParameterException + * @throws NoNodeAvailableException */ public function flush(): ?Bulk\ResponseSet { @@ -114,7 +144,7 @@ public function flush(): ?Bulk\ResponseSet return $response; } - public function getQueueSize() + public function getQueueSize(): int { if (!$this->currentBulk) { return 0; @@ -124,9 +154,13 @@ public function getQueueSize() } /** - * @throws ExceptionInterface + * @throws ClientException + * @throws ClientResponseException + * @throws MissingParameterException + * @throws ServerResponseException + * @throws NoNodeAvailableException */ - public function refresh($index) + public function refresh(Index|string $index): void { $indexName = $index instanceof Index ? $index->getName() : $index; @@ -134,7 +168,12 @@ public function refresh($index) } /** - * @throws ExceptionInterface + * @throws ClientException + * @throws ClientResponseException + * @throws MissingParameterException + * @throws ServerResponseException + * @throws NoNodeAvailableException + * @throws ResponseException */ public function setBulkMaxSize(int $bulkMaxSize): void { @@ -156,11 +195,6 @@ public function setBulkRequestParams(array $bulkRequestParams): void $this->refreshBulkRequestParams(); } - public function getClient(): Client - { - return $this->client; - } - protected function getCurrentBulk(): Bulk { if (!$this->currentBulk) { @@ -172,7 +206,12 @@ protected function getCurrentBulk(): Bulk } /** - * @throws ExceptionInterface + * @throws ClientResponseException + * @throws ClientException + * @throws ResponseException + * @throws ServerResponseException + * @throws MissingParameterException + * @throws NoNodeAvailableException */ protected function flushIfNeeded(): void { @@ -181,7 +220,7 @@ protected function flushIfNeeded(): void } } - private function refreshBulkRequestParams() + private function refreshBulkRequestParams(): void { if (!$this->currentBulk) { return; @@ -198,16 +237,6 @@ private function updateDocumentData(ElasticaDocument $document): void $context = $this->contextBuilder->buildContext(\get_class($document->getModel())); $data = $this->serializer->serialize($document->getModel(), 'json', $context); $document->setData($data); - - return; - } - - // This check is added for BC-compatibility with older version - // But a deprecation could be added and this could be removed in 2.x versions (?) - if (\is_object($document->getData())) { // @phpstan-ignore-line - $context = $this->contextBuilder->buildContext(\get_class($document->getData())); // @phpstan-ignore-line - $data = $this->serializer->serialize($document->getData(), 'json', $context); - $document->setData($data); } } } diff --git a/src/Messenger/IndexationRequestHandler.php b/src/Messenger/IndexationRequestHandler.php index 6656bb2..9f88c98 100644 --- a/src/Messenger/IndexationRequestHandler.php +++ b/src/Messenger/IndexationRequestHandler.php @@ -11,10 +11,13 @@ namespace JoliCode\Elastically\Messenger; +use Elastic\Elasticsearch\Exception\ClientResponseException; +use Elastic\Elasticsearch\Exception\MissingParameterException; +use Elastic\Elasticsearch\Exception\ServerResponseException; +use Elastic\Transport\Exception\NoNodeAvailableException; use Elastica\Exception\Bulk\ResponseException; use Elastica\Exception\ExceptionInterface; use Elastica\Exception\RuntimeException; -use JoliCode\Elastically\Client; use JoliCode\Elastically\Indexer; use JoliCode\Elastically\IndexNameMapper; use Symfony\Component\Messenger\Attribute\AsMessageHandler; @@ -36,15 +39,13 @@ class IndexationRequestHandler self::OP_CREATE, ]; - private Client $client; private MessageBusInterface $bus; private DocumentExchangerInterface $exchanger; private Indexer $indexer; private IndexNameMapper $indexNameMapper; - public function __construct(Client $client, MessageBusInterface $bus, DocumentExchangerInterface $exchanger, Indexer $indexer, IndexNameMapper $indexNameMapper) + public function __construct(MessageBusInterface $bus, DocumentExchangerInterface $exchanger, Indexer $indexer, IndexNameMapper $indexNameMapper) { - $this->client = $client; $this->bus = $bus; $this->exchanger = $exchanger; $this->indexer = $indexer; @@ -53,7 +54,10 @@ public function __construct(Client $client, MessageBusInterface $bus, DocumentEx /** * @throws ExceptionInterface - * @throws UnrecoverableMessageHandlingException + * @throws ClientResponseException + * @throws MissingParameterException + * @throws ServerResponseException + * @throws NoNodeAvailableException * @throws \Symfony\Component\Messenger\Exception\ExceptionInterface */ public function __invoke(IndexationRequestInterface $message): void @@ -110,10 +114,14 @@ public function __invoke(IndexationRequestInterface $message): void } /** - * @throws UnrecoverableMessageHandlingException + * @throws ClientResponseException * @throws ExceptionInterface + * @throws MissingParameterException + * @throws ServerResponseException + * @throws NoNodeAvailableException + * @throws UnrecoverableMessageHandlingException */ - private function schedule(Indexer $indexer, IndexationRequest $indexationRequest) + private function schedule(Indexer $indexer, IndexationRequest $indexationRequest): void { try { $indexName = $this->indexNameMapper->getIndexNameFromClass($indexationRequest->getClassName()); diff --git a/tests/BaseTestCase.php b/tests/BaseTestCase.php index b6d12c5..80f4fa9 100644 --- a/tests/BaseTestCase.php +++ b/tests/BaseTestCase.php @@ -14,7 +14,7 @@ namespace JoliCode\Elastically\Tests; use Elastica\Request; -use Http\Discovery\Psr17Factory; +use Http\Discovery\Psr17FactoryDiscovery; use JoliCode\Elastically\Client; use JoliCode\Elastically\Factory; use PHPUnit\Framework\TestCase; @@ -23,7 +23,9 @@ abstract class BaseTestCase extends TestCase { protected function setUp(): void { - $this->getClient()->sendRequest((new Psr17Factory())->createRequest(Request::DELETE, '*')); + $requestFactory = Psr17FactoryDiscovery::findRequestFactory(); + + $this->getClient()->sendRequest($requestFactory->createRequest(Request::DELETE, '*')); } protected function getFactory(?string $path = null, array $config = []): Factory diff --git a/tests/Bridge/Symfony/DependencyInjection/ElasticallyExtensionTest.php b/tests/Bridge/Symfony/DependencyInjection/ElasticallyExtensionTest.php index cde737c..437600b 100644 --- a/tests/Bridge/Symfony/DependencyInjection/ElasticallyExtensionTest.php +++ b/tests/Bridge/Symfony/DependencyInjection/ElasticallyExtensionTest.php @@ -16,7 +16,6 @@ use JoliCode\Elastically\Client; use JoliCode\Elastically\IndexBuilder; use JoliCode\Elastically\Indexer; -use JoliCode\Elastically\Transport\HttpClientTransport; use PHPUnit\Framework\TestCase; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -212,7 +211,7 @@ public function testWithTransport(): void 'default' => [ 'client' => [ 'transport_config' => [ - 'http_client' => '@psr_es_client' + 'http_client' => '@psr_es_client', ], ], 'mapping_directory' => __DIR__, diff --git a/tests/IndexerTest.php b/tests/IndexerTest.php index ee96917..feea13b 100644 --- a/tests/IndexerTest.php +++ b/tests/IndexerTest.php @@ -151,7 +151,10 @@ public function testRequestParameters(): void $dto->bar = 'I like unicorns.'; $dto->foo = 'Why is the sky blue?'; - $indexer = $this->getIndexer(); + $factory = $this->getFactory(); + $client = $factory->buildClient(); + $indexer = $factory->buildIndexer(); + $indexer->setBulkRequestParams([ 'refresh' => 'wait_for', ]); @@ -160,7 +163,8 @@ public function testRequestParameters(): void $response = $indexer->flush(); $this->assertInstanceOf(ResponseSet::class, $response); - $query = $indexer->getClient()->getLastRequest()->getUri()->getQuery(); + + $query = $client->getLastRequest()->getUri()->getQuery(); $this->assertStringContainsString('refresh=wait_for', $query); // Test the same with an invalid pipeline diff --git a/tests/Messenger/IndexationRequestHandlerTest.php b/tests/Messenger/IndexationRequestHandlerTest.php index 8726285..812c096 100644 --- a/tests/Messenger/IndexationRequestHandlerTest.php +++ b/tests/Messenger/IndexationRequestHandlerTest.php @@ -43,7 +43,7 @@ public function testDocumentAreIndexed(): void $indexer = $factory->buildIndexer(); $indexNameMapper = $factory->buildIndexNameMapper(); - $handler = new IndexationRequestHandler($client, new MessageBus(), new TestDocumentExchanger(), $indexer, $indexNameMapper); + $handler = new IndexationRequestHandler(new MessageBus(), new TestDocumentExchanger(), $indexer, $indexNameMapper); $handler(new IndexationRequest(TestDTO::class, '1234567890')); $handler(new IndexationRequest(TestDTO::class, '1234567890', IndexationRequestHandler::OP_UPDATE)); $handler(new IndexationRequest(TestDTO::class, 'ref7777', IndexationRequestHandler::OP_CREATE)); @@ -109,7 +109,7 @@ public function testRequeueOnlyFailedMessageFromMultiple(): void $traceableBus = new TraceableMessageBus(new MessageBus()); - $handler = new IndexationRequestHandler($client, $traceableBus, new FooBarDocumentExchanger(), $indexer, $indexNameMapper); + $handler = new IndexationRequestHandler($traceableBus, new FooBarDocumentExchanger(), $indexer, $indexNameMapper); $goodRequest = new IndexationRequest(FooDTO::class, '1234567892'); $badRequest = new IndexationRequest(BarDTO::class, '1234567892'); @@ -142,7 +142,7 @@ public function testThrowsResponseExceptionIfAllRequestsFailInMulti(): void $traceableBus = new TraceableMessageBus(new MessageBus()); - $handler = new IndexationRequestHandler($client, $traceableBus, new FooBarDocumentExchanger(), $indexer, $indexNameMapper); + $handler = new IndexationRequestHandler($traceableBus, new FooBarDocumentExchanger(), $indexer, $indexNameMapper); $badRequest1 = new IndexationRequest(BarDTO::class, '1234567892'); $badRequest2 = new IndexationRequest(BarDTO::class, '1234567892'); @@ -172,7 +172,7 @@ public function testThrowsResponseExceptionIfSingleRequestFail(): void $traceableBus = new TraceableMessageBus(new MessageBus()); - $handler = new IndexationRequestHandler($client, $traceableBus, new FooBarDocumentExchanger(), $indexer, $indexNameMapper); + $handler = new IndexationRequestHandler($traceableBus, new FooBarDocumentExchanger(), $indexer, $indexNameMapper); $badRequest = new IndexationRequest(BarDTO::class, '1234567892'); @@ -207,7 +207,7 @@ public function testMultipleBulkResilienceOverError(): void $traceableBus = new TraceableMessageBus(new MessageBus()); - $handler = new IndexationRequestHandler($client, $traceableBus, new FooBarDocumentExchanger(), $indexer, $indexNameMapper); + $handler = new IndexationRequestHandler($traceableBus, new FooBarDocumentExchanger(), $indexer, $indexNameMapper); // bulk 1 $request1 = new IndexationRequest(FooDTO::class, 'bulk-1-message-1');