From b2c43ec781d760be62098c5105fabe3c27aaa3d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Pimpa=CC=83o?= Date: Fri, 3 May 2024 11:05:39 +0100 Subject: [PATCH 1/3] chore: make methods public --- src/Api.php | 28 ++++++------- tests/Integration/ApiTest.php | 79 +---------------------------------- 2 files changed, 15 insertions(+), 92 deletions(-) diff --git a/src/Api.php b/src/Api.php index d102c42..366ec69 100644 --- a/src/Api.php +++ b/src/Api.php @@ -55,7 +55,7 @@ public function __construct() * @throws ConfigException If a base URL has not been set. * @throws ClientException */ - protected function request( + public function request( string $method, string $path, array $query = [], @@ -138,50 +138,50 @@ private function configurePlugins(): void } } - protected function getBaseUrl(): ?string + public function getBaseUrl(): ?string { return $this->baseUrl; } - protected function setBaseUrl(string $baseUrl): self + public function setBaseUrl(string $baseUrl): self { $this->baseUrl = $baseUrl; return $this; } - protected function getQueryDefault(string $name): mixed + public function getQueryDefault(string $name): mixed { return $this->queryDefaults[$name] ?? null; } - protected function addQueryDefault(string $name, mixed $value): self + public function addQueryDefault(string $name, mixed $value): self { $this->queryDefaults[$name] = $value; return $this; } - protected function removeQueryDefault(string $name): self + public function removeQueryDefault(string $name): self { unset($this->queryDefaults[$name]); return $this; } - protected function getHeaderDefault(string $name): mixed + public function getHeaderDefault(string $name): mixed { return $this->headerDefaults[$name] ?? null; } - protected function addHeaderDefault(string $name, mixed $value): self + public function addHeaderDefault(string $name, mixed $value): self { $this->headerDefaults[$name] = $value; return $this; } - protected function removeHeaderDefault(string $name): self + public function removeHeaderDefault(string $name): self { unset($this->headerDefaults[$name]); @@ -224,33 +224,33 @@ public function setLoggerBuilder(?LoggerBuilder $loggerBuilder): self return $this; } - protected function getAuthentication(): ?Authentication + public function getAuthentication(): ?Authentication { return $this->authentication; } - protected function setAuthentication(?Authentication $authentication): self + public function setAuthentication(?Authentication $authentication): self { $this->authentication = $authentication; return $this; } - protected function addPostRequestHandler(callable $handler, int $priority = 0): self + public function addPostRequestHandler(callable $handler, int $priority = 0): self { $this->eventDispatcher->addListener(PostRequestEvent::class, $handler, $priority); return $this; } - protected function addResponseContentsHandler(callable $handler, int $priority = 0): self + public function addResponseContentsHandler(callable $handler, int $priority = 0): self { $this->eventDispatcher->addListener(ResponseContentsEvent::class, $handler, $priority); return $this; } - protected function buildPath(string $path, array $parameters): string + public function buildPath(string $path, array $parameters): string { foreach ($parameters as $parameter => $value) { $path = \str_replace( diff --git a/tests/Integration/ApiTest.php b/tests/Integration/ApiTest.php index 17d17c8..33b5adb 100644 --- a/tests/Integration/ApiTest.php +++ b/tests/Integration/ApiTest.php @@ -15,7 +15,6 @@ use ProgrammatorDev\Api\Test\MockResponse; use Psr\Cache\CacheItemPoolInterface; use Psr\Http\Message\RequestInterface; -use Psr\Http\Message\StreamInterface; use Psr\Log\LoggerInterface; class ApiTest extends AbstractTestCase @@ -31,83 +30,7 @@ protected function setUp(): void parent::setUp(); // set protected functions to public for testing - $this->class = new class extends Api { - public function request( - string $method, - string $path, - array $query = [], - array $headers = [], - StreamInterface|string $body = null - ): mixed - { - return parent::request($method, $path, $query, $headers, $body); - } - - public function getBaseUrl(): ?string - { - return parent::getBaseUrl(); - } - - public function setBaseUrl(string $baseUrl): Api - { - return parent::setBaseUrl($baseUrl); - } - - public function getQueryDefault(string $name): mixed - { - return parent::getQueryDefault($name); - } - - public function addQueryDefault(string $name, mixed $value): Api - { - return parent::addQueryDefault($name, $value); - } - - public function removeQueryDefault(string $name): Api - { - return parent::removeQueryDefault($name); - } - - public function getHeaderDefault(string $name): mixed - { - return parent::getHeaderDefault($name); - } - - public function addHeaderDefault(string $name, mixed $value): Api - { - return parent::addHeaderDefault($name, $value); - } - - public function removeHeaderDefault(string $name): Api - { - return parent::removeHeaderDefault($name); - } - - public function getAuthentication(): ?Authentication - { - return parent::getAuthentication(); - } - - public function setAuthentication(?Authentication $authentication): Api - { - return parent::setAuthentication($authentication); - } - - public function addPostRequestHandler(callable $handler, int $priority = 0): Api - { - return parent::addPostRequestHandler($handler, $priority); - } - - public function addResponseContentsHandler(callable $handler, int $priority = 0): Api - { - return parent::addResponseContentsHandler($handler, $priority); - } - - public function buildPath(string $path, array $parameters): string - { - return parent::buildPath($path, $parameters); - } - }; + $this->class = new class extends Api {}; // set mock client $this->mockClient = new Client(); From 520d3affbedbfdae32a96ea5f0e3a6948f0d0f5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Pimpa=CC=83o?= Date: Fri, 3 May 2024 12:26:37 +0100 Subject: [PATCH 2/3] docs: added event priority and propagation sections --- README.md | 143 ++++++++++++++++++++++++------------------------------ 1 file changed, 64 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index c2a5fdb..362cf64 100644 --- a/README.md +++ b/README.md @@ -13,24 +13,20 @@ A library for creating SDKs in PHP with support for: - Event listeners; - ...and more. +All methods are public for full end user hackability 🔥. + ## Requirements - PHP 8.1 or higher. ## Installation -You can install the library via [Composer](https://getcomposer.org/): +Install the library via [Composer](https://getcomposer.org/): ```bash composer require programmatordev/php-api-sdk ``` -To use the library, use Composer's [autoload](https://getcomposer.org/doc/01-basic-usage.md#autoloading): - -```php -require_once 'vendor/autoload.php'; -``` - ## Basic Usage Just extend your API library with the `Api` class and have fun coding: @@ -365,6 +361,8 @@ class YourApi extends Api - [`addPostRequestHandler`](#addpostrequesthandler) - [`addResponseContentsHandler`](#addresponsecontentshandler) +- [Event Priority](#event-priority) +- [Event Propagation](#event-propagation) #### `addPostRequestHandler` @@ -455,11 +453,65 @@ class YourApi extends Api } ``` -### HTTP Client (PSR-18) and HTTP Factories (PSR-17) +#### Event Priority + +It is possible to add multiple listeners for the same event and set the order in which they will be executed. +By default, they will be executed in the same order as they are added, but you can set a `priority` to control that order. +Event listeners are then executed from the highest priority to the lowest: + +```php +use ProgrammatorDev\Api\Api; +use ProgrammatorDev\Api\Event\PostRequestEvent; + +class YourApi extends Api +{ + public function __construct() + { + // two event listeners are added, + // but the second is executed first (higher priority) even though it was added after + + // executed last (lower priority) + $this->addResponseContentsHandler( + handler: function(PostRequestEvent $event) { ... }, + priority: 0 + ); + + // executed first (higher priority) + $this->addResponseContentsHandler( + handler: function(PostRequestEvent $event) { ... }, + priority: 10 + ); + } +} +``` + +#### Event Propagation + +In some cases, you may want to stop the event flow and prevent listeners from being called. +For that, you can use the `stopPropagation()` method: + +```php +use ProgrammatorDev\Api\Api; +use ProgrammatorDev\Api\Event\PostRequestEvent; + +class YourApi extends Api +{ + public function __construct() + { + $this->addResponseContentsHandler(function(PostRequestEvent $event) { + // stop propagation so future listeners of this event will not be called + $event->stopPropagation(); + }); + + // this listener will not be called + $this->addResponseContentsHandler(function(PostRequestEvent $event) { + // ... + }); + } +} +``` -> [!IMPORTANT] -> The methods in this section are all public. -> The purpose for that is to allow the end user to configure their own HTTP client, HTTP factories and plugins. +### HTTP Client (PSR-18) and HTTP Factories (PSR-17) - [HTTP client and HTTP factory adapters](#http-client-and-http-factory-adapters) - [Plugin system](#plugin-system) @@ -525,30 +577,12 @@ class YourApi extends Api } ``` -The same for the end user: - -```php -$api = new YourApi(); - -$client = new Psr18Client(); -$requestFactory = $streamFactory = new Psr17Factory(); - -$api->setClientBuilder( - new ClientBuilder( - client: $client, - requestFactory: $requestFactory, - streamFactory: $streamFactory - ) -); -``` - #### Plugin System This library enables attaching plugins to the HTTP client. A plugin modifies the behavior of the client by intercepting the request and response flow. -Since plugin order matters, a plugin is added with a priority level, -and are executed in descending order from highest to lowest. +Since plugin order matters, a plugin is added with a priority level, and are executed in descending order from highest to lowest. Check all the [available plugins](https://docs.php-http.org/en/latest/plugins/index.html) or [create your own](https://docs.php-http.org/en/latest/plugins/build-your-own.html). @@ -597,23 +631,8 @@ class YourApi extends Api } ``` -The same for the end user: - -```php -$api = new YourApi(); - -$api->getClientBuilder()->addPlugin( - plugin: new RetryPlugin(['retries' => 3]) - priority: 12 -); -``` - ### Cache (PSR-6) -> [!IMPORTANT] -> The methods in this section are all public. -> The purpose for that is to allow the end user to configure their own cache adapter. - This library allows configuring the cache layer of the client for making API requests. It uses a standard PSR-6 implementation and provides methods to fine-tune how HTTP caching behaves: - [PSR-6 compatible implementations](https://packagist.org/providers/psr/cache-implementation) @@ -685,27 +704,8 @@ class YourApi extends Api } ``` -The same for the end user: - -```php -$api = new YourApi(); - -$pool = new FilesystemAdapter(); - -$api->setCacheBuilder( - new CacheBuilder( - pool: $pool, - ttl: 3600 - ) -); -``` - ### Logger (PSR-3) -> [!IMPORTANT] -> The methods in this section are all public. -> The purpose for that is to allow the end user to configure their own logger adapter. - This library allows configuring a logger to save data for making API requests. It uses a standard PSR-3 implementation and provides methods to fine-tune how logging behaves: - [PSR-3 compatible implementations](https://packagist.org/providers/psr/log-implementation) @@ -763,21 +763,6 @@ class YourApi extends Api } ``` -The same for the end user: - -```php -$api = new YourApi(); - -$logger = new Logger('api'); -$logger->pushHandler(new StreamHandler('/logs/api.log')); - -$api->setLoggerBuilder( - new LoggerBuilder( - logger: $logger - ) -); -``` - ### Configure Options It is very common for APIs to offer different options (like language, timezone, etc.). From aadcf0594db721addc82b6bfb3c9924e0fa59cb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Pimpa=CC=83o?= Date: Fri, 3 May 2024 12:29:29 +0100 Subject: [PATCH 3/3] tests: fixed comment --- tests/Integration/ApiTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Integration/ApiTest.php b/tests/Integration/ApiTest.php index 33b5adb..9a7881f 100644 --- a/tests/Integration/ApiTest.php +++ b/tests/Integration/ApiTest.php @@ -29,7 +29,7 @@ protected function setUp(): void { parent::setUp(); - // set protected functions to public for testing + // create anonymous class $this->class = new class extends Api {}; // set mock client