From c47cc9f39521d7d7ca389c9873be1a190e7fb607 Mon Sep 17 00:00:00 2001 From: Thomas Rieschl Date: Sat, 11 Jan 2025 14:15:37 +0100 Subject: [PATCH 1/2] Refresh Package * Require PHP 8.2 * upgrade code quality tools * remove thecodingmachine/safe * switch from PHPCS to PHP-CS-Fixer and fix CS issues * use setup-php in GitHub CI --- .github/workflows/checks.yml | 38 +++--- .gitignore | 3 +- .php-cs-fixer.dist.php | 7 ++ CHANGELOG.md | 117 +----------------- composer.json | 53 ++++---- infection.json | 4 +- phpunit.xml | 5 +- psalm.xml | 7 +- src/MezzioTestEnvironment.php | 34 +++-- src/TestConfigProvider.php | 4 +- src/Util.php | 9 +- tests/config/container.php | 14 ++- tests/config/routes.php | 4 +- .../functional/MezzioTestEnvironmentTest.php | 17 +-- tests/functional/ReflectionUtil.php | 7 +- tests/functional/TestConfigProviderTest.php | 8 +- .../TestDouble/RequestLoggerCallback.php | 2 +- 17 files changed, 127 insertions(+), 206 deletions(-) create mode 100644 .php-cs-fixer.dist.php diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 3dbbb9a..3d9c7cd 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -7,27 +7,30 @@ jobs: strategy: matrix: - php: ["7.4", "8.0", "8.1"] + php: ["8.2", "8.3"] composer_args: - '--prefer-lowest' - '' runs-on: ubuntu-latest - container: - image: eventjet/checks-${{ matrix.php }}:latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: pcov + tools: composer:v2 - name: Prepare environment run: | - mkdir -p /root/.ssh - ssh-keyscan -t rsa github.com >> /root/.ssh/known_hosts echo "COMPOSER_CACHE=$(composer config cache-dir)" >> $GITHUB_ENV - name: Composer Cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ${{ env.COMPOSER_CACHE }} @@ -38,12 +41,17 @@ jobs: run: | composer update --no-progress --no-interaction ${{ matrix.composer_args }} > /dev/null - - name: Static analysis - run: | - composer check-deps - composer cs-check - composer phpstan -- --no-progress - composer psalm + - name: Check Dependencies + run: composer check-deps + + - name: Check Code Style + run: PHP_CS_FIXER_IGNORE_ENV=1 composer cs-check + + - name: PHPStan + run: composer phpstan -- --no-progress + + - name: Psalm + run: composer psalm - name: Tests run: | @@ -51,10 +59,10 @@ jobs: composer run --timeout=0 infection - name: Save Infection result - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: - name: infection-log-${{ matrix.php }}.txt + name: infection-log-${{ matrix.php }}-${{ matrix.composer_args }}.txt path: infection-log.txt - name: Monitor coverage diff --git a/.gitignore b/.gitignore index 07058c9..e69cbe7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ -/vendor/ /composer.lock /infection-log.txt +/.php-cs-fixer.cache +/vendor/ .phpunit.result.cache diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000..63b921e --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,7 @@ + @@ -14,9 +13,9 @@ tests/functional - + src - + diff --git a/psalm.xml b/psalm.xml index 92827db..edc2b2a 100644 --- a/psalm.xml +++ b/psalm.xml @@ -1,10 +1,13 @@ diff --git a/src/MezzioTestEnvironment.php b/src/MezzioTestEnvironment.php index 2185cb6..e0ebdbc 100644 --- a/src/MezzioTestEnvironment.php +++ b/src/MezzioTestEnvironment.php @@ -20,20 +20,22 @@ use Psr\Http\Message\UriInterface; use Throwable; +use function chdir; use function count; +use function putenv; final class MezzioTestEnvironment { - private ?ContainerInterface $container = null; - private ?Application $app = null; + private ContainerInterface|null $container = null; + private Application|null $app = null; private string $basePath; - public function __construct(?string $basePath = null) + public function __construct(string|null $basePath = null) { - \Safe\putenv('APP_TESTING=true'); + putenv('APP_TESTING=true'); $this->basePath = $basePath ?? Util::basePath(); $this->basePath = Util::ensureTrailingSlash($this->basePath); - \Safe\chdir($this->basePath); + chdir($this->basePath); $this->app(); // initialize App for routes to be populated $this->registerErrorListener(); } @@ -45,9 +47,9 @@ public function __construct(?string $basePath = null) */ public function dispatch( $uri, - ?string $method = null, + string|null $method = null, array $params = [], - array $headers = [] + array $headers = [], ): ResponseInterface { if ($method === null) { $method = RequestMethodInterface::METHOD_GET; @@ -81,9 +83,9 @@ public function dispatch( public function dispatchRoute( string $routeName, array $routeParams = [], - ?string $method = null, + string|null $method = null, array $requestParams = [], - array $headers = [] + array $headers = [], ): ResponseInterface { $router = $this->router(); $route = $router->generateUri($routeName, $routeParams); @@ -103,7 +105,9 @@ public function container(): ContainerInterface if ($this->container !== null) { return $this->container; } - $this->container = require $this->basePath . 'config/container.php'; + /** @var ContainerInterface $container */ + $container = require $this->basePath . 'config/container.php'; + $this->container = $container; return $this->container; } @@ -121,7 +125,7 @@ private function registerErrorListener(): void $errorHandler->attachListener( static function (Throwable $error): void { throw $error; - } + }, ); } @@ -136,8 +140,12 @@ private function app(): Application $this->app = $this->container()->get(Application::class); $factory = $this->container()->get(MiddlewareFactory::class); - (require $this->basePath . 'config/pipeline.php')($this->app, $factory, $this->container()); - (require $this->basePath . 'config/routes.php')($this->app, $factory, $this->container()); + /** @var callable $pipeline */ + $pipeline = require $this->basePath . 'config/pipeline.php'; + $pipeline($this->app, $factory, $this->container()); + /** @var callable $routes */ + $routes = require $this->basePath . 'config/routes.php'; + $routes($this->app, $factory, $this->container()); return $this->app; } } diff --git a/src/TestConfigProvider.php b/src/TestConfigProvider.php index c7d0b0e..2979c33 100644 --- a/src/TestConfigProvider.php +++ b/src/TestConfigProvider.php @@ -13,7 +13,7 @@ final class TestConfigProvider /** * @return list */ - public static function load(?string $configDir = null): array + public static function load(string|null $configDir = null): array { if (!self::isTesting()) { return []; @@ -32,7 +32,7 @@ private static function isTesting(): bool return $testing !== false; } - private static function prepareConfigDir(?string $configDir): string + private static function prepareConfigDir(string|null $configDir): string { if ($configDir === null) { return Util::basePath() . 'config/autoload/'; diff --git a/src/Util.php b/src/Util.php index d7205f2..152d3b0 100644 --- a/src/Util.php +++ b/src/Util.php @@ -9,6 +9,7 @@ use function dirname; use function file_exists; +use function realpath; use function strlen; use function trim; @@ -16,13 +17,13 @@ final class Util { public static function basePath(): string { - $path = \Safe\realpath(dirname(__DIR__)); - if (file_exists($path . '/vendor')) { + $path = realpath(dirname(__DIR__)); + if ($path !== false && file_exists($path . '/vendor')) { return self::ensureTrailingSlash($path); } // @codeCoverageIgnoreStart - $path = \Safe\realpath(dirname(__DIR__, 4)); - if (file_exists($path . '/vendor')) { + $path = realpath(dirname(__DIR__, 4)); + if ($path !== false && file_exists($path . '/vendor')) { return self::ensureTrailingSlash($path); } throw new RuntimeException('Could not find base path.'); diff --git a/tests/config/container.php b/tests/config/container.php index 5109c1b..ed4b51d 100644 --- a/tests/config/container.php +++ b/tests/config/container.php @@ -4,11 +4,21 @@ use Laminas\ServiceManager\ServiceManager; -// Load configuration +/** @var array{ + * dependencies: array{ + * aliases: array, + * factories: array, + * services: array|object>, + * } + * } $config + */ $config = require __DIR__ . '/config.php'; $dependencies = $config['dependencies']; $dependencies['services']['config'] = $config; -// Build container +/** + * @psalm-suppress ArgumentTypeCoercion unnecessary complicated + * @phpstan-ignore-next-line argument.type unnecessary complicated + */ return new ServiceManager($dependencies); diff --git a/tests/config/routes.php b/tests/config/routes.php index 26be42c..8971e0c 100644 --- a/tests/config/routes.php +++ b/tests/config/routes.php @@ -11,13 +11,13 @@ static function (): TextResponse { return new TextResponse('Hi'); }, - 'home' + 'home', ); $app->get( '/error', static function (): void { throw new LogicException('I have an error'); }, - 'error' + 'error', ); }; diff --git a/tests/functional/MezzioTestEnvironmentTest.php b/tests/functional/MezzioTestEnvironmentTest.php index 60bf960..bf9e1e7 100644 --- a/tests/functional/MezzioTestEnvironmentTest.php +++ b/tests/functional/MezzioTestEnvironmentTest.php @@ -20,13 +20,6 @@ class MezzioTestEnvironmentTest extends TestCase { private MezzioTestEnvironment $mezzio; - protected function setUp(): void - { - parent::setUp(); - $basePath = dirname(__DIR__); - $this->mezzio = new MezzioTestEnvironment($basePath); - } - public function testDispatch(): void { $result = $this->mezzio->dispatch('/'); @@ -82,6 +75,7 @@ public function testDispatchParamsArePassedToQueryForGetRequest(): void $params = ['foo' => 'bar']; $this->mezzio->dispatch('/', null, $params); + /** @var RequestLoggerCallback $logger */ $request = $logger->getRequest(); self::assertSame($request->getQueryParams(), $params); } @@ -96,6 +90,7 @@ public function testDispatchParamsArePassedToParsedBodyForPostRequest(): void $params = ['foo' => 'bar']; $this->mezzio->dispatch('/', RequestMethodInterface::METHOD_POST, $params); + /** @var RequestLoggerCallback $logger */ $request = $logger->getRequest(); self::assertSame($request->getParsedBody(), $params); } @@ -116,6 +111,7 @@ public function testDispatchHeadersArePassedToRequest(): void ], ]; + /** @var RequestLoggerCallback $logger */ $request = $logger->getRequest(); self::assertSame($request->getHeaders(), $expected); } @@ -127,4 +123,11 @@ public function testCustomErrorHandlerRethrowsException(): void $this->mezzio->dispatch('/error'); } + + protected function setUp(): void + { + parent::setUp(); + $basePath = dirname(__DIR__); + $this->mezzio = new MezzioTestEnvironment($basePath); + } } diff --git a/tests/functional/ReflectionUtil.php b/tests/functional/ReflectionUtil.php index e5ffd5f..22ecedb 100644 --- a/tests/functional/ReflectionUtil.php +++ b/tests/functional/ReflectionUtil.php @@ -15,10 +15,7 @@ final class ReflectionUtil public static function getReflectionProperty(object $object, string $property) { $reflectionProperty = (new ReflectionObject($object))->getProperty($property); - $reflectionProperty->setAccessible(true); - $value = $reflectionProperty->getValue($object); - $reflectionProperty->setAccessible(false); - return $value; + return $reflectionProperty->getValue($object); } /** @@ -28,8 +25,6 @@ public static function getReflectionProperty(object $object, string $property) public static function setReflectionProperty(object $object, string $property, $value): void { $reflectionProperty = (new ReflectionObject($object))->getProperty($property); - $reflectionProperty->setAccessible(true); $reflectionProperty->setValue($object, $value); - $reflectionProperty->setAccessible(false); } } diff --git a/tests/functional/TestConfigProviderTest.php b/tests/functional/TestConfigProviderTest.php index ff4fd7a..7184ae4 100644 --- a/tests/functional/TestConfigProviderTest.php +++ b/tests/functional/TestConfigProviderTest.php @@ -7,11 +7,13 @@ use PHPUnit\Framework\TestCase; use Trinet\MezzioTest\TestConfigProvider; +use function putenv; + class TestConfigProviderTest extends TestCase { public function testReturnsEmptyArrayWhenNotInTestingEnvironment(): void { - \Safe\putenv('APP_TESTING'); + putenv('APP_TESTING'); $result = TestConfigProvider::load(); @@ -20,7 +22,7 @@ public function testReturnsEmptyArrayWhenNotInTestingEnvironment(): void public function testAdditionalFileProvidersAreReturnedWhenTesting(): void { - \Safe\putenv('APP_TESTING=true'); + putenv('APP_TESTING=true'); $result = TestConfigProvider::load(); @@ -29,7 +31,7 @@ public function testAdditionalFileProvidersAreReturnedWhenTesting(): void public function testCustomConfigPath(): void { - \Safe\putenv('APP_TESTING=true'); + putenv('APP_TESTING=true'); $path = 'my/special/config'; $result = TestConfigProvider::load($path); diff --git a/tests/functional/TestDouble/RequestLoggerCallback.php b/tests/functional/TestDouble/RequestLoggerCallback.php index e3b2f3a..3cfeaea 100644 --- a/tests/functional/TestDouble/RequestLoggerCallback.php +++ b/tests/functional/TestDouble/RequestLoggerCallback.php @@ -11,7 +11,7 @@ final class RequestLoggerCallback { - private ?ServerRequestInterface $request = null; + private ServerRequestInterface|null $request = null; public function __invoke(ServerRequestInterface $request): ResponseInterface { From 74ea9d26f1161f25168399d49c4b7d9f43472350 Mon Sep 17 00:00:00 2001 From: Thomas Rieschl Date: Sat, 11 Jan 2025 14:31:58 +0100 Subject: [PATCH 2/2] * allow laminas/laminas-diactoros ^3 --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index aa3fe0d..bb367d1 100644 --- a/composer.json +++ b/composer.json @@ -7,12 +7,12 @@ "php": "^8.2", "fig/http-message-util": "^1.1", "laminas/laminas-config-aggregator": "^1.2", - "laminas/laminas-diactoros": "^2.2", + "laminas/laminas-diactoros": "^2.2 || ^3.5", "laminas/laminas-stratigility": "^3.2", "mezzio/mezzio": "^3.2", "mezzio/mezzio-router": "^3.1", "psr/container": "^1.0 || ^2.0", - "psr/http-message": "^1.0" + "psr/http-message": "^1.0 || ^2.0" }, "require-dev": { "bnf/phpstan-psr-container": "^1.1",