Skip to content

Commit

Permalink
Merge branch 'feature/change-formatter-interface'
Browse files Browse the repository at this point in the history
  • Loading branch information
oscarotero committed May 10, 2019
2 parents ec80134 + b1c8c27 commit 244bdf1
Show file tree
Hide file tree
Showing 17 changed files with 183 additions and 197 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ php:
- 7.0
- 7.1
- 7.2
- 7.3

before_script:
- composer install -n
Expand Down
39 changes: 6 additions & 33 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,120 +5,93 @@ 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/).

## [Unreleased]

## [2.0.0] - 2019-05-10
### Added

- Use `phpstan` as a dev dependency to detect bugs

### Changed

- Always catches exceptions
- Create separate classes for error formatters
- Allow any number of formatters to be used
- Allow any exception to define HTTP status code

## [1.2.0] - 2018-08-04
### Removed
- Ability to handle responses with http error codes (400-599). A new package will be created for that. This package only handles exceptions.
- `HttpErrorException` class (that was simply an extension of `Middlewares\Utils\HttpErrorException`). You can use `Middlewares\Utils\HttpErrorException` directly.

## [1.2.0] - 2018-08-04
### Added

- PSR-17 support
- Added a first argument to the constructor of `ErrorHandlerDefault` to customize the `ResponseFactoryInterface`

## [1.1.0] - 2018-06-25

### Changed

- Use `HttpErrorException` from utils package

## [1.0.0] - 2018-01-26

### Added

- Improved testing and added code coverage reporting
- Added tests for PHP 7.2

### Changed

- Upgraded to the final version of PSR-15 `psr/http-server-middleware`

### Fixed

- Updated license year

## [0.9.0] - 2017-12-16

### Changed

- The request handler used to generate the response must implement `Interop\Http\Server\RequestHandlerInterface`. Removed support for callables.

### Removed

- Removed `arguments()` option.

## [0.8.0] - 2017-11-13

### Changed

- Replaced `http-interop/http-middleware` with `http-interop/http-server-middleware`.

### Removed

- Removed support for PHP 5.x.

## [0.7.0] - 2017-09-21

### Changed

- Append `.dist` suffix to phpcs.xml and phpunit.xml files
- Changed the configuration of phpcs and php_cs
- Upgraded phpunit to the latest version and improved its config file
- Updated to `http-interop/http-middleware#0.5`

## [0.6.0] - 2017-03-26

### Changed

- Added `Middlewares\HttpErrorException` class to allow to pass data context to the error handler
- Changed the error handler signature. The attribute `error` contains an instance of `Middlewares\HttpErrorException` instead an array.
- Updated to `middlewares/utils#~0.11`

## [0.5.0] - 2017-02-05

### Changed

- Updated to `middlewares/utils#~0.9`

## [0.4.0] - 2016-12-26

### Changed

- Updated tests
- Updated to `http-interop/http-middleware#0.4`
- Updated `friendsofphp/php-cs-fixer#2.0`

## [0.3.0] - 2016-11-22

### Changed

- Updated to `http-interop/http-middleware#0.3`

## [0.2.0] - 2016-11-19

### Added

- New option `attribute()` to change the attribute name used to pass the error info to the handler.

### Changed

- Changed the handler signature to `function(ServerRequestInterface $request)`.
- The error info is passed to the handler using an array stored in the request attribute `error`.

## 0.1.0 - 2016-10-03

First version

[Unreleased]: https://github.com/middlewares/error-handler/compare/v1.2.0...HEAD
[2.0.0]: https://github.com/middlewares/error-handler/compare/v1.2.0...v2.0.0
[1.2.0]: https://github.com/middlewares/error-handler/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/middlewares/error-handler/compare/v1.0.0...v1.1.0
[1.0.0]: https://github.com/middlewares/error-handler/compare/v0.9.0...v1.0.0
Expand Down
19 changes: 9 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Middleware to catch and format errors encountered while handling the request.

## Requirements

* PHP >= 7.1
* PHP >= 7.0
* A [PSR-7 http library](https://github.com/middlewares/awesome-psr15-middlewares#psr-7-implementations)
* A [PSR-15 middleware dispatcher](https://github.com/middlewares/awesome-psr15-middlewares#dispatcher)

Expand All @@ -31,19 +31,19 @@ use Middlewares\ErrorHandler;
use Middlewares\Utils\Dispatcher;

// Create a new ErrorHandler instance
$errorHandler = new ErrorHandler();

// Any number of formatters can be added. One will be picked based on the Accept
// header of the request. If no formatter matches, the PlainFormatter will be used.
$errorHandler->addFormatters(
$errorHandler = new ErrorHandler([
new ErrorFormatter\GifFormatter(),
new ErrorFormatter\HtmlFormatter(),
new ErrorFormatter\JpegFormatter(),
new ErrorFormatter\JsonFormatter(),
new ErrorFormatter\PngFormatter(),
new ErrorFormatter\SvgFormatter(),
new ErrorFormatter\XmlFormatter(),
);
]);

$errorHandler->defaultFormatter(new ErrorFormatter\PlainFormatter());

// ErrorHandler should always be the first middleware in the stack!
$dispatcher = new Dispatcher([
Expand All @@ -60,14 +60,13 @@ $response = $dispatcher->dispatch($request);

## Options

### `__construct(ResponseFactoryInterface $responseFactory = null, StreamFactoryInterface $streamFactory = null)`

Provide a specific response and stream factory. If not provided, will be detected based on available PSR-17 implementations.
### `__construct(array $formatters [])`

### `addFormatters(FormatterInterface ...$formatters)`
Add the [formatters](src/Formatter) to be used (instances of `Middlewares\ErrorFormatter\FormatterInterface`).

Add additional error [formatters](src/Formatter). Default is `PlainFormatter`.
### `defaultFormatter(FormatterInterface $defaultFormatter)`

Set the default formatter if no content-type matches (by default is `PlainFormatter`).
---

Please see [CHANGELOG](CHANGELOG.md) for more information about recent changes and [CONTRIBUTING](CONTRIBUTING.md) for contributing details.
Expand Down
77 changes: 77 additions & 0 deletions src/ErrorFormatter/AbstractFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php
declare(strict_types = 1);

namespace Middlewares\ErrorFormatter;

use Middlewares\Utils\Factory;
use Middlewares\Utils\HttpErrorException;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;

abstract class AbstractFormatter implements FormatterInterface
{
/** @var ResponseFactoryInterface */
protected $responseFactory;

/** @var StreamFactoryInterface */
protected $streamFactory;

/** @var string[] */
protected $contentTypes = [];

public function __construct(
ResponseFactoryInterface $responseFactory = null,
StreamFactoryInterface $streamFactory = null
) {
$this->responseFactory = $responseFactory ?? Factory::getResponseFactory();
$this->streamFactory = $streamFactory ?? Factory::getStreamFactory();
}

public function isValid(Throwable $error, ServerRequestInterface $request): bool
{
return $this->getContentType($request) ? true : false;
}

abstract protected function format(Throwable $error): string;

public function handle(Throwable $error, ServerRequestInterface $request): ResponseInterface
{
$response = $this->responseFactory->createResponse($this->errorStatus($error));
$body = $this->streamFactory->createStream($this->format($error));
$response = $response->withBody($body);

$contentType = $this->getContentType($request);

return $response->withHeader('Content-Type', $contentType ? $contentType : $this->contentTypes[0]);
}

protected function errorStatus(Throwable $error): int
{
if ($error instanceof HttpErrorException) {
return $error->getCode();
}

if (method_exists($error, 'getStatusCode')) {
return $error->getStatusCode();
}

return 500;
}

/**
* @return string|null
*/
protected function getContentType(ServerRequestInterface $request)
{
$accept = $request->getHeaderLine('Accept');

foreach ($this->contentTypes as $type) {
if (stripos($accept, $type) !== false) {
return $type;
}
}
}
}
4 changes: 2 additions & 2 deletions src/ErrorFormatter/AbstractImageFormatter.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?php
declare(strict_types=1);
declare(strict_types = 1);

namespace Middlewares\ErrorFormatter;

use Throwable;

abstract class AbstractImageFormatter implements FormatterInterface
abstract class AbstractImageFormatter extends AbstractFormatter
{
/**
* Create an image resource from an error
Expand Down
14 changes: 7 additions & 7 deletions src/ErrorFormatter/FormatterInterface.php
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
<?php
declare(strict_types=1);
declare(strict_types = 1);

namespace Middlewares\ErrorFormatter;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;

interface FormatterInterface
{
/**
* Get supported content types
*
* @return string[]
* Check whether the error can be handled by this formatter
*/
public function contentTypes(): array;
public function isValid(Throwable $error, ServerRequestInterface $request): bool;

/**
* Format an error as a string
* Create a response with this error
*/
public function format(Throwable $error): string;
public function handle(Throwable $error, ServerRequestInterface $request): ResponseInterface;
}
15 changes: 6 additions & 9 deletions src/ErrorFormatter/GifFormatter.php
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
<?php
declare(strict_types=1);
declare(strict_types = 1);

namespace Middlewares\ErrorFormatter;

use Throwable;

class GifFormatter extends AbstractImageFormatter
{
public function contentTypes(): array
{
return [
'image/gif',
];
}
protected $contentTypes = [
'image/gif',
];

public function format(Throwable $error): string
protected function format(Throwable $error): string
{
ob_start();
imagegif($this->createImage($error));
return ob_get_clean();
return (string) ob_get_clean();
}
}
15 changes: 6 additions & 9 deletions src/ErrorFormatter/HtmlFormatter.php
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
<?php
declare(strict_types=1);
declare(strict_types = 1);

namespace Middlewares\ErrorFormatter;

use Throwable;

class HtmlFormatter implements FormatterInterface
class HtmlFormatter extends AbstractFormatter
{
public function contentTypes(): array
{
return [
'text/html',
];
}
protected $contentTypes = [
'text/html',
];

public function format(Throwable $error): string
protected function format(Throwable $error): string
{
$type = get_class($error);
$code = $error->getCode();
Expand Down
15 changes: 6 additions & 9 deletions src/ErrorFormatter/JpegFormatter.php
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
<?php
declare(strict_types=1);
declare(strict_types = 1);

namespace Middlewares\ErrorFormatter;

use Throwable;

class JpegFormatter extends AbstractImageFormatter
{
public function contentTypes(): array
{
return [
'image/jpeg',
];
}
protected $contentTypes = [
'image/jpeg',
];

public function format(Throwable $error): string
protected function format(Throwable $error): string
{
ob_start();
imagejpeg($this->createImage($error));
return ob_get_clean();
return (string) ob_get_clean();
}
}
Loading

0 comments on commit 244bdf1

Please sign in to comment.