diff --git a/playground/php/loadEnv.php b/playground/php/loadEnv.php index 2326f85672b..b53e2e1d0ce 100644 --- a/playground/php/loadEnv.php +++ b/playground/php/loadEnv.php @@ -1,4 +1,5 @@ $indexName, 'model' => 'bought-together', 'objectID' => $query, - 'threshold' => 0 - ] - ] + 'threshold' => 0, + ], + ], ] )); diff --git a/playground/php/src/search.php b/playground/php/src/search.php index e26c4c30dcd..241549d66f9 100644 --- a/playground/php/src/search.php +++ b/playground/php/src/search.php @@ -1,63 +1,63 @@ setMaxRetries(200); -var_dump($config->getDefaultMaxRetries()); +// $config->setMaxRetries(200); +// var_dump($config->getDefaultMaxRetries()); -//$config->setFullHosts( +// $config->setFullHosts( // [ // 'http://localhost:6677', // 'http://localhost:6678', // ] -//); +// ); -$client = SearchClient::createWithConfig($config); -$indexName = $env['SEARCH_INDEX']; - - -$response = $client->saveObject( - $indexName, - ['objectID' => "1", 'name' => 'Michel'], -); - -$client->waitForTask($indexName, $response['taskID']); +// $client = SearchClient::createWithConfig($config); +// $indexName = $env['SEARCH_INDEX']; +// +// +// $response = $client->saveObject( +// $indexName, +// ['objectID' => "1", 'name' => 'Michel'], +// ); +// +// $client->waitForTask($indexName, $response['taskID']); -//$response = $client->saveObject( +// $response = $client->saveObject( // $indexName, // ['objectID' => "2", 'name' => 'Raymond'], -//); +// ); // -//$client->waitForTask($indexName, $response['taskID']); +// $client->waitForTask($indexName, $response['taskID']); -$newGuys = [ - ['objectID' => "3", 'name' => 'Hubert'], - ['objectID' => "4", 'name' => 'Bob'], - ['objectID' => "5", 'name' => $env['SEARCH_QUERY']], -]; +// $newGuys = [ +// ['objectID' => "3", 'name' => 'Hubert'], +// ['objectID' => "4", 'name' => 'Bob'], +// ['objectID' => "5", 'name' => $env['SEARCH_QUERY']], +// ]; -$response = $client->replaceAllObjects($indexName, $newGuys, 2); +// $response = $client->replaceAllObjects($indexName, $newGuys, 2); -//var_dump( +// var_dump( // $client->search([ // 'requests' => [ // ['indexName' => $indexName, 'query' => $env['SEARCH_QUERY']], // ], // ]) -//); +// ); // $apiKey = SearchClient::generateSecuredApiKey($env['ALGOLIA_APPLICATION_ID'], ['edit','browse','listIndices']); // var_dump($apiKey); @@ -88,3 +88,9 @@ // $rules[] = $rule; // } // var_dump($rules); + +$configForIngestion = $config->setFullHosts(['http://localhost:6689'])->setTransformationRegion('eu'); + +$clientWithTransformation = SearchClient::createWithConfig($configForIngestion); + +var_dump($clientWithTransformation->saveObjectsWithTransformation('boyd', [['objectID' => '1', 'name' => 'Michel']], true)); diff --git a/scripts/cts/runCts.ts b/scripts/cts/runCts.ts index 78e7194df26..43308b2a557 100644 --- a/scripts/cts/runCts.ts +++ b/scripts/cts/runCts.ts @@ -158,7 +158,7 @@ export async function runCts( assertValidReplaceAllObjectsFailed(languages.length - skip('dart')); assertValidReplaceAllObjectsScopes(languages.length - skip('dart')); assertValidWaitForApiKey(languages.length - skip('dart')); - assertPushMockValid(only('javascript') + only('go') + only('python') + only('java')); + assertPushMockValid(only('javascript') + only('go') + only('python') + only('java') + only('php')); } if (withBenchmarkServer) { printBenchmarkReport(); diff --git a/specs/search/helpers/partialUpdateObjectsWithTransformation.yml b/specs/search/helpers/partialUpdateObjectsWithTransformation.yml index 73cff4f987a..bf1bae0dc13 100644 --- a/specs/search/helpers/partialUpdateObjectsWithTransformation.yml +++ b/specs/search/helpers/partialUpdateObjectsWithTransformation.yml @@ -2,10 +2,11 @@ method: post: x-helper: true x-available-languages: - - javascript - go - - python - java + - javascript + - php + - python tags: - Records operationId: partialUpdateObjectsWithTransformation diff --git a/specs/search/helpers/saveObjectsWithTransformation.yml b/specs/search/helpers/saveObjectsWithTransformation.yml index ed32e73267b..ca487d7dc22 100644 --- a/specs/search/helpers/saveObjectsWithTransformation.yml +++ b/specs/search/helpers/saveObjectsWithTransformation.yml @@ -2,10 +2,11 @@ method: get: x-helper: true x-available-languages: - - javascript - go - - python - java + - javascript + - php + - python tags: - Records operationId: saveObjectsWithTransformation diff --git a/templates/java/api.mustache b/templates/java/api.mustache index 0e9f6da20e4..49c23c6185f 100644 --- a/templates/java/api.mustache +++ b/templates/java/api.mustache @@ -56,6 +56,11 @@ public class {{classname}} extends ApiClient { {{#isSearchClient}} private IngestionClient ingestionTransporter; + /** + * Sets the region of the current algolia application to the configuration, this is required to be called if you wish to leverage the transformation pipeline (via the *WithTransformation methods). + * + * @param region (required) + */ public void setTransformationRegion(String region) { this.ingestionTransporter = new IngestionClient(this.authInterceptor.getApplicationId(), this.authInterceptor.getApiKey(), region, this.clientOptions); } diff --git a/templates/php/api.mustache b/templates/php/api.mustache index 62417264326..3609586c56e 100644 --- a/templates/php/api.mustache +++ b/templates/php/api.mustache @@ -18,6 +18,10 @@ use {{invokerPackage}}\RetryStrategy\ApiWrapperInterface; use {{invokerPackage}}\RetryStrategy\ClusterHosts; use {{invokerPackage}}\Support\Helpers; +{{#isSearchClient}} +use {{invokerPackage}}\Configuration\IngestionConfig; +{{/isSearchClient}} + use Algolia\AlgoliaSearch\Exceptions\NotFoundException; /** @@ -34,6 +38,11 @@ use Algolia\AlgoliaSearch\Exceptions\NotFoundException; */ protected $api; + /** + * @var IngestionClient + */ + protected $ingestionTransporter; + /** * @var {{configClassname}} */ @@ -93,7 +102,25 @@ use Algolia\AlgoliaSearch\Exceptions\NotFoundException; self::getClusterHosts($config) ); - return new static($apiWrapper, $config); + $client = new static($apiWrapper, $config); + + {{#isSearchClient}} + if (null !== $config->getTransformationRegion()) { + $ingestionConfig = IngestionConfig::create($config->getAppId(), $config->getAlgoliaApiKey(), $config->getTransformationRegion()); + + if ($hosts = $config->getHosts()) { + if ($config->getHasFullHosts()) { + $ingestionConfig = $ingestionConfig->setFullHosts($hosts); + } else { + $ingestionConfig = $ingestionConfig->setHosts($hosts); + } + } + + $client->ingestionTransporter = IngestionClient::createWithConfig($ingestionConfig); + } + {{/isSearchClient}} + + return $client; } /** @@ -514,6 +541,27 @@ use Algolia\AlgoliaSearch\Exceptions\NotFoundException; return $this->chunkedBatch($indexName, $objects, 'addObject', $waitForTasks, $batchSize, $requestOptions); } + /** + * Helper: Similar to the `saveObjects` method but requires a Push connector + * (https://www.algolia.com/doc/guides/sending-and-managing-data/send-and-update-your-data/connectors/push/) + * to be created first, in order to transform records before indexing them to Algolia. The + * `region` must have been passed to the client instantiation method. + * + * @param string $indexName the `indexName` to replace `objects` in + * @param array $objects the array of `objects` to store in the given Algolia `indexName` + * @param bool $waitForTasks Whether or not we should wait until every `batch` tasks has been processed, this operation may slow the total execution time of this method but is more reliable + * @param array $batchSize The size of the chunk of `objects`. The number of `batch` calls will be equal to `length(objects) / batchSize`. Defaults to 1000. + * @param array $requestOptions Request options + */ + public function saveObjectsWithTransformation($indexName, $objects, $waitForTasks = false, $batchSize = 1000, $requestOptions = []) + { + if (null == $this->ingestionTransporter) { + throw new \InvalidArgumentException('`setTransformationRegion` must have been called before calling this method.'); + } + + return $this->ingestionTransporter->push($indexName, ['action'=>'addObject', 'records'=>$objects], $waitForTasks, $requestOptions); + } + /** * Helper: Deletes every records for the given objectIDs. The `chunkedBatch` helper is used under the hood, which creates a `batch` requests with at most 1000 objectIDs in it. * @@ -548,6 +596,28 @@ use Algolia\AlgoliaSearch\Exceptions\NotFoundException; return $this->chunkedBatch($indexName, $objects, ($createIfNotExists == TRUE) ? 'partialUpdateObject' : 'partialUpdateObjectNoCreate', $waitForTasks, $batchSize, $requestOptions); } + /** + * Helper: Similar to the `partialUpdateObjects` method but requires a Push connector + * (https://www.algolia.com/doc/guides/sending-and-managing-data/send-and-update-your-data/connectors/push/) + * to be created first, in order to transform records before indexing them to Algolia. The + * `region` must have been passed to the client instantiation method. + * + * @param string $indexName the `indexName` to replace `objects` in + * @param array $objects the array of `objects` to store in the given Algolia `indexName` + * @param bool $createIfNotExists To be provided if non-existing objects are passed, otherwise, the call will fail.. + * @param bool $waitForTasks Whether or not we should wait until every `batch` tasks has been processed, this operation may slow the total execution time of this method but is more reliable + * @param array $batchSize The size of the chunk of `objects`. The number of `batch` calls will be equal to `length(objects) / batchSize`. Defaults to 1000. + * @param array $requestOptions Request options + */ + public function partialUpdateObjectsWithTransformation($indexName, $objects, $createIfNotExists, $waitForTasks = false, $batchSize = 1000, $requestOptions = []) + { + if (null == $this->ingestionTransporter) { + throw new \InvalidArgumentException('`setTransformationRegion` must have been called before calling this method.'); + } + + return $this->ingestionTransporter->push($indexName, ['action'=>(true == $createIfNotExists) ? 'partialUpdateObject' : 'partialUpdateObjectNoCreate', 'records'=>$objects], $waitForTasks, $requestOptions); + } + /** * Helper: Chunks the given `objects` list in subset of 1000 elements max in order to make it fit in `batch` requests. * diff --git a/templates/php/client_config.mustache b/templates/php/client_config.mustache index 246ad23f64b..85bb1b68faf 100644 --- a/templates/php/client_config.mustache +++ b/templates/php/client_config.mustache @@ -66,6 +66,25 @@ class {{configClassname}} extends {{#hasRegionalHost}}ConfigWithRegion{{/hasRegi { return $this->config['defaultMaxRetries']; } + + /** + * Sets the region of the current algolia application to the configuration, this is required to be called if you wish to leverage the transformation pipeline (via the *WithTransformation methods). + * + * @param string $region the user agent of the api client + * + * @return $this + */ + public function setTransformationRegion($region) + { + $this->config['region'] = $region; + + return $this; + } + + public function getTransformationRegion() + { + return $this->config['region']; + } {{/isSearchClient}} public function getDefaultConfiguration() @@ -80,6 +99,7 @@ class {{configClassname}} extends {{#hasRegionalHost}}ConfigWithRegion{{/hasRegi 'connectTimeout' => {{#lambda.toSeconds}}{{x-timeouts.server.connect}}{{/lambda.toSeconds}}, 'defaultHeaders' => [], {{#isSearchClient}} + 'region' => null, 'waitTaskTimeBeforeRetry' => $this->defaultWaitTaskTimeBeforeRetry, 'defaultMaxRetries' => $this->defaultMaxRetries, 'defaultForwardToReplicas' => null, diff --git a/templates/php/tests/client/createClient.mustache b/templates/php/tests/client/createClient.mustache index d5dd9af08aa..54b508fbab0 100644 --- a/templates/php/tests/client/createClient.mustache +++ b/templates/php/tests/client/createClient.mustache @@ -4,6 +4,9 @@ $client = $this->createClient( {{#parametersWithDataTypeMap.apiKey}}"{{parametersWithDataTypeMap.apiKey.value}}"{{/parametersWithDataTypeMap.apiKey}}{{^parametersWithDataTypeMap.apiKey}}null{{/parametersWithDataTypeMap.apiKey}}{{#hasRegionalHost}}, {{#parametersWithDataTypeMap.region}}"{{parametersWithDataTypeMap.region.value}}"{{/parametersWithDataTypeMap.region}}{{^parametersWithDataTypeMap.region}}null{{/parametersWithDataTypeMap.region}}{{/hasRegionalHost}} ); -{{^isError}}$this->assertIsObject($client);{{/isError}}{{/useEchoRequester}}{{#hasCustomHosts}} +{{^isError}}$this->assertIsObject($client);{{/isError}}{{/useEchoRequester}}{{^hasTransformationRegion}}{{#hasCustomHosts}} $client = {{client}}::createWithConfig({{clientPrefix}}Config::create("{{parametersWithDataTypeMap.appId.value}}","{{parametersWithDataTypeMap.apiKey.value}}"{{#hasRegionalHost}}{{#parametersWithDataTypeMap.region}},"{{parametersWithDataTypeMap.region.value}}"{{/parametersWithDataTypeMap.region}}{{/hasRegionalHost}})->setFullHosts([{{#customHosts}}"http://" . (getenv("CI") == "true" ? "localhost" : "host.docker.internal") . ":{{port}}"{{^-last}},{{/-last}}{{/customHosts}}])); -{{/hasCustomHosts}} \ No newline at end of file +{{/hasCustomHosts}}{{/hasTransformationRegion}} +{{#hasTransformationRegion}} +$client = {{client}}::createWithConfig({{clientPrefix}}Config::create("{{parametersWithDataTypeMap.appId.value}}","{{parametersWithDataTypeMap.apiKey.value}}")->setFullHosts([{{#customHosts}}"http://" . (getenv("CI") == "true" ? "localhost" : "host.docker.internal") . ":{{port}}"{{^-last}},{{/-last}}{{/customHosts}}])->setTransformationRegion("{{{transformationRegion}}}")); +{{/hasTransformationRegion}} \ No newline at end of file