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 fb33d5d..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,15 +40,15 @@ jobs:
strategy:
matrix:
- php:
- - 7.2
- - 7.3
- - 7.4
- - 8.0
- - 8.1
- - 8.2
- - 8.3
- - 8.4
+ php:
+ - 7.2
+ - 7.3
+ - 7.4
+ - 8.0
+ - 8.1
+ - 8.2
+ - 8.3
+ - 8.4
steps:
- name: Checkout
@@ -71,6 +71,3 @@ jobs:
- name: Tests
run: composer test
-
- - name: Tests coverage
- run: composer coverage
\ No newline at end of file
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..c13c95b
--- /dev/null
+++ b/.phpstan.neon
@@ -0,0 +1,10 @@
+parameters:
+ reportUnmatchedIgnoredErrors: false
+ inferPrivatePropertyTypeFromConstructor: true
+ level: 8
+ paths:
+ - src
+ - tests
+ ignoreErrors:
+ - "#expects GdImage, resource given#"
+ - "#should return resource but returns#"
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 cabe854..b8d4dfd 100644
--- a/composer.json
+++ b/composer.json
@@ -20,16 +20,17 @@
},
"require": {
"php": "^7.2 || ^8.0",
- "middlewares/utils": "^3.0 || ^4.0",
- "psr/http-server-middleware": "^1.0"
+ "middlewares/utils": "^2 || ^3 || ^4",
+ "psr/http-server-middleware": "^1",
+ "ext-gd": "*"
},
"require-dev": {
- "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"
+ "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": {
@@ -49,4 +50,4 @@
"coverage": "phpunit --coverage-text",
"coverage-html": "phpunit --coverage-html=coverage"
}
-}
+}
\ No newline at end of file
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..76258d7
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,38 @@
+
+
+
+
+ tests
+
+
+
+
+
+ ./src
+
+ ./tests
+ ./vendor
+
+
+
+
+
+
+
+
+
diff --git a/src/ErrorFormatter/AbstractFormatter.php b/src/ErrorFormatter/AbstractFormatter.php
index 775e629..c839fec 100644
--- a/src/ErrorFormatter/AbstractFormatter.php
+++ b/src/ErrorFormatter/AbstractFormatter.php
@@ -23,8 +23,8 @@ abstract class AbstractFormatter implements FormatterInterface
protected $contentTypes = [];
public function __construct(
- ResponseFactoryInterface $responseFactory = null,
- StreamFactoryInterface $streamFactory = null
+ ?ResponseFactoryInterface $responseFactory = null,
+ ?StreamFactoryInterface $streamFactory = null
) {
$this->responseFactory = $responseFactory ?? Factory::getResponseFactory();
$this->streamFactory = $streamFactory ?? Factory::getStreamFactory();
diff --git a/src/ErrorFormatter/ImageFormatter.php b/src/ErrorFormatter/ImageFormatter.php
index cf68400..0072243 100644
--- a/src/ErrorFormatter/ImageFormatter.php
+++ b/src/ErrorFormatter/ImageFormatter.php
@@ -51,9 +51,13 @@ private function createImage(Throwable $error)
$size = 200;
$image = imagecreatetruecolor($size, $size);
$textColor = imagecolorallocate($image, 255, 255, 255);
+
+ /* @phpstan-ignore-next-line */
imagestring($image, 5, 10, 10, "$type $code", $textColor);
+ /* @phpstan-ignore-next-line */
foreach (str_split($message, intval($size / 10)) as $line => $text) {
+ /* @phpstan-ignore-next-line */
imagestring($image, 5, 10, ($line * 18) + 28, $text, $textColor);
}
diff --git a/src/ErrorHandler.php b/src/ErrorHandler.php
index 49f00ef..8d6afd4 100644
--- a/src/ErrorHandler.php
+++ b/src/ErrorHandler.php
@@ -4,6 +4,12 @@
namespace Middlewares;
use Middlewares\ErrorFormatter\FormatterInterface;
+use Middlewares\ErrorFormatter\HtmlFormatter;
+use Middlewares\ErrorFormatter\ImageFormatter;
+use Middlewares\ErrorFormatter\JsonFormatter;
+use Middlewares\ErrorFormatter\PlainFormatter;
+use Middlewares\ErrorFormatter\SvgFormatter;
+use Middlewares\ErrorFormatter\XmlFormatter;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
@@ -20,16 +26,16 @@ class ErrorHandler implements MiddlewareInterface
*
* @param FormatterInterface[] $formatters
*/
- public function __construct(array $formatters = null)
+ public function __construct(?array $formatters = null)
{
if (empty($formatters)) {
$formatters = [
- new ErrorFormatter\PlainFormatter(),
- new ErrorFormatter\HtmlFormatter(),
- new ErrorFormatter\ImageFormatter(),
- new ErrorFormatter\JsonFormatter(),
- new ErrorFormatter\SvgFormatter(),
- new ErrorFormatter\XmlFormatter(),
+ new PlainFormatter(),
+ new HtmlFormatter(),
+ new ImageFormatter(),
+ new JsonFormatter(),
+ new SvgFormatter(),
+ new XmlFormatter(),
];
}
@@ -59,6 +65,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
}
}
+ /** @var FormatterInterface $default */
$default = reset($this->formatters);
return $default->handle($error, $request);
diff --git a/tests/ErrorHandlerTest.php b/tests/ErrorHandlerTest.php
index b5421c8..d250385 100644
--- a/tests/ErrorHandlerTest.php
+++ b/tests/ErrorHandlerTest.php
@@ -4,7 +4,12 @@
namespace Middlewares\Tests;
use Exception;
-use Middlewares\ErrorFormatter;
+use Middlewares\ErrorFormatter\HtmlFormatter;
+use Middlewares\ErrorFormatter\ImageFormatter;
+use Middlewares\ErrorFormatter\JsonFormatter;
+use Middlewares\ErrorFormatter\PlainFormatter;
+use Middlewares\ErrorFormatter\SvgFormatter;
+use Middlewares\ErrorFormatter\XmlFormatter;
use Middlewares\ErrorHandler;
use Middlewares\Utils\Dispatcher;
use Middlewares\Utils\Factory;
@@ -13,7 +18,7 @@
class ErrorHandlerTest extends TestCase
{
- public function testMiddleware()
+ public function testMiddleware(): void
{
$response = Dispatcher::run([
new ErrorHandler(),
@@ -27,7 +32,7 @@ function ($request) {
$this->assertStringContainsString('Something went wrong', (string) $response->getBody());
}
- public function testHttpException()
+ public function testHttpException(): void
{
$response = Dispatcher::run([
new ErrorHandler(),
@@ -39,7 +44,7 @@ function ($request) {
$this->assertEquals(404, $response->getStatusCode());
}
- public function testHttpStatusException()
+ public function testHttpStatusException(): void
{
$response = Dispatcher::run([
new ErrorHandler(),
@@ -56,13 +61,13 @@ public function getStatusCode(): int
$this->assertEquals(418, $response->getStatusCode());
}
- public function testGifFormatter()
+ public function testGifFormatter(): void
{
$request = Factory::createServerRequest('GET', '/');
$request = $request->withheader('Accept', 'image/gif');
$response = Dispatcher::run([
- (new ErrorHandler())->addFormatters(new ErrorFormatter\ImageFormatter()),
+ (new ErrorHandler())->addFormatters(new ImageFormatter()),
function ($request) {
throw new Exception('Something went wrong');
},
@@ -71,13 +76,13 @@ function ($request) {
$this->assertEquals('image/gif', $response->getHeaderLine('Content-Type'));
}
- public function testHtmlFormatter()
+ public function testHtmlFormatter(): void
{
$request = Factory::createServerRequest('GET', '/');
$request = $request->withheader('Accept', 'text/html');
$response = Dispatcher::run([
- (new ErrorHandler())->addFormatters(new ErrorFormatter\HtmlFormatter()),
+ (new ErrorHandler())->addFormatters(new HtmlFormatter()),
function ($request) {
throw new Exception('Something went wrong');
},
@@ -86,13 +91,13 @@ function ($request) {
$this->assertEquals('text/html', $response->getHeaderLine('Content-Type'));
}
- public function testJpegFormatter()
+ public function testJpegFormatter(): void
{
$request = Factory::createServerRequest('GET', '/');
$request = $request->withheader('Accept', 'image/jpeg');
$response = Dispatcher::run([
- (new ErrorHandler())->addFormatters(new ErrorFormatter\ImageFormatter()),
+ (new ErrorHandler())->addFormatters(new ImageFormatter()),
function ($request) {
throw new Exception('Something went wrong');
},
@@ -101,13 +106,13 @@ function ($request) {
$this->assertEquals('image/jpeg', $response->getHeaderLine('Content-Type'));
}
- public function testJsonFormatter()
+ public function testJsonFormatter(): void
{
$request = Factory::createServerRequest('GET', '/');
$request = $request->withheader('Accept', 'application/json');
$response = Dispatcher::run([
- (new ErrorHandler())->addFormatters(new ErrorFormatter\JsonFormatter()),
+ (new ErrorHandler())->addFormatters(new JsonFormatter()),
function ($request) {
throw new Exception('Something went wrong');
},
@@ -116,13 +121,13 @@ function ($request) {
$this->assertEquals('application/json', $response->getHeaderLine('Content-Type'));
}
- public function testPlainFormatter()
+ public function testPlainFormatter(): void
{
$request = Factory::createServerRequest('GET', '/');
$request = $request->withheader('Accept', 'text/plain');
$response = Dispatcher::run([
- (new ErrorHandler())->addFormatters(new ErrorFormatter\PlainFormatter()),
+ (new ErrorHandler())->addFormatters(new PlainFormatter()),
function ($request) {
throw new Exception('Something went wrong');
},
@@ -131,13 +136,13 @@ function ($request) {
$this->assertEquals('text/plain', $response->getHeaderLine('Content-Type'));
}
- public function testPngFormatter()
+ public function testPngFormatter(): void
{
$request = Factory::createServerRequest('GET', '/');
$request = $request->withheader('Accept', 'image/png');
$response = Dispatcher::run([
- (new ErrorHandler())->addFormatters(new ErrorFormatter\ImageFormatter()),
+ (new ErrorHandler())->addFormatters(new ImageFormatter()),
function ($request) {
throw new Exception('Something went wrong');
},
@@ -146,13 +151,13 @@ function ($request) {
$this->assertEquals('image/png', $response->getHeaderLine('Content-Type'));
}
- public function testSvgFormatter()
+ public function testSvgFormatter(): void
{
$request = Factory::createServerRequest('GET', '/');
$request = $request->withheader('Accept', 'image/svg+xml');
$response = Dispatcher::run([
- (new ErrorHandler())->addFormatters(new ErrorFormatter\SvgFormatter()),
+ (new ErrorHandler())->addFormatters(new SvgFormatter()),
function ($request) {
throw new Exception('Something went wrong');
},
@@ -161,13 +166,13 @@ function ($request) {
$this->assertEquals('image/svg+xml', $response->getHeaderLine('Content-Type'));
}
- public function testXmlFormatter()
+ public function testXmlFormatter(): void
{
$request = Factory::createServerRequest('GET', '/');
$request = $request->withheader('Accept', 'text/xml');
$response = Dispatcher::run([
- (new ErrorHandler())->addFormatters(new ErrorFormatter\XmlFormatter()),
+ (new ErrorHandler())->addFormatters(new XmlFormatter()),
function ($request) {
throw new Exception('Something went wrong');
},