diff --git a/CHANGELOG.md b/CHANGELOG.md index 721122a..4dec7cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p # Release Notes -## [Unreleased](https://github.com/algolia/search-bundle/compare/8.0.0...master) - ## [v8.0.0](https://github.com/algolia/search-bundle/compare/7.0.0...8.0.0) ### Added diff --git a/composer.json b/composer.json index 4281f46..cf8e3ee 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "prefer-stable": true, "require": { "php": ">= 8.2", - "algolia/algoliasearch-client-php": "^3.0", + "algolia/algoliasearch-client-php": "^4.41.0", "doctrine/event-manager": "^1.1 || ^2.0", "doctrine/persistence": "^2.1 || ^3.0 || ^4.0", "symfony/filesystem": "^7.0 || ^8.0", diff --git a/src/AlgoliaSearchBundle.php b/src/AlgoliaSearchBundle.php index 56a9485..21f5253 100644 --- a/src/AlgoliaSearchBundle.php +++ b/src/AlgoliaSearchBundle.php @@ -2,7 +2,7 @@ namespace Algolia\SearchBundle; -use Algolia\AlgoliaSearch\Support\UserAgent; +use Algolia\AlgoliaSearch\Support\AlgoliaAgent; use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\HttpKernel\Kernel as SfKernel; @@ -17,7 +17,7 @@ public function boot(): void { parent::boot(); - UserAgent::addCustomUserAgent('Symfony Search Bundle', self::VERSION); - UserAgent::addCustomUserAgent('Symfony', SfKernel::VERSION); + AlgoliaAgent::addAlgoliaAgent('Search', 'Symfony Search Bundle', self::VERSION); + AlgoliaAgent::addAlgoliaAgent('Search', 'Symfony', SfKernel::VERSION); } } diff --git a/src/Command/SearchClearCommand.php b/src/Command/SearchClearCommand.php index cd006ce..ab8b859 100644 --- a/src/Command/SearchClearCommand.php +++ b/src/Command/SearchClearCommand.php @@ -2,7 +2,7 @@ namespace Algolia\SearchBundle\Command; -use Algolia\AlgoliaSearch\Response\IndexingResponse; +use Algolia\SearchBundle\Responses\NullResponse; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -34,7 +34,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int foreach ($indexToClear as $indexName => $className) { $success = $this->searchService->clear($className); - if ($success instanceof IndexingResponse) { + if (!$success instanceof NullResponse) { $output->writeln('Cleared ' . $indexName . ' index of ' . $className . ' '); } else { $output->writeln('Index ' . $indexName . ' couldn\'t be cleared'); diff --git a/src/Command/SearchImportCommand.php b/src/Command/SearchImportCommand.php index 8139113..d2a6f67 100644 --- a/src/Command/SearchImportCommand.php +++ b/src/Command/SearchImportCommand.php @@ -2,7 +2,7 @@ namespace Algolia\SearchBundle\Command; -use Algolia\AlgoliaSearch\SearchClient; +use Algolia\AlgoliaSearch\Api\SearchClient; use Algolia\SearchBundle\Entity\Aggregator; use Algolia\SearchBundle\SearchService; use Doctrine\Persistence\ManagerRegistry; @@ -81,7 +81,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($shouldDoAtomicReindex) { $temporaryIndexName = $this->searchServiceForAtomicReindex->searchableAs($entityClassName); $output->writeln("Creating temporary index $temporaryIndexName"); - $this->searchClient->copyIndex($sourceIndexName, $temporaryIndexName, ['scope' => ['settings', 'synonyms', 'rules']]); + $copyResponse = $this->searchClient->operationIndex($sourceIndexName, [ + 'operation' => 'copy', + 'destination' => $temporaryIndexName, + 'scope' => ['settings', 'synonyms', 'rules'], + ]); + $this->searchClient->waitForTask($sourceIndexName, $copyResponse['taskID']); } $allResponses = []; @@ -119,13 +124,16 @@ protected function execute(InputInterface $input, OutputInterface $output): int $manager->clear(); } - if ($shouldDoAtomicReindex && isset($indexName)) { + if ($shouldDoAtomicReindex) { $output->writeln("Waiting for indexing tasks to finalize\n"); foreach ($allResponses as $response) { $response->wait(); } - $output->writeln("Moving $indexName -> $sourceIndexName\n"); - $this->searchClient->moveIndex($indexName, $sourceIndexName); + $output->writeln("Moving $temporaryIndexName -> $sourceIndexName\n"); + $this->searchClient->operationIndex($temporaryIndexName, [ + 'operation' => 'move', + 'destination' => $sourceIndexName, + ]); } } @@ -149,7 +157,9 @@ private function formatIndexingResponse($batch) $formattedResponse[$indexName] = 0; } - $formattedResponse[$indexName] += count($apiResponse->current()['objectIDs']); + foreach ($apiResponse as $batchResponse) { + $formattedResponse[$indexName] += count($batchResponse['objectIDs']); + } } } diff --git a/src/Engine.php b/src/Engine.php index 643c9b6..30ff5a0 100644 --- a/src/Engine.php +++ b/src/Engine.php @@ -2,10 +2,10 @@ namespace Algolia\SearchBundle; +use Algolia\AlgoliaSearch\Api\SearchClient; use Algolia\AlgoliaSearch\RequestOptions\RequestOptions; -use Algolia\AlgoliaSearch\Response\BatchIndexingResponse; -use Algolia\AlgoliaSearch\Response\NullResponse; -use Algolia\AlgoliaSearch\SearchClient; +use Algolia\SearchBundle\Responses\EngineResponse; +use Algolia\SearchBundle\Responses\NullResponse; /** * @internal @@ -20,6 +20,14 @@ public function __construct(SearchClient $client) $this->client = $client; } + /** + * @return SearchClient + */ + public function getClient() + { + return $this->client; + } + /** * Add new objects to an index. * @@ -29,7 +37,7 @@ public function __construct(SearchClient $client) * @param array $searchableEntities * @param array|RequestOptions $requestOptions * - * @return array + * @return array * * @throws \Algolia\AlgoliaSearch\Exceptions\AlgoliaException */ @@ -59,13 +67,8 @@ public function index($searchableEntities, $requestOptions) } $result = []; - if (!array_key_exists('autoGenerateObjectIDIfNotExist', $requestOptions)) { - $requestOptions['autoGenerateObjectIDIfNotExist'] = true; - } foreach ($data as $indexName => $objects) { - $result[$indexName] = $this->client - ->initIndex($indexName) - ->saveObjects($objects, $requestOptions); + $result[$indexName] = $this->client->saveObjects($indexName, $objects, false, 1000, $requestOptions); } return $result; @@ -79,7 +82,7 @@ public function index($searchableEntities, $requestOptions) * @param array $searchableEntities * @param array|RequestOptions $requestOptions * - * @return array + * @return array * * @throws \Algolia\AlgoliaSearch\Exceptions\AlgoliaException */ @@ -106,9 +109,7 @@ public function remove($searchableEntities, $requestOptions) $result = []; foreach ($data as $indexName => $objects) { - $result[$indexName] = $this->client - ->initIndex($indexName) - ->deleteObjects($objects, $requestOptions); + $result[$indexName] = $this->client->deleteObjects($indexName, $objects, false, 1000, $requestOptions); } return $result; @@ -117,7 +118,7 @@ public function remove($searchableEntities, $requestOptions) /** * Clear the records of an index without affecting its settings. * - * This method enables you to delete an index’s contents (records) without + * This method enables you to delete an index's contents (records) without * removing any settings, rules and synonyms. * * If you want to remove the entire index and not just its records, use the @@ -125,15 +126,13 @@ public function remove($searchableEntities, $requestOptions) * * @param string $indexName * @param array|RequestOptions $requestOptions - * - * @return \Algolia\AlgoliaSearch\Response\AbstractResponse */ public function clear($indexName, $requestOptions) { - $index = $this->client->initIndex($indexName); + if ($this->client->indexExists($indexName)) { + $response = $this->client->clearObjects($indexName, $requestOptions); - if ($index->exists($requestOptions)) { - return $index->clearObjects($requestOptions); + return new EngineResponse($this->client, $indexName, $response['taskID']); } return new NullResponse(); @@ -146,19 +145,17 @@ public function clear($indexName, $requestOptions) * removes its metadata and configured settings (like searchable attributes or custom ranking). * * If the index has replicas, they will be preserved but will no longer be - * linked to their primary index. Instead, they’ll become independent indices. + * linked to their primary index. Instead, they'll become independent indices. * * @param string $indexName * @param array|RequestOptions $requestOptions - * - * @return \Algolia\AlgoliaSearch\Response\AbstractResponse */ public function delete($indexName, $requestOptions) { - $index = $this->client->initIndex($indexName); + if ($this->client->indexExists($indexName)) { + $response = $this->client->deleteIndex($indexName, $requestOptions); - if ($index->exists($requestOptions)) { - return $index->delete($requestOptions); + return new EngineResponse($this->client, $indexName, $response['taskID']); } return new NullResponse(); @@ -177,7 +174,27 @@ public function delete($indexName, $requestOptions) */ public function search($query, $indexName, $requestOptions) { - return $this->client->initIndex($indexName)->search($query, $requestOptions); + $searchParams = ['query' => $query]; + $httpOptions = []; + + if ($requestOptions instanceof RequestOptions) { + $searchParams = array_merge($searchParams, $requestOptions->getBody()); + $requestOptions = clone $requestOptions; + $requestOptions->setBody([]); + + return $this->client->searchSingleIndex($indexName, $searchParams, $requestOptions); + } + + $httpOptionKeys = ['headers', 'queryParameters', 'body', 'readTimeout', 'writeTimeout', 'connectTimeout']; + foreach ($requestOptions as $key => $value) { + if (in_array($key, $httpOptionKeys, true)) { + $httpOptions[$key] = $value; + } else { + $searchParams[$key] = $value; + } + } + + return $this->client->searchSingleIndex($indexName, $searchParams, $httpOptions); } /** @@ -195,7 +212,12 @@ public function searchIds($query, $indexName, $requestOptions) { $result = $this->search($query, $indexName, $requestOptions); - return array_column($result['hits'], 'objectID'); + $ids = []; + foreach ($result['hits'] as $hit) { + $ids[] = $hit['objectID']; + } + + return $ids; } /** @@ -211,7 +233,7 @@ public function searchIds($query, $indexName, $requestOptions) */ public function count($query, $indexName, $requestOptions) { - $results = $this->client->initIndex($indexName)->search($query, $requestOptions); + $results = $this->search($query, $indexName, $requestOptions); return (int) $results['nbHits']; } diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index 48dc7f6..9ad4986 100644 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -23,15 +23,15 @@ services: - { name: doctrine_mongodb.odm.event_subscriber } search.client: - class: Algolia\AlgoliaSearch\SearchClient + class: Algolia\AlgoliaSearch\Api\SearchClient public: true lazy: true - factory: ['Algolia\AlgoliaSearch\SearchClient', 'create'] + factory: ['Algolia\AlgoliaSearch\Api\SearchClient', 'create'] arguments: $appId: '%env(ALGOLIA_APP_ID)%' $apiKey: '%env(ALGOLIA_API_KEY)%' - Algolia\AlgoliaSearch\SearchClient: + Algolia\AlgoliaSearch\Api\SearchClient: alias: search.client Algolia\SearchBundle\SearchService: diff --git a/src/Responses/EngineResponse.php b/src/Responses/EngineResponse.php new file mode 100644 index 0000000..e6c2183 --- /dev/null +++ b/src/Responses/EngineResponse.php @@ -0,0 +1,32 @@ +client = $client; + $this->indexName = $indexName; + $this->taskID = $taskID; + } + + public function wait() + { + $this->client->waitForTask($this->indexName, $this->taskID); + } +} diff --git a/src/Responses/NullResponse.php b/src/Responses/NullResponse.php new file mode 100644 index 0000000..e79c601 --- /dev/null +++ b/src/Responses/NullResponse.php @@ -0,0 +1,14 @@ +> $apiResponse + * @param array> $apiResponse */ - public function __construct($apiResponse) + public function __construct(SearchClient $client, $apiResponse) { + $this->client = $client; $this->apiResponse = $apiResponse; } /** - * @param array|mixed $requestOptions - * * @return void */ - public function wait($requestOptions = []) + public function wait() { foreach ($this->apiResponse as $chunk) { - foreach ($chunk as $indexName => $apiResponse) { - /* @var $apiResponse AbstractResponse */ - $apiResponse->wait($requestOptions); + foreach ($chunk as $indexName => $batchResponses) { + foreach ($batchResponses as $batchResponse) { + $this->client->waitForTask($indexName, $batchResponse['taskID']); + } } } } @@ -42,7 +48,7 @@ public function rewind(): void } /** - * @return array + * @return array */ public function current(): array { diff --git a/src/SearchService.php b/src/SearchService.php index 3b3a97e..68dd75b 100644 --- a/src/SearchService.php +++ b/src/SearchService.php @@ -36,32 +36,24 @@ public function searchableAs($className); /** * @param object|array $searchables * @param array|RequestOptions $requestOptions - * - * @return \Algolia\AlgoliaSearch\Response\AbstractResponse */ public function index(ObjectManager $objectManager, $searchables, $requestOptions = []); /** * @param object|array $searchables * @param array|RequestOptions $requestOptions - * - * @return \Algolia\AlgoliaSearch\Response\AbstractResponse */ public function remove(ObjectManager $objectManager, $searchables, $requestOptions = []); /** * @param string $className * @param array|RequestOptions $requestOptions - * - * @return \Algolia\AlgoliaSearch\Response\AbstractResponse */ public function clear($className, $requestOptions = []); /** * @param string $className * @param array|RequestOptions $requestOptions - * - * @return \Algolia\AlgoliaSearch\Response\AbstractResponse */ public function delete($className, $requestOptions = []); diff --git a/src/Services/AlgoliaSearchService.php b/src/Services/AlgoliaSearchService.php index 24405b9..7df35fe 100644 --- a/src/Services/AlgoliaSearchService.php +++ b/src/Services/AlgoliaSearchService.php @@ -122,8 +122,6 @@ public function searchableAs($className) /** * @param object|array $searchables * @param array|RequestOptions $requestOptions - * - * @return \Algolia\AlgoliaSearch\Response\AbstractResponse */ public function index(ObjectManager $objectManager, $searchables, $requestOptions = []) { @@ -154,8 +152,6 @@ public function index(ObjectManager $objectManager, $searchables, $requestOption /** * @param object|array $searchables * @param array|RequestOptions $requestOptions - * - * @return \Algolia\AlgoliaSearch\Response\AbstractResponse */ public function remove(ObjectManager $objectManager, $searchables, $requestOptions = []) { @@ -174,8 +170,6 @@ public function remove(ObjectManager $objectManager, $searchables, $requestOptio /** * @param string $className * @param array|RequestOptions $requestOptions - * - * @return \Algolia\AlgoliaSearch\Response\AbstractResponse */ public function clear($className, $requestOptions = []) { @@ -187,8 +181,6 @@ public function clear($className, $requestOptions = []) /** * @param string $className * @param array|RequestOptions $requestOptions - * - * @return \Algolia\AlgoliaSearch\Response\AbstractResponse */ public function delete($className, $requestOptions = []) { @@ -391,8 +383,6 @@ private function setIndexIfMapping() * * @param array $entities * @param callable $operation - * - * @return \Algolia\AlgoliaSearch\Response\AbstractResponse */ private function makeSearchServiceResponseFrom(ObjectManager $objectManager, array $entities, $operation) { @@ -414,7 +404,7 @@ private function makeSearchServiceResponseFrom(ObjectManager $objectManager, arr $batch[] = $operation($searchableEntitiesChunk); } - return new SearchServiceResponse($batch); + return new SearchServiceResponse($this->engine->getClient(), $batch); } /** diff --git a/src/Services/NullSearchService.php b/src/Services/NullSearchService.php index ecdc117..2cb425c 100644 --- a/src/Services/NullSearchService.php +++ b/src/Services/NullSearchService.php @@ -3,7 +3,7 @@ namespace Algolia\SearchBundle\Services; use Algolia\AlgoliaSearch\RequestOptions\RequestOptions; -use Algolia\AlgoliaSearch\Response\NullResponse; +use Algolia\SearchBundle\Responses\NullResponse; use Algolia\SearchBundle\SearchService; use Doctrine\Persistence\ObjectManager; @@ -54,8 +54,6 @@ public function searchableAs($className) /** * @param object|array $searchables * @param array|RequestOptions $requestOptions - * - * @return \Algolia\AlgoliaSearch\Response\AbstractResponse */ public function index(ObjectManager $objectManager, $searchables, $requestOptions = []) { @@ -65,8 +63,6 @@ public function index(ObjectManager $objectManager, $searchables, $requestOption /** * @param object|array $searchables * @param array|RequestOptions $requestOptions - * - * @return \Algolia\AlgoliaSearch\Response\AbstractResponse */ public function remove(ObjectManager $objectManager, $searchables, $requestOptions = []) { @@ -76,8 +72,6 @@ public function remove(ObjectManager $objectManager, $searchables, $requestOptio /** * @param string $className * @param array|RequestOptions $requestOptions - * - * @return \Algolia\AlgoliaSearch\Response\AbstractResponse */ public function clear($className, $requestOptions = []) { @@ -87,8 +81,6 @@ public function clear($className, $requestOptions = []) /** * @param string $className * @param array|RequestOptions $requestOptions - * - * @return \Algolia\AlgoliaSearch\Response\AbstractResponse */ public function delete($className, $requestOptions = []) { diff --git a/src/Settings/SettingsManager.php b/src/Settings/SettingsManager.php index af241d8..fd23b64 100644 --- a/src/Settings/SettingsManager.php +++ b/src/Settings/SettingsManager.php @@ -2,7 +2,7 @@ namespace Algolia\SearchBundle\Settings; -use Algolia\AlgoliaSearch\SearchClient; +use Algolia\AlgoliaSearch\Api\SearchClient; use Symfony\Component\Filesystem\Filesystem; /** @@ -45,8 +45,7 @@ public function backup(array $params) } foreach ($indices as $indexName) { - $index = $this->algolia->initIndex($indexName); - $settings = $index->getSettings(); + $settings = $this->algolia->getSettings($indexName); $filename = $this->getFileName($indexName, 'settings'); $fs->dumpFile($filename, json_encode($settings, JSON_PRETTY_PRINT)); @@ -71,9 +70,8 @@ public function push(array $params) $filename = $this->getFileName($indexName, 'settings'); if (is_readable($filename)) { - $index = $this->algolia->initIndex($indexName); $settings = json_decode(file_get_contents($filename), true); - $index->setSettings($settings); + $this->algolia->setSettings($indexName, $settings); $output[] = "Pushed settings for $indexName"; } diff --git a/tests/TestCase/ClientProxyTest.php b/tests/TestCase/ClientProxyTest.php index 62c3fc5..1222533 100644 --- a/tests/TestCase/ClientProxyTest.php +++ b/tests/TestCase/ClientProxyTest.php @@ -2,7 +2,7 @@ namespace Algolia\SearchBundle\TestCase; -use Algolia\AlgoliaSearch\SearchClient; +use Algolia\AlgoliaSearch\Api\SearchClient; use Algolia\SearchBundle\BaseTest; use Symfony\Component\DependencyInjection\Exception\EnvNotFoundException; diff --git a/tests/TestCase/CommandsTest.php b/tests/TestCase/CommandsTest.php index f26ef27..eb086ff 100644 --- a/tests/TestCase/CommandsTest.php +++ b/tests/TestCase/CommandsTest.php @@ -19,7 +19,6 @@ class CommandsTest extends BaseTest protected $application; protected $indexName; protected $platform; - protected $index; public function setUp(): void { @@ -30,12 +29,15 @@ public function setUp(): void $this->connection = $this->get('doctrine')->getConnection(); $this->platform = $this->connection->getDatabasePlatform(); $this->indexName = 'posts'; - $this->index = $this->client->initIndex($this->getPrefix() . $this->indexName); - $this->index->setSettings($this->getDefaultConfig())->wait(); + + $fullIndexName = $this->getPrefix() . $this->indexName; + $response = $this->client->setSettings($fullIndexName, $this->getDefaultConfig()); + $this->client->waitForTask($fullIndexName, $response['taskID']); $contentsIndexName = 'contents'; - $contentsIndex = $this->client->initIndex($this->getPrefix() . $contentsIndexName); - $contentsIndex->setSettings($this->getDefaultConfig())->wait(); + $fullContentsName = $this->getPrefix() . $contentsIndexName; + $response = $this->client->setSettings($fullContentsName, $this->getDefaultConfig()); + $this->client->waitForTask($fullContentsName, $response['taskID']); $this->application = new Application(self::$kernel); $this->refreshDb($this->application); @@ -179,7 +181,9 @@ public function testSearchSettingsBackupCommand(): void 'hitsPerPage' => 51, 'maxValuesPerFacet' => 99, ]; - $this->index->setSettings($settingsToUpdate)->wait(); + $fullIndexName = $this->getPrefix() . $this->indexName; + $response = $this->client->setSettings($fullIndexName, $settingsToUpdate); + $this->client->waitForTask($fullIndexName, $response['taskID']); $command = $this->application->find('search:settings:backup'); $commandTester = new CommandTester($command); $commandTester->execute([ @@ -204,8 +208,10 @@ public function testSearchSettingsPushCommand(): void 'hitsPerPage' => 50, 'maxValuesPerFacet' => 100, ]; - $this->index->setSettings($settingsToUpdate)->wait(); - $settings = $this->index->getSettings(); + $fullIndexName = $this->getPrefix() . $this->indexName; + $response = $this->client->setSettings($fullIndexName, $settingsToUpdate); + $this->client->waitForTask($fullIndexName, $response['taskID']); + $settings = $this->client->getSettings($fullIndexName); $settingsFile = $this->getFileName($this->indexName, 'settings'); $settingsFileContent = json_decode(file_get_contents($settingsFile), true); @@ -226,7 +232,7 @@ public function testSearchSettingsPushCommand(): void // check if the settings were imported $iteration = 0; do { - $newSettings = $this->index->getSettings(); + $newSettings = $this->client->getSettings($fullIndexName); sleep(1); $iteration++; } while ($newSettings['hitsPerPage'] !== $settingsFileContent['hitsPerPage'] || $iteration < 10); diff --git a/tests/TestCase/DoctrineTest.php b/tests/TestCase/DoctrineTest.php index 60baa45..7ee5172 100644 --- a/tests/TestCase/DoctrineTest.php +++ b/tests/TestCase/DoctrineTest.php @@ -24,8 +24,9 @@ public function setUp(): void $client = $this->get('search.client'); $indexName = 'posts'; - $index = $client->initIndex($this->getPrefix() . $indexName); - $index->setSettings($this->getDefaultConfig())->wait(); + $fullIndexName = $this->getPrefix() . $indexName; + $response = $client->setSettings($fullIndexName, $this->getDefaultConfig()); + $client->waitForTask($fullIndexName, $response['taskID']); } public function cleanUp(): void diff --git a/tests/TestCase/EngineTest.php b/tests/TestCase/EngineTest.php index 1bc24d5..fa26747 100644 --- a/tests/TestCase/EngineTest.php +++ b/tests/TestCase/EngineTest.php @@ -2,9 +2,10 @@ namespace Algolia\SearchBundle\TestCase; -use Algolia\AlgoliaSearch\Response\IndexingResponse; +use Algolia\AlgoliaSearch\RequestOptions\RequestOptions; use Algolia\SearchBundle\BaseTest; use Algolia\SearchBundle\Engine; +use Algolia\SearchBundle\Responses\NullResponse; class EngineTest extends BaseTest { @@ -41,23 +42,25 @@ public function testIndexing(): void 'autoGenerateObjectIDIfNotExist' => true, ]); self::assertArrayHasKey($searchablePost->getIndexName(), $result); - self::assertEquals(1, $result[$searchablePost->getIndexName()]->count()); + self::assertCount(1, $result[$searchablePost->getIndexName()][0]['objectIDs']); // Remove $result = $this->engine->remove($searchablePost, [ 'X-Forwarded-For' => '0.0.0.0', ]); self::assertArrayHasKey($searchablePost->getIndexName(), $result); - self::assertEquals(1, $result[$searchablePost->getIndexName()]->count()); + self::assertCount(1, $result[$searchablePost->getIndexName()][0]['objectIDs']); // Update $result = $this->engine->index($searchablePost, [ 'createIfNotExists' => true, ]); self::assertArrayHasKey($searchablePost->getIndexName(), $result); - self::assertEquals(1, $result[$searchablePost->getIndexName()]->count()); - foreach ($result as $indexName => $response) { - $response->wait(); + self::assertCount(1, $result[$searchablePost->getIndexName()][0]['objectIDs']); + foreach ($result as $indexName => $responses) { + foreach ($responses as $response) { + $this->get('search.client')->waitForTask($indexName, $response['taskID']); + } } // Search @@ -92,11 +95,103 @@ public function testIndexing(): void // Cleanup $result = $this->engine->clear($searchablePost->getIndexName(), []); - self::assertInstanceOf(IndexingResponse::class, $result); + self::assertNotInstanceOf(NullResponse::class, $result); // Delete index $result = $this->engine->delete($searchablePost->getIndexName(), []); - self::assertInstanceOf(IndexingResponse::class, $result); + self::assertNotInstanceOf(NullResponse::class, $result); + } + + /** + * Same as testIndexing but passes RequestOptions objects instead of arrays. + * Verifies that RequestOptions work identically to plain arrays across + * all Engine methods (index, remove, search, searchIds, count, clear, delete). + * + * @group legacy + */ + public function testIndexingWithRequestOptions(): void + { + $searchablePost = $this->createSearchablePost(); + $indexName = $searchablePost->getIndexName(); + + // Delete index in case there is already something + $this->engine->delete($indexName, new RequestOptions([ + 'headers' => [], 'queryParameters' => [], 'body' => [], + 'readTimeout' => 30, 'writeTimeout' => 30, 'connectTimeout' => 5, + ])); + + // Index + $result = $this->engine->index($searchablePost, new RequestOptions([ + 'headers' => [], 'queryParameters' => [], 'body' => [], + 'readTimeout' => 30, 'writeTimeout' => 30, 'connectTimeout' => 5, + ])); + self::assertArrayHasKey($indexName, $result); + self::assertCount(1, $result[$indexName][0]['objectIDs']); + + // Remove + $result = $this->engine->remove($searchablePost, new RequestOptions([ + 'headers' => [], 'queryParameters' => [], 'body' => [], + 'readTimeout' => 30, 'writeTimeout' => 30, 'connectTimeout' => 5, + ])); + self::assertArrayHasKey($indexName, $result); + self::assertCount(1, $result[$indexName][0]['objectIDs']); + + // Re-index for search tests + $result = $this->engine->index($searchablePost, new RequestOptions([ + 'headers' => [], 'queryParameters' => [], 'body' => [], + 'readTimeout' => 30, 'writeTimeout' => 30, 'connectTimeout' => 5, + ])); + self::assertArrayHasKey($indexName, $result); + foreach ($result as $name => $responses) { + foreach ($responses as $response) { + $this->get('search.client')->waitForTask($name, $response['taskID']); + } + } + + // Search — verify search params in body are forwarded correctly + $result = $this->engine->search('Test', $indexName, new RequestOptions([ + 'headers' => [], 'queryParameters' => [], 'readTimeout' => 30, + 'writeTimeout' => 30, 'connectTimeout' => 5, + 'body' => [ + 'page' => 0, + 'hitsPerPage' => 1, + 'attributesToRetrieve' => ['title'], + ], + ])); + self::assertArrayHasKey('hits', $result); + self::assertCount(1, $result['hits']); + self::assertEquals(0, $result['page']); + self::assertEquals(1, $result['hitsPerPage']); + self::assertArrayHasKey('title', $result['hits'][0]); + self::assertArrayNotHasKey('content', $result['hits'][0]); + + // Search IDs + $result = $this->engine->searchIds('This should not have results', $indexName, new RequestOptions([ + 'headers' => [], 'queryParameters' => [], 'body' => ['page' => 1, 'hitsPerPage' => 20], + 'readTimeout' => 30, 'writeTimeout' => 30, 'connectTimeout' => 5, + ])); + self::assertEmpty($result); + + // Count + $result = $this->engine->count('Test', $indexName, new RequestOptions([ + 'headers' => [], 'queryParameters' => [], 'body' => [], + 'readTimeout' => 30, 'writeTimeout' => 30, 'connectTimeout' => 5, + ])); + self::assertEquals(1, $result); + + // Clear + $result = $this->engine->clear($indexName, new RequestOptions([ + 'headers' => [], 'queryParameters' => [], 'body' => [], + 'readTimeout' => 30, 'writeTimeout' => 30, 'connectTimeout' => 5, + ])); + self::assertNotInstanceOf(NullResponse::class, $result); + + // Delete + $result = $this->engine->delete($indexName, new RequestOptions([ + 'headers' => [], 'queryParameters' => [], 'body' => [], + 'readTimeout' => 30, 'writeTimeout' => 30, 'connectTimeout' => 5, + ])); + self::assertNotInstanceOf(NullResponse::class, $result); } public function testIndexingEmptyEntity(): void diff --git a/tests/TestCase/SearchServiceTest.php b/tests/TestCase/SearchServiceTest.php index 475b587..27eb330 100644 --- a/tests/TestCase/SearchServiceTest.php +++ b/tests/TestCase/SearchServiceTest.php @@ -108,9 +108,9 @@ public function testIndexedDataAreSearchable(): void self::assertEquals(6, $this->searchService->count(ContentAggregator::class)); // Cleanup - $this->searchService->delete(Post::class); - $this->searchService->delete(Comment::class); - $this->searchService->delete(ContentAggregator::class); + $this->searchService->delete(Post::class)->wait(); + $this->searchService->delete(Comment::class)->wait(); + $this->searchService->delete(ContentAggregator::class)->wait(); $this->cleanUp(); } diff --git a/tests/TestCase/SerializationTest.php b/tests/TestCase/SerializationTest.php index 07319be..1e01114 100644 --- a/tests/TestCase/SerializationTest.php +++ b/tests/TestCase/SerializationTest.php @@ -21,8 +21,7 @@ public function testSerializerHasRequiredNormalizers(): void $refl = new \ReflectionClass($serializer); $normalizersProperty = $refl->getProperty('normalizers'); - $normalizersProperty->setAccessible(true); - $normalizers = $normalizersProperty->getValue($serializer); + $normalizers = $normalizersProperty->getValue($serializer); $classes = array_map(static function ($value) { return get_class($value); diff --git a/tests/TestCase/SettingsTest.php b/tests/TestCase/SettingsTest.php index e9ee137..22cd33c 100644 --- a/tests/TestCase/SettingsTest.php +++ b/tests/TestCase/SettingsTest.php @@ -2,7 +2,7 @@ namespace Algolia\SearchBundle\TestCase; -use Algolia\AlgoliaSearch\SearchClient; +use Algolia\AlgoliaSearch\Api\SearchClient; use Algolia\SearchBundle\BaseTest; use Algolia\SearchBundle\Settings\SettingsManager; use Algolia\SearchBundle\TestApp\Entity\Post; @@ -42,8 +42,9 @@ public function testBackup(): void 'hitsPerPage' => 51, 'maxValuesPerFacet' => 99, ]; - $index = $this->client->initIndex($this->getPrefix() . $this->indexName); - $index->setSettings($settingsToUpdate)->wait(); + $fullIndexName = $this->getPrefix() . $this->indexName; + $response = $this->client->setSettings($fullIndexName, $settingsToUpdate); + $this->client->waitForTask($fullIndexName, $response['taskID']); $message = $this->settingsManager->backup(['indices' => [$this->indexName]]); @@ -70,8 +71,9 @@ public function testBackupWithoutIndices(): void ]; foreach ($this->configIndexes as $indexName => $configIndex) { - $index = $this->client->initIndex($this->getPrefix() . $indexName); - $index->setSettings($settingsToUpdate)->wait(); + $fullIndexName = $this->getPrefix() . $indexName; + $response = $this->client->setSettings($fullIndexName, $settingsToUpdate); + $this->client->waitForTask($fullIndexName, $response['taskID']); } $message = $this->settingsManager->backup(['indices' => []]); @@ -99,8 +101,9 @@ public function testPush(): void 'hitsPerPage' => 12, 'maxValuesPerFacet' => 100, ]; - $index = $this->client->initIndex($this->getPrefix() . $this->indexName); - $index->setSettings($settingsToUpdate)->wait(); + $fullIndexName = $this->getPrefix() . $this->indexName; + $response = $this->client->setSettings($fullIndexName, $settingsToUpdate); + $this->client->waitForTask($fullIndexName, $response['taskID']); $message = $this->settingsManager->push(['indices' => [$this->indexName]]); @@ -112,9 +115,10 @@ public function testPush(): void for ($i = 0; $i < 5; $i++) { sleep(1); - $settings = $index->getSettings(); + $settings = $this->client->getSettings($fullIndexName); if (12 !== $settings['hitsPerPage']) { - self::assertEquals($savedSettings, $settings); + self::assertEquals($savedSettings['hitsPerPage'], $settings['hitsPerPage']); + self::assertEquals($savedSettings['maxValuesPerFacet'], $settings['maxValuesPerFacet']); } } } @@ -130,8 +134,9 @@ public function testPushWithoutIndices(): void ]; foreach ($this->configIndexes as $indexName => $configIndex) { - $index = $this->client->initIndex($this->getPrefix() . $indexName); - $index->setSettings($settingsToUpdate)->wait(); + $fullIndexName = $this->getPrefix() . $indexName; + $response = $this->client->setSettings($fullIndexName, $settingsToUpdate); + $this->client->waitForTask($fullIndexName, $response['taskID']); } $message = $this->settingsManager->push(['indices' => []]); @@ -143,11 +148,13 @@ public function testPushWithoutIndices(): void $this->getFileName($indexName, 'settings') ), true); + $fullIndexName = $this->getPrefix() . $indexName; for ($i = 0; $i < 5; $i++) { sleep(1); - $settings = $index->getSettings(); + $settings = $this->client->getSettings($fullIndexName); if (12 !== $settings['hitsPerPage']) { - self::assertEquals($savedSettings, $settings); + self::assertEquals($savedSettings['hitsPerPage'], $settings['hitsPerPage']); + self::assertEquals($savedSettings['maxValuesPerFacet'], $settings['maxValuesPerFacet']); } } }