From 5f0202fc5de574360e7aa7d150796702b3508987 Mon Sep 17 00:00:00 2001 From: Fanis Tharropoulos Date: Tue, 17 Dec 2024 13:45:56 +0200 Subject: [PATCH 1/3] chore: add .env to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 7e50fb64..e107f66b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .idea .tmp .phpunit.result.cache +.env /composer.lock phpunit.xml vendor From adc2386c43a618cc329c49a816587e3d34695ca8 Mon Sep 17 00:00:00 2001 From: Fanis Tharropoulos Date: Tue, 17 Dec 2024 13:50:29 +0200 Subject: [PATCH 2/3] fix(http-client): improve client configuration handling * add support for HttpMethodsClient to be used directly without wrapping * handle different client types (PSR-18, HttpClient) properly by wrapping only when needed * fix client initialization to avoid creating new instances on every call * add tests for client configuration scenarios * improve type hints and error messages for invalid client configurations --- src/Lib/Configuration.php | 33 ++++++++++---- tests/Feature/HttpClientsTest.php | 71 +++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 tests/Feature/HttpClientsTest.php diff --git a/src/Lib/Configuration.php b/src/Lib/Configuration.php index da53245c..cef099f7 100644 --- a/src/Lib/Configuration.php +++ b/src/Lib/Configuration.php @@ -3,6 +3,7 @@ namespace Typesense\Lib; use Http\Client\Common\HttpMethodsClient; +use Http\Client\HttpClient; use Http\Discovery\Psr17FactoryDiscovery; use Http\Discovery\Psr18ClientDiscovery; use Monolog\Handler\StreamHandler; @@ -56,9 +57,9 @@ class Configuration private LoggerInterface $logger; /** - * @var null|ClientInterface + * @var HttpMethodsClient|ClientInterface|null */ - private ?ClientInterface $client = null; + private $client = null; /** * @var int @@ -103,8 +104,18 @@ public function __construct(array $config) $this->logger = new Logger('typesense'); $this->logger->pushHandler(new StreamHandler('php://stdout', $this->logLevel)); - if (true === \array_key_exists('client', $config) && $config['client'] instanceof ClientInterface) { - $this->client = $config['client']; + if (true === \array_key_exists('client', $config)) { + if ($config['client'] instanceof HttpMethodsClient) { + $this->client = $config['client']; + } elseif ($config['client'] instanceof HttpClient || $config['client'] instanceof ClientInterface) { + $this->client = new HttpMethodsClient( + $config['client'], + Psr17FactoryDiscovery::findRequestFactory(), + Psr17FactoryDiscovery::findStreamFactory() + ); + } else { + throw new ConfigError('Client must implement PSR-18 ClientInterface or Http\Client\HttpClient'); + } } } @@ -216,10 +227,14 @@ public function getLogger(): LoggerInterface */ public function getClient(): ClientInterface { - return new HttpMethodsClient( - $this->client ?? Psr18ClientDiscovery::find(), - Psr17FactoryDiscovery::findRequestFactory(), - Psr17FactoryDiscovery::findStreamFactory(), - ); + if ($this->client === null) { + $discoveredClient = Psr18ClientDiscovery::find(); + $this->client = new HttpMethodsClient( + $discoveredClient, + Psr17FactoryDiscovery::findRequestFactory(), + Psr17FactoryDiscovery::findStreamFactory() + ); + } + return $this->client; } } diff --git a/tests/Feature/HttpClientsTest.php b/tests/Feature/HttpClientsTest.php new file mode 100644 index 00000000..4903990d --- /dev/null +++ b/tests/Feature/HttpClientsTest.php @@ -0,0 +1,71 @@ +baseConfig = [ + 'api_key' => $_ENV['TYPESENSE_API_KEY'], + 'nodes' => [[ + 'host' => $_ENV['TYPESENSE_NODE_HOST'], + 'port' => $_ENV['TYPESENSE_NODE_PORT'], + 'protocol' => $_ENV['TYPESENSE_NODE_PROTOCOL'] + ]] + ]; + } + + public function testWorksWithDefaultClient(): void + { + $client = new Client($this->baseConfig); + $response = $client->health->retrieve(); + $this->assertIsBool($response['ok']); + } + + public function testWorksWithPsr18Client(): void + { + $httpClient = new Psr18Client(); + $config = array_merge($this->baseConfig, ['client' => $httpClient]); + + $client = new Client($config); + $response = $client->health->retrieve(); + $this->assertIsBool($response['ok']); + } + + public function testWorksWithHttpMethodsClient(): void + { + $httpClient = new HttpMethodsClient( + Psr18ClientDiscovery::find(), + Psr17FactoryDiscovery::findRequestFactory(), + Psr17FactoryDiscovery::findStreamFactory() + ); + + $config = array_merge($this->baseConfig, ['client' => $httpClient]); + + $client = new Client($config); + $response = $client->health->retrieve(); + $this->assertIsBool($response['ok']); + } + + public function testRejectsInvalidClient(): void + { + $this->expectException(ConfigError::class); + $this->expectExceptionMessage('Client must implement PSR-18 ClientInterface or Http\Client\HttpClient'); + + $config = array_merge($this->baseConfig, ['client' => new stdClass()]); + new Client($config); + } +} From 1e655651e2a43a516b519d2c06abe497d22053ff Mon Sep 17 00:00:00 2001 From: Fanis Tharropoulos Date: Mon, 23 Dec 2024 12:00:54 +0200 Subject: [PATCH 3/3] fix(client): handle legacy psr-18 client compatibility - modify client instance checks in `Configuration.php` to handle psr-18 clients correctly - update `testWorksWithPsr18Client` to wrap client with required factories - add new test `testWorksWithLegacyPsr18Client` for backward compatibility - simplify array key check using `isset` instead of `array_key_exists` --- src/Lib/Configuration.php | 6 +++--- tests/Feature/HttpClientsTest.php | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Lib/Configuration.php b/src/Lib/Configuration.php index cef099f7..7f60ec07 100644 --- a/src/Lib/Configuration.php +++ b/src/Lib/Configuration.php @@ -104,10 +104,10 @@ public function __construct(array $config) $this->logger = new Logger('typesense'); $this->logger->pushHandler(new StreamHandler('php://stdout', $this->logLevel)); - if (true === \array_key_exists('client', $config)) { - if ($config['client'] instanceof HttpMethodsClient) { + if (isset($config['client'])) { + if ($config['client'] instanceof HttpMethodsClient || $config['client'] instanceof ClientInterface) { $this->client = $config['client']; - } elseif ($config['client'] instanceof HttpClient || $config['client'] instanceof ClientInterface) { + } elseif ($config['client'] instanceof HttpClient) { $this->client = new HttpMethodsClient( $config['client'], Psr17FactoryDiscovery::findRequestFactory(), diff --git a/tests/Feature/HttpClientsTest.php b/tests/Feature/HttpClientsTest.php index 4903990d..de3ab05d 100644 --- a/tests/Feature/HttpClientsTest.php +++ b/tests/Feature/HttpClientsTest.php @@ -38,8 +38,13 @@ public function testWorksWithDefaultClient(): void public function testWorksWithPsr18Client(): void { $httpClient = new Psr18Client(); - $config = array_merge($this->baseConfig, ['client' => $httpClient]); + $wrappedClient = new HttpMethodsClient( + $httpClient, + Psr17FactoryDiscovery::findRequestFactory(), + Psr17FactoryDiscovery::findStreamFactory() + ); + $config = array_merge($this->baseConfig, ['client' => $wrappedClient]); $client = new Client($config); $response = $client->health->retrieve(); $this->assertIsBool($response['ok']); @@ -60,6 +65,14 @@ public function testWorksWithHttpMethodsClient(): void $this->assertIsBool($response['ok']); } + public function testWorksWithLegacyPsr18Client(): void + { + $httpClient = $this->createMock(\Psr\Http\Client\ClientInterface::class); + $config = array_merge($this->baseConfig, ['client' => $httpClient]); + $client = new Client($config); + $this->assertInstanceOf(Client::class, $client); + } + public function testRejectsInvalidClient(): void { $this->expectException(ConfigError::class);