diff --git a/CHANGELOG.md b/CHANGELOG.md index d154844da..530f5ae7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## [Unreleased] ### Added +- Added Guzzle and Symfony client factories. ### Changed ### Deprecated ### Removed diff --git a/UPGRADING.md b/UPGRADING.md index 5182b0ae6..f16f73be7 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -16,95 +16,50 @@ openseach-php removes the hard-coded dependency on the [Guzzle HTTP client](http You can continue to use Guzzle, but will need to configure it as a PSR-18 HTTP Client. -### HTTP Client Auto-Discovery +### PSR-18 HTTP Client Interfaces -opensearch-php 2.x will try and discover and install a PSR HTTP Client using [PHP-HTTP Discovery](https://docs.php-http.org/en/latest/discovery.html) -if one is not explicitly provided. +Starting with `opensearch-php` 2.4.0 you can use any PSR-18 compatible HTTP client. -```php -$transport = (new \OpenSearch\TransportFactory())->create(); -$endpointFactory = new \OpenSearch\EndpointFactory(); -$client = new Client($transport, $endpointFactory, []); - -// Send a request to the 'info' endpoint. -$info = $client->info(); -``` +To simplify creating a Client, we provide two factories to create PSR-18 HTTP clients +for Guzzle and Symfony HTTP clients. -### Configuring Guzzle HTTP Client in 2.x +### Configuring Guzzle HTTP Client in 2.4.x To configure Guzzle as a PSR HTTP Client with the similar configuration to opensearch 1.x you can use the following example: +Ensure the Guzzle packages are installed via composer: + ```php -$guzzleClient = new \GuzzleHttp\Client([ +composer require guzzlehttp/guzzle +``` + +```php +$client = (new \OpenSearch\GuzzleClientFactory())->create([ 'base_uri' => 'https://localhost:9200', 'auth' => ['admin', getenv('OPENSEARCH_PASSWORD')], 'verify' => false, - 'retries' => 2, - 'headers' => [ - 'Accept' => 'application/json', - 'Content-Type' => 'application/json', - 'User-Agent' => sprintf('opensearch-php/%s (%s; PHP %s)', \OpenSearch\Client::VERSION, PHP_OS, PHP_VERSION), - ] ]); -$guzzleHttpFactory = new \GuzzleHttp\Psr7\HttpFactory(); - -$serializer = new \OpenSearch\Serializers\SmartSerializer(); - -$requestFactory = new \OpenSearch\RequestFactory( - $guzzleHttpFactory, - $guzzleHttpFactory, - $guzzleHttpFactory, - $serializer, -); - -$transport = (new OpenSearch\TransportFactory()) - ->setHttpClient($guzzleClient) - ->setRequestFactory($requestFactory) - ->create(); - -$endpointFactory = new \OpenSearch\EndpointFactory(); -$client = new \OpenSearch\Client($transport, $endpointFactory, []); - // Send a request to the 'info' endpoint. $info = $client->info(); ``` -### Configuring Symfony HTTP Client in 2.x +### Configuring Symfony HTTP Client in 2.4.x You can configure [Symfony HTTP Client](https://symfony.com/doc/current/http_client.html) as a PSR HTTP Client using the following example: ```php -$symfonyPsr18Client = (new \Symfony\Component\HttpClient\Psr18Client())->withOptions([ +composer require symfony/http-client +``` + +```php +$client = (new \OpenSearch\SymfonyClientFactory())->create([ 'base_uri' => 'https://localhost:9200', 'auth_basic' => ['admin', getenv('OPENSEARCH_PASSWORD')], 'verify_peer' => false, - 'max_retries' => 2, - 'headers' => [ - 'Accept' => 'application/json', - 'Content-Type' => 'application/json', - ], ]); -$serializer = new \OpenSearch\Serializers\SmartSerializer(); - -$requestFactory = new \OpenSearch\RequestFactory( - $symfonyPsr18Client, - $symfonyPsr18Client, - $symfonyPsr18Client, - $serializer, -); - -$transport = (new \OpenSearch\TransportFactory()) - ->setHttpClient($symfonyPsr18Client) - ->setRequestFactory($requestFactory) - ->create(); - -$endpointFactory = new \OpenSearch\EndpointFactory(); -$client = new \OpenSearch\Client($transport, $endpointFactory, []); - // Send a request to the 'info' endpoint. $info = $client->info(); - ``` diff --git a/samples/README.md b/samples/README.md index 5c2fd6c9e..f494147e2 100644 --- a/samples/README.md +++ b/samples/README.md @@ -3,7 +3,7 @@ Start an OpenSearch instance. ``` -docker run -d -p 9200:9200 -p 9600:9600 -e "discovery.type=single-node" -e "OPENSEARCH_INITIAL_ADMIN_PASSWORD=myStrongPassword123!" opensearchproject/opensearch:latest +docker compose up ``` Run sample. diff --git a/samples/index.php b/samples/index.php index 0cb2ebcee..3d2d5fbe0 100644 --- a/samples/index.php +++ b/samples/index.php @@ -1,12 +1,7 @@ create(); -$endpointFactory = new EndpointFactory(); -$client = new Client($transport, $endpointFactory, []); - -// Send a request to the 'info' endpoint. -$info = $client->info(); - // Guzzle example -$guzzleClient = new \GuzzleHttp\Client([ +$client = (new GuzzleClientFactory())->create([ 'base_uri' => 'https://localhost:9200', 'auth' => ['admin', getenv('OPENSEARCH_PASSWORD')], 'verify' => false, - 'retries' => 2, - 'headers' => [ - 'Accept' => 'application/json', - 'Content-Type' => 'application/json', - 'User-Agent' => sprintf('opensearch-php/%s (%s; PHP %s)', Client::VERSION, PHP_OS, PHP_VERSION), - ] ]); -$guzzleHttpFactory = new HttpFactory(); - -$serializer = new SmartSerializer(); - -$requestFactory = new RequestFactory( - $guzzleHttpFactory, - $guzzleHttpFactory, - $guzzleHttpFactory, - $serializer, -); - -$transport = (new TransportFactory()) - ->setHttpClient($guzzleClient) - ->setRequestFactory($requestFactory) - ->create(); - -$endpointFactory = new EndpointFactory(); -$client = new Client($transport, $endpointFactory, []); - // Send a request to the 'info' endpoint. $info = $client->info(); // Symfony example -$symfonyPsr18Client = (new Psr18Client())->withOptions([ +$client = (new SymfonyClientFactory())->create([ 'base_uri' => 'https://localhost:9200', 'auth_basic' => ['admin', getenv('OPENSEARCH_PASSWORD')], 'verify_peer' => false, - 'max_retries' => 2, - 'headers' => [ - 'Accept' => 'application/json', - 'Content-Type' => 'application/json', - ], ]); -$serializer = new SmartSerializer(); - -$requestFactory = new RequestFactory( - $symfonyPsr18Client, - $symfonyPsr18Client, - $symfonyPsr18Client, - $serializer, -); - -$transport = (new TransportFactory()) - ->setHttpClient($symfonyPsr18Client) - ->setRequestFactory($requestFactory) - ->create(); - -$client = new Client($transport, $endpointFactory, []); - // Send a request to the 'info' endpoint. $info = $client->info(); diff --git a/src/OpenSearch/ClientFactory.php b/src/OpenSearch/ClientFactory.php deleted file mode 100644 index f94f26050..000000000 --- a/src/OpenSearch/ClientFactory.php +++ /dev/null @@ -1,19 +0,0 @@ -transport, $this->endpointFactory, $this->registeredNamespaces); - } - -} diff --git a/src/OpenSearch/ClientFactoryInterface.php b/src/OpenSearch/ClientFactoryInterface.php new file mode 100644 index 000000000..23f44c3d4 --- /dev/null +++ b/src/OpenSearch/ClientFactoryInterface.php @@ -0,0 +1,17 @@ + $options + * The options to use when creating the client. The options are specific to the HTTP client implementation. + */ + public function create(array $options): Client; +} diff --git a/src/OpenSearch/GuzzleClientFactory.php b/src/OpenSearch/GuzzleClientFactory.php new file mode 100644 index 000000000..099ed4ac8 --- /dev/null +++ b/src/OpenSearch/GuzzleClientFactory.php @@ -0,0 +1,48 @@ + $options + * The Guzzle client options. + */ + public function create(array $options): Client + { + $httpClient = (new GuzzleHttpClientFactory($this->maxRetries, $this->logger))->create($options); + $httpFactory = new HttpFactory(); + + $serializer = new SmartSerializer(); + + $requestFactory = new RequestFactory( + $httpFactory, + $httpFactory, + $httpFactory, + $serializer, + ); + + $transport = (new TransportFactory()) + ->setHttpClient($httpClient) + ->setRequestFactory($requestFactory) + ->create(); + + return new Client($transport, new EndpointFactory($serializer), []); + } +} diff --git a/src/OpenSearch/HttpClient/GuzzleHttpClientFactory.php b/src/OpenSearch/HttpClient/GuzzleHttpClientFactory.php index 35682d8ed..fcab115ca 100644 --- a/src/OpenSearch/HttpClient/GuzzleHttpClientFactory.php +++ b/src/OpenSearch/HttpClient/GuzzleHttpClientFactory.php @@ -8,7 +8,6 @@ use GuzzleHttp\HandlerStack; use GuzzleHttp\Middleware; use OpenSearch\Client; -use Psr\Http\Client\ClientInterface; use Psr\Log\LoggerInterface; /** @@ -25,7 +24,7 @@ public function __construct( /** * {@inheritdoc} */ - public function create(array $options): ClientInterface + public function create(array $options): GuzzleClient { if (!isset($options['base_uri'])) { throw new \InvalidArgumentException('The base_uri option is required.'); diff --git a/src/OpenSearch/HttpClient/SymfonyHttpClientFactory.php b/src/OpenSearch/HttpClient/SymfonyHttpClientFactory.php index e70e43783..7bee6126a 100644 --- a/src/OpenSearch/HttpClient/SymfonyHttpClientFactory.php +++ b/src/OpenSearch/HttpClient/SymfonyHttpClientFactory.php @@ -5,7 +5,6 @@ namespace OpenSearch\HttpClient; use OpenSearch\Client; -use Psr\Http\Client\ClientInterface; use Psr\Log\LoggerInterface; use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\HttpClient\Psr18Client; @@ -25,7 +24,7 @@ public function __construct( /** * {@inheritdoc} */ - public function create(array $options): ClientInterface + public function create(array $options): Psr18Client { if (!isset($options['base_uri'])) { throw new \InvalidArgumentException('The base_uri option is required.'); diff --git a/src/OpenSearch/SymfonyClientFactory.php b/src/OpenSearch/SymfonyClientFactory.php new file mode 100644 index 000000000..8334866fc --- /dev/null +++ b/src/OpenSearch/SymfonyClientFactory.php @@ -0,0 +1,47 @@ + $options + * The Symfony HTTP Client options. + */ + public function create(array $options): Client + { + $httpClient = (new SymfonyHttpClientFactory($this->maxRetries, $this->logger))->create($options); + + $serializer = new SmartSerializer(); + + $requestFactory = new RequestFactory( + $httpClient, + $httpClient, + $httpClient, + $serializer, + ); + + $transport = (new TransportFactory()) + ->setHttpClient($httpClient) + ->setRequestFactory($requestFactory) + ->create(); + + $endpointFactory = new EndpointFactory(); + return new Client($transport, $endpointFactory, []); + } +} diff --git a/tests/GuzzleClientFactoryTest.php b/tests/GuzzleClientFactoryTest.php new file mode 100644 index 000000000..6cc6bc080 --- /dev/null +++ b/tests/GuzzleClientFactoryTest.php @@ -0,0 +1,31 @@ +create([ + 'base_uri' => 'https://localhost:9200', + 'auth' => ['admin', 'password'], + 'verify' => false, + ]); + + $this->assertInstanceOf(Client::class, $client); + } +} diff --git a/tests/SymfonyClientFactoryTest.php b/tests/SymfonyClientFactoryTest.php new file mode 100644 index 000000000..f5315dc33 --- /dev/null +++ b/tests/SymfonyClientFactoryTest.php @@ -0,0 +1,31 @@ +create([ + 'base_uri' => 'https://localhost:9200', + 'auth_basic' => ['admin', 'password'], + 'verify_peer' => false, + ]); + + $this->assertInstanceOf(Client::class, $client); + } +}