diff --git a/.gitattributes b/.gitattributes index c540470..b67c7ca 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,10 +1,10 @@ * text=auto eol=lf -/tests export-ignore -.editorconfig export-ignore -.gitattributes export-ignore -.gitignore export-ignore -.php_cs export-ignore -.travis.yml export-ignore -phpcs.xml.dist export-ignore -phpunit.xml.dist export-ignore +/tests export-ignore +.editorconfig export-ignore +.gitattributes export-ignore +.gitignore export-ignore +.php-cs-fixer.php export-ignore +phpcs.xml.dist export-ignore +phpunit.xml.dist export-ignore +.phpstan.neon export-ignore diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 327717c..5d14a59 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -1,10 +1,10 @@ name: "testing" on: - push: - branches: [ master ] - pull_request: - branches: [ master ] + push: + branches: [ master ] + pull_request: + branches: [ master ] jobs: qa: @@ -13,19 +13,19 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Validate composer.json and composer.lock run: composer validate - name: Cache Composer packages id: composer-cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: - path: vendor - key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} - restore-keys: | - ${{ runner.os }}-php- + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- - name: Install dependencies if: steps.composer-cache.outputs.cache-hit != 'true' @@ -40,19 +40,19 @@ jobs: strategy: matrix: - php: - - 7.2 - - 7.3 - - 7.4 - composer-args: [ "" ] - include: - - php: 8.0 - composer-args: --ignore-platform-reqs - fail-fast: false + php: + - 7.2 + - 7.3 + - 7.4 + - 8.0 + - 8.1 + - 8.2 + - 8.3 + - 8.4 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install PHP uses: shivammathur/setup-php@v2 @@ -60,17 +60,14 @@ jobs: php-version: ${{ matrix.php }} - name: Cache PHP dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: vendor key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }} restore-keys: ${{ runner.os }}-php-${{ matrix.php }}-composer- - name: Install dependencies - run: composer install --prefer-dist --no-progress ${{ matrix.composer-args }} + run: composer install --prefer-dist --no-progress - name: Tests run: composer test - - - name: Tests coverage - run: composer coverage diff --git a/.gitignore b/.gitignore index 364d1a4..5ae8693 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ vendor composer.lock coverage *.cache +.idea +kit diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php new file mode 100644 index 0000000..90b12a3 --- /dev/null +++ b/.php-cs-fixer.php @@ -0,0 +1,10 @@ +setFinder( + PhpCsFixer\Finder::create() + ->files() + ->name('*.php') + ->in(__DIR__.'/src') + ->in(__DIR__.'/tests') + ); \ No newline at end of file diff --git a/.phpstan.neon b/.phpstan.neon new file mode 100644 index 0000000..7f33c04 --- /dev/null +++ b/.phpstan.neon @@ -0,0 +1,5 @@ +parameters: + level: 8 + paths: + - src + - tests diff --git a/CHANGELOG.md b/CHANGELOG.md index bfa289f..5c48dd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [2.1.0] - 2025-03-21 +### Added +- Support for PHP 8.4 + ## [2.0.0] - 2020-12-03 ### Added - Support for PHP 8 @@ -50,6 +54,7 @@ First version [#2]: https://github.com/middlewares/proxy/issues/2 +[2.1.0]: https://github.com/middlewares/proxy/compare/v2.0.0...v2.1.0 [2.0.0]: https://github.com/middlewares/proxy/compare/v1.1.1...v2.0.0 [1.1.1]: https://github.com/middlewares/proxy/compare/v1.1.0...v1.1.1 [1.1.0]: https://github.com/middlewares/proxy/compare/v1.0.0...v1.1.0 diff --git a/LICENSE b/LICENSE index 017c0cd..374fb13 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2019 +Copyright (c) 2019-2025 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/composer.json b/composer.json index 3ab05f1..9b1db27 100644 --- a/composer.json +++ b/composer.json @@ -16,17 +16,17 @@ }, "require": { "php": "^7.2 || ^8.0", - "guzzlehttp/guzzle": "^6.2", - "psr/http-server-middleware": "^1.0" + "guzzlehttp/guzzle": "^6 || ^7", + "psr/http-server-middleware": "^1" }, "require-dev": { - "middlewares/utils": "^3.0", - "phpunit/phpunit": "^8|^9", - "friendsofphp/php-cs-fixer": "^2.0", - "squizlabs/php_codesniffer": "^3.0", - "oscarotero/php-cs-fixer-config": "^1.0", - "phpstan/phpstan": "^0.12", - "laminas/laminas-diactoros": "^2.3" + "middlewares/utils": "^2 || ^3 || ^4", + "phpunit/phpunit": "^8 || ^9", + "friendsofphp/php-cs-fixer": "^3", + "squizlabs/php_codesniffer": "^3", + "oscarotero/php-cs-fixer-config": "^2", + "phpstan/phpstan": "^1 || ^2", + "laminas/laminas-diactoros": "^2 || ^3" }, "autoload": { "psr-4": { diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..7814331 --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,16 @@ + + + Middlewares coding standard + + + + + + + + + + + src + tests + diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..c2d04d2 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,33 @@ + + + + + tests + + + + + + ./src + + ./tests + ./vendor + + + + diff --git a/src/Proxy.php b/src/Proxy.php index f332aa7..f9f7b14 100644 --- a/src/Proxy.php +++ b/src/Proxy.php @@ -12,6 +12,7 @@ use Psr\Http\Message\UriInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; +use RuntimeException; class Proxy implements MiddlewareInterface { @@ -26,7 +27,7 @@ class Proxy implements MiddlewareInterface private $client; /** - * @var array + * @var array */ private $options = []; @@ -50,6 +51,8 @@ public function client(ClientInterface $client): self /** * Set the client options + * + * @param array $options */ public function options(array $options): self { @@ -89,10 +92,12 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $detachedBody = $response->getBody()->detach(); - if (null !== $detachedBody) { - $response = $response->withBody(new Stream($detachedBody)); - - return $response; + if ($detachedBody === null) { + throw new RuntimeException('Detached body is empty.'); } + + $response = $response->withBody(new Stream($detachedBody)); + + return $response; } } diff --git a/tests/ProxyTest.php b/tests/ProxyTest.php index 5f6dcf6..49b3287 100644 --- a/tests/ProxyTest.php +++ b/tests/ProxyTest.php @@ -9,10 +9,13 @@ use Middlewares\Utils\Dispatcher; use Middlewares\Utils\Factory; use PHPUnit\Framework\TestCase; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamInterface; +use RuntimeException; class ProxyTest extends TestCase { - public function testProxy() + public function testProxy(): void { $response = Dispatcher::run( [ @@ -27,7 +30,7 @@ public function testProxy() $this->assertNotFalse(stripos($html, 'middlewares/psr15-middlewares')); } - public function testOptionsAndClient() + public function testOptionsAndClient(): void { $received = false; $response = Dispatcher::run( @@ -50,7 +53,7 @@ public function testOptionsAndClient() $this->assertTrue($received); } - public function testError() + public function testError(): void { $response = Dispatcher::run( [ @@ -64,7 +67,7 @@ public function testError() $this->assertEquals(404, $response->getStatusCode()); } - public function testTargetPath() + public function testTargetPath(): void { $response = Dispatcher::run( [ @@ -85,7 +88,7 @@ public function testTargetPath() * * @see https://github.com/middlewares/proxy/issues/1 */ - public function testRethrowsExceptionIfNoResponse() + public function testRethrowsExceptionIfNoResponse(): void { $client = $this->createMock(Client::class); $request = Factory::createServerRequest('GET', 'http://example.com/middlewares/psr15-middlewares'); @@ -101,4 +104,27 @@ public function testRethrowsExceptionIfNoResponse() $request ); } + + public function testWhenDettachedBodyIsEmptyThrowsAnException(): void + { + $client = $this->createMock(Client::class); + $request = Factory::createServerRequest('GET', 'http://example.com/middlewares/psr15-middlewares'); + + $stream = $this->createMock(StreamInterface::class); + $stream->method('detach')->willReturn(null); + + $response = $this->createMock(ResponseInterface::class); + $response->method('getBody')->willReturn($stream); + + $client->method('send')->willReturn($response); + + $this->expectException(RuntimeException::class); + + Dispatcher::run( + [ + (new Proxy(Factory::createUri('https://github.com')))->client($client), + ], + $request + ); + } }