diff --git a/README.md b/README.md index 04a4e70..8c17130 100644 --- a/README.md +++ b/README.md @@ -11,162 +11,256 @@ __Table of contents__ * [Get channel information](#get-channel-information) * [Delete a channel](#delete-a-channel) * [Nchan status information](#nchan-status-information) - * [Use with authentication](#use-with-authentication) -* [Exchange the provided http client](#exchange-the-provided-http-client) + * [Authorize requests](#authorize-requests) +* [PSR-18 compatibility](#psr-18-compatibility) ## Overview This is a PHP client for [https://nchan.io](https://nchan.io). -This library provides a http client which has some authentication features. If you need more, you can for sure -exchange this library with another like guzzle. Take a look below to -"[Exchange the provided http client](#exchange-the-provided-http-client)". - ## Installation and requirements ``` composer require marein/php-nchan-client ``` -If you use the provided http client (default if you don't set anything), -you must enable the php configuration +If you want to use the +[PSR-18 adapter](#psr-18-compatibility), +install a library that implements PSR-18 http client +([see here](https://packagist.org/providers/psr/http-client-implementation)) +and a library that implements PSR-17 http factories +([see here](https://packagist.org/providers/psr/http-factory-implementation)). + +If you want to use the built-in http client (default if you don't set anything), +enable the php configuration [allow_url_fopen](http://php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen). ## Usage -### Publish a message - -```php -channel('/path-to-publisher-endpoint'); - $channelInformation = $channel->publish( - new PlainTextMessage( - 'my-message-name', - 'my message content' - ) - ); +### Publish a message - // Nchan returns some channel information after publishing a message. - var_dump($channelInformation); -} -``` +
+ Show code -### Get channel information + ```php + channel('/path-to-publisher-endpoint'); + $channelInformation = $channel->publish( + new PlainTextMessage( + 'my-message-name', + 'my message content' + ) + ); - $nchan = new Nchan('http://my-nchan-domain'); - $channel = $nchan->channel('/path-to-publisher-endpoint'); - $channelInformation = $channel->information(); + // Nchan returns some channel information after publishing a message. + var_dump($channelInformation); + } + ``` +
- var_dump($channelInformation); -} -``` +### Get channel information -### Delete a channel +
+ Show code -```php -channel('/path-to-publisher-endpoint'); - $channel->delete(); -} -``` + $nchan = new Nchan('http://my-nchan-domain'); + $channel = $nchan->channel('/path-to-publisher-endpoint'); + $channelInformation = $channel->information(); -### Nchan status information + var_dump($channelInformation); + } + ``` +
-First you have to create a location with the `nchan_stub_status directive`. Then you can query it. +### Delete a channel -```php - + Show code -namespace { + ```php + status('/path-to-status-location'); - $statusInformation = $status->information(); + include '/path/to/autoload.php'; - var_dump($statusInformation); -} -``` + $nchan = new Nchan('http://my-nchan-domain'); + $channel = $nchan->channel('/path-to-publisher-endpoint'); + $channel->delete(); + } + ``` + -### Use with authentication +### Nchan status information -Nchan gives you the possibility to authenticate endpoints with the `nchan_authorize_request` directive. -The provided http client supports basic and bearer authentication. It needs to be setup as follows. +Endpoints with the `nchan_stub_status` directive can be queried as follows. -```php - + Show code -namespace { + ```php + status('/path-to-status-location'); + $statusInformation = $status->information(); - $nchan = new Nchan('http://my-nchan-domain', $adapter); -} + var_dump($statusInformation); + } ``` + -The -`\Marein\Nchan\HttpAdapter\HttpStreamWrapperClient` -class constructor takes an implementation of type -`\Marein\Nchan\HttpAdapter\Credentials`. -As long as you implement that interface, you can build your own authentication -method. Take a look at -`\Marein\Nchan\HttpAdapter\BasicAuthenticationCredentials` -to see how this works. - -## Exchange the provided http client - -Sometimes, the provided client is not enough and you want to use features from other libraries like guzzle. -You can exchange the http client easily because of the -`\Marein\Nchan\Http\Client` -interface. I've created a guzzle adapter -for those who want to use guzzle. This is also a good example to look at, if you want to use another library. The -guzzle adapter lives at -[marein/php-nchan-client-guzzle-adapter](https://github.com/marein/php-nchan-client-guzzle-adapter). - -Another good reason to exchange the provided client is to gain performance, since the client uses the http stream wrapper -from php. There is a little overhead because the tcp connection gets closed after each request. Other implementations, -like guzzle, can keep the connection alive. +### Authorize requests + +Endpoints with the `nchan_authorize_request` directive must be authorized. +The constructor of the +[built-in http client](/src/HttpAdapter/HttpStreamWrapperClient.php) +takes an implementation of type +[Credentials](/src/HttpAdapter/Credentials.php). +This library comes with 2 built-in implementations, +[BasicAuthenticationCredentials](/src/HttpAdapter/BasicAuthenticationCredentials.php) +and +[BearerAuthenticationCredentials](/src/HttpAdapter/BearerAuthenticationCredentials.php). + +
+ Show code + + ```php + + +If you use another http client through the +[PSR-18 adapter](#psr-18-compatibility), +the respective http client has its own extension points to modify the request before it is sent. + +## PSR-18 compatibility + +This library comes with a PSR-18 compatible +[adapter](/src/HttpAdapter/Psr18ClientAdapter.php). +There are good reasons not to use the built-in client. +It's based on the http stream wrapper and `file_get_contents`. +This closes the TCP connection after each request. +Other clients, see below, can keep the connection open. + +The following example uses +[guzzlehttp/guzzle](https://packagist.org/packages/guzzlehttp/guzzle) +and +[guzzlehttp/psr7](https://packagist.org/packages/guzzlehttp/psr7). + +
+ Show code + + ```php + + +The following code example uses +[symfony/http-client](https://packagist.org/packages/symfony/http-client) +and +[nyholm/psr7](https://packagist.org/packages/nyholm/psr7). + +
+ Show code + + ```php + diff --git a/composer.json b/composer.json index fe0fd39..7553b2a 100644 --- a/composer.json +++ b/composer.json @@ -20,12 +20,17 @@ }, "require": { "php": "^7.4 || ^8.0", - "ext-json": "*" + "ext-json": "*", + "psr/http-client": "^1.0", + "psr/http-message": "^1.0", + "psr/http-factory": "^1.0" }, "require-dev": { "phpunit/phpunit": "^9.5", "symfony/process": "^5.4", "squizlabs/php_codesniffer": "^3.6", - "phpstan/phpstan": "^1.2" + "phpstan/phpstan": "^1.2", + "symfony/http-client": "^5.4", + "nyholm/psr7": "^1.5" } } diff --git a/composer.lock b/composer.lock index 222a3f3..c025ae7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,160 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "90eecf44ea84544e4c2a84f219bad999", - "packages": [], + "content-hash": "3ae070ca2b604a15c991eeaf4308013a", + "packages": [ + { + "name": "psr/http-client", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "time": "2020-06-29T06:28:15+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "time": "2019-04-30T12:38:16+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + } + ], "packages-dev": [ { "name": "doctrine/instantiator", @@ -158,6 +310,69 @@ ], "time": "2021-11-30T19:35:32+00:00" }, + { + "name": "nyholm/psr7", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/Nyholm/psr7.git", + "reference": "1461e07a0f2a975a52082ca3b769ca912b816226" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Nyholm/psr7/zipball/1461e07a0f2a975a52082ca3b769ca912b816226", + "reference": "1461e07a0f2a975a52082ca3b769ca912b816226", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "php-http/message-factory": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "http-interop/http-factory-tests": "^0.9", + "php-http/psr7-integration-tests": "^1.0", + "phpunit/phpunit": "^7.5 || 8.5 || 9.4", + "symfony/error-handler": "^4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "Nyholm\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Martijn van der Ven", + "email": "martijn@vanderven.se" + } + ], + "description": "A fast PHP7 implementation of PSR-7", + "homepage": "https://tnyholm.se", + "keywords": [ + "psr-17", + "psr-7" + ], + "time": "2022-02-02T18:37:57+00:00" + }, { "name": "phar-io/manifest", "version": "2.0.3", @@ -261,6 +476,56 @@ "description": "Library for handling version information and constraints", "time": "2021-02-23T14:00:09+00:00" }, + { + "name": "php-http/message-factory", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-http/message-factory.git", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/message-factory/zipball/a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Factory interfaces for PSR-7 HTTP Message", + "homepage": "http://php-http.org", + "keywords": [ + "factory", + "http", + "message", + "stream", + "uri" + ], + "time": "2015-12-19T14:08:53+00:00" + }, { "name": "phpdocumentor/reflection-common", "version": "2.2.0", @@ -871,6 +1136,97 @@ ], "time": "2021-12-25T07:07:57+00:00" }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2021-11-05T16:50:12+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2021-05-03T11:20:27+00:00" + }, { "name": "sebastian/cli-parser", "version": "1.0.1", @@ -1726,6 +2082,187 @@ ], "time": "2021-12-12T21:44:58+00:00" }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/6f981ee24cf69ee7ce9736146d1c57c2780598a8", + "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "time": "2021-07-12T14:48:14+00:00" + }, + { + "name": "symfony/http-client", + "version": "v5.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client.git", + "reference": "fab84798694e45b4571d305125215699eb2b1f73" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client/zipball/fab84798694e45b4571d305125215699eb2b1f73", + "reference": "fab84798694e45b4571d305125215699eb2b1f73", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/http-client-contracts": "^2.4", + "symfony/polyfill-php73": "^1.11", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.0|^2|^3" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "2.4" + }, + "require-dev": { + "amphp/amp": "^2.5", + "amphp/http-client": "^4.2.1", + "amphp/http-tunnel": "^1.0", + "amphp/socket": "^1.1", + "guzzlehttp/promises": "^1.4", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4.13|^5.1.5|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/stopwatch": "^4.4|^5.0|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", + "time": "2022-02-27T08:46:18+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "ec82e57b5b714dbb69300d348bd840b345e24166" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ec82e57b5b714dbb69300d348bd840b345e24166", + "reference": "ec82e57b5b714dbb69300d348bd840b345e24166", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/http-client-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2021-11-03T09:24:47+00:00" + }, { "name": "symfony/polyfill-ctype", "version": "v1.24.0", @@ -1791,6 +2328,68 @@ ], "time": "2021-10-20T20:35:02+00:00" }, + { + "name": "symfony/polyfill-php73", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", + "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2021-06-05T21:20:04+00:00" + }, { "name": "symfony/polyfill-php80", "version": "v1.24.0", @@ -1902,6 +2501,72 @@ "homepage": "https://symfony.com", "time": "2021-12-27T21:01:00+00:00" }, + { + "name": "symfony/service-contracts", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", + "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2021-11-04T16:48:04+00:00" + }, { "name": "theseer/tokenizer", "version": "1.2.1", diff --git a/src/HttpAdapter/Psr18ClientAdapter.php b/src/HttpAdapter/Psr18ClientAdapter.php new file mode 100644 index 0000000..36b6bd7 --- /dev/null +++ b/src/HttpAdapter/Psr18ClientAdapter.php @@ -0,0 +1,72 @@ +client = $client; + $this->requestFactory = $requestFactory; + $this->streamFactory = $streamFactory; + } + + public function get(Request $request): Response + { + return $this->request('GET', $request); + } + + public function post(Request $request): Response + { + return $this->request('POST', $request); + } + + public function delete(Request $request): Response + { + return $this->request('DELETE', $request); + } + + /** + * @throws NchanException + */ + private function request(string $method, Request $request): Response + { + try { + $psrRequest = $this->requestFactory + ->createRequest($method, $request->url()->toString()) + ->withBody($this->streamFactory->createStream($request->body())); + + foreach ($request->headers() as $name => $value) { + $psrRequest = $psrRequest->withHeader($name, $value); + } + + return new Psr7ResponseAdapter($this->client->sendRequest($psrRequest)); + } catch (ClientExceptionInterface $exception) { + throw new NchanException( + $exception->getMessage(), + $exception->getCode(), + $exception + ); + } + } +} diff --git a/src/HttpAdapter/Psr7ResponseAdapter.php b/src/HttpAdapter/Psr7ResponseAdapter.php new file mode 100644 index 0000000..be6486c --- /dev/null +++ b/src/HttpAdapter/Psr7ResponseAdapter.php @@ -0,0 +1,28 @@ +response = $response; + } + + public function statusCode(): int + { + return $this->response->getStatusCode(); + } + + public function body(): string + { + return (string)$this->response->getBody(); + } +} diff --git a/tests/Integration/HttpAdapter/ClientTestCase.php b/tests/Integration/HttpAdapter/ClientTestCase.php new file mode 100644 index 0000000..bea35f9 --- /dev/null +++ b/tests/Integration/HttpAdapter/ClientTestCase.php @@ -0,0 +1,110 @@ + 'application/json' + ] + ); + + $client = $this->createClient($request); + + $response = $client->get($request); + + $serverResponse = unserialize($response->body()); + + $this->assertSame(201, $response->statusCode()); + $this->assertSame('application/json', $serverResponse['SERVER']['HTTP_ACCEPT']); + } + + /** + * @test + */ + public function itShouldPerformPostRequest(): void + { + $request = new Request( + new Url(getenv('INTEGRATION_TEST_BASE_URL') . '?statusCode=201'), + [ + 'Accept' => 'application/json', + 'Content-Type' => 'application/x-www-form-urlencoded' + ], + http_build_query( + [ + 'message' => 'my-message-name' + ] + ) + ); + + $client = $this->createClient($request); + + $response = $client->post($request); + + $serverResponse = unserialize($response->body()); + + $this->assertSame(201, $response->statusCode()); + $this->assertSame('application/json', $serverResponse['SERVER']['HTTP_ACCEPT']); + $this->assertSame('my-message-name', $serverResponse['POST']['message']); + } + + /** + * @test + */ + public function itShouldPerformDeleteRequest(): void + { + $request = new Request( + new Url(getenv('INTEGRATION_TEST_BASE_URL') . '?statusCode=201'), + [ + 'Accept' => 'application/json' + ] + ); + + $client = $this->createClient($request); + + $response = $client->delete($request); + + $serverResponse = unserialize($response->body()); + + $this->assertSame(201, $response->statusCode()); + $this->assertSame('application/json', $serverResponse['SERVER']['HTTP_ACCEPT']); + } + + /** + * @test + */ + public function itShouldThrowExceptionOnInvalidResponse(): void + { + $this->expectException(NchanException::class); + + $request = new Request( + new Url(getenv('INTEGRATION_TEST_INVALID_BASE_URL')), + [ + 'Accept' => 'application/json' + ] + ); + + $client = $this->createClient($request); + + $client->get($request); + } +} diff --git a/tests/Integration/HttpAdapter/HttpStreamWrapperClientTest.php b/tests/Integration/HttpAdapter/HttpStreamWrapperClientTest.php index f3a9597..48fc63f 100644 --- a/tests/Integration/HttpAdapter/HttpStreamWrapperClientTest.php +++ b/tests/Integration/HttpAdapter/HttpStreamWrapperClientTest.php @@ -4,126 +4,28 @@ namespace Marein\Nchan\Tests\Integration\HttpAdapter; -use Marein\Nchan\Exception\NchanException; +use Marein\Nchan\Http\Client; use Marein\Nchan\Http\Request; -use Marein\Nchan\Http\Url; use Marein\Nchan\HttpAdapter\Credentials; use Marein\Nchan\HttpAdapter\HttpStreamWrapperClient; -use PHPUnit\Framework\TestCase; -class HttpStreamWrapperClientTest extends TestCase +class HttpStreamWrapperClientTest extends ClientTestCase { - /** - * @test - */ - public function itShouldBeCreatedWithDefaults(): void - { - HttpStreamWrapperClient::withDefaults(); - - $this->assertTrue(true); - } - - /** - * @test - */ - public function itShouldPerformGetRequest(): void + protected function createClient(Request $request): Client { - $request = new Request( - new Url(getenv('INTEGRATION_TEST_BASE_URL') . '?statusCode=201'), - [ - 'Accept' => 'application/json' - ] - ); - $credentials = $this->createMock(Credentials::class); $credentials->expects($this->once())->method('authenticate')->willReturn($request); - $client = new HttpStreamWrapperClient($credentials); - - $response = $client->get($request); - - $serverResponse = unserialize($response->body()); - - $this->assertSame(201, $response->statusCode()); - $this->assertSame('application/json', $serverResponse['SERVER']['HTTP_ACCEPT']); + return new HttpStreamWrapperClient($credentials); } /** * @test */ - public function itShouldPerformPostRequest(): void - { - $request = new Request( - new Url(getenv('INTEGRATION_TEST_BASE_URL') . '?statusCode=201'), - [ - 'Accept' => 'application/json', - 'Content-Type' => 'application/x-www-form-urlencoded' - ], - http_build_query( - [ - 'message' => 'my-message-name' - ] - ) - ); - - $credentials = $this->createMock(Credentials::class); - $credentials->expects($this->once())->method('authenticate')->willReturn($request); - - $client = new HttpStreamWrapperClient($credentials); - - $response = $client->post($request); - - $serverResponse = unserialize($response->body()); - - $this->assertSame(201, $response->statusCode()); - $this->assertSame('application/json', $serverResponse['SERVER']['HTTP_ACCEPT']); - $this->assertSame('my-message-name', $serverResponse['POST']['message']); - } - - /** - * @test - */ - public function itShouldPerformDeleteRequest(): void - { - $request = new Request( - new Url(getenv('INTEGRATION_TEST_BASE_URL') . '?statusCode=201'), - [ - 'Accept' => 'application/json' - ] - ); - - $credentials = $this->createMock(Credentials::class); - $credentials->expects($this->once())->method('authenticate')->willReturn($request); - - $client = new HttpStreamWrapperClient($credentials); - - $response = $client->delete($request); - - $serverResponse = unserialize($response->body()); - - $this->assertSame(201, $response->statusCode()); - $this->assertSame('application/json', $serverResponse['SERVER']['HTTP_ACCEPT']); - } - - /** - * @test - */ - public function itShouldThrowExceptionOnInvalidResponse(): void + public function itShouldBeCreatedWithDefaults(): void { - $this->expectException(NchanException::class); - - $request = new Request( - new Url(getenv('INTEGRATION_TEST_INVALID_BASE_URL')), - [ - 'Accept' => 'application/json' - ] - ); - - $credentials = $this->createMock(Credentials::class); - $credentials->expects($this->once())->method('authenticate')->willReturn($request); - - $client = new HttpStreamWrapperClient($credentials); + HttpStreamWrapperClient::withDefaults(); - $client->get($request); + $this->assertTrue(true); } } diff --git a/tests/Integration/HttpAdapter/Psr18ClientAdapterTest.php b/tests/Integration/HttpAdapter/Psr18ClientAdapterTest.php new file mode 100644 index 0000000..c796a98 --- /dev/null +++ b/tests/Integration/HttpAdapter/Psr18ClientAdapterTest.php @@ -0,0 +1,26 @@ +