├── .github └── workflows │ └── main.yaml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── composer.json └── src ├── ErrorFormatter ├── AbstractFormatter.php ├── FormatterInterface.php ├── HtmlFormatter.php ├── ImageFormatter.php ├── JsonFormatter.php ├── PlainFormatter.php ├── SvgFormatter.php └── XmlFormatter.php └── ErrorHandler.php /.github/workflows/main.yaml: -------------------------------------------------------------------------------- 1 | name: "testing" 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | qa: 11 | name: Quality assurance 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | 18 | - name: Validate composer.json and composer.lock 19 | run: composer validate 20 | 21 | - name: Cache Composer packages 22 | id: composer-cache 23 | uses: actions/cache@v4 24 | with: 25 | path: vendor 26 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} 27 | restore-keys: | 28 | ${{ runner.os }}-php- 29 | 30 | - name: Install dependencies 31 | if: steps.composer-cache.outputs.cache-hit != 'true' 32 | run: composer install --prefer-dist --no-progress 33 | 34 | - name: Coding Standard 35 | run: composer run-script cs 36 | 37 | tests: 38 | name: Tests 39 | runs-on: ubuntu-latest 40 | 41 | strategy: 42 | matrix: 43 | php: 44 | - 7.2 45 | - 7.3 46 | - 7.4 47 | - 8.0 48 | - 8.1 49 | - 8.2 50 | - 8.3 51 | - 8.4 52 | 53 | steps: 54 | - name: Checkout 55 | uses: actions/checkout@v4 56 | 57 | - name: Install PHP 58 | uses: shivammathur/setup-php@v2 59 | with: 60 | php-version: ${{ matrix.php }} 61 | 62 | - name: Cache PHP dependencies 63 | uses: actions/cache@v4 64 | with: 65 | path: vendor 66 | key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }} 67 | restore-keys: ${{ runner.os }}-php-${{ matrix.php }}-composer- 68 | 69 | - name: Install dependencies 70 | run: composer install --prefer-dist --no-progress 71 | 72 | - name: Tests 73 | run: composer test 74 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | ## [3.1.0] - 2025-03-21 8 | ### Fixed 9 | - Support for PHP typing. 10 | 11 | ## [3.0.2] - 2024-12-05 12 | ### Fixed 13 | - Support for PHP 8.4 14 | 15 | ## [3.0.1] - 2020-12-03 16 | ### Added 17 | - Support for PHP 8.0 18 | 19 | ## [3.0.0] - 2019-11-29 20 | ### Added 21 | - Support for webp responses under the `ImageFormatter` error handler 22 | - Additional XML content types [#9] 23 | 24 | ### Changed 25 | - Merged `JpegFormatter`, `GifFormatter` and `PngFormatter` in one `ImageFormatter`. 26 | - By default, all formatters are used. 27 | 28 | ### Removed 29 | - Support for PHP 7.0 and 7.1 30 | - `defaultFormatter` option. De first value of the array of formatters will be used as default 31 | 32 | ## [2.0.0] - 2019-05-10 33 | ### Added 34 | - Use `phpstan` as a dev dependency to detect bugs 35 | 36 | ### Changed 37 | - Always catches exceptions 38 | - Create separate classes for error formatters 39 | - Allow any number of formatters to be used 40 | - Allow any exception to define HTTP status code 41 | 42 | ### Removed 43 | - Ability to handle responses with http error codes (400-599). A new package will be created for that. This package only handles exceptions. 44 | - `HttpErrorException` class (that was simply an extension of `Middlewares\Utils\HttpErrorException`). You can use `Middlewares\Utils\HttpErrorException` directly. 45 | 46 | ## [1.2.0] - 2018-08-04 47 | ### Added 48 | - PSR-17 support 49 | - Added a first argument to the constructor of `ErrorHandlerDefault` to customize the `ResponseFactoryInterface` 50 | 51 | ## [1.1.0] - 2018-06-25 52 | ### Changed 53 | - Use `HttpErrorException` from utils package 54 | 55 | ## [1.0.0] - 2018-01-26 56 | ### Added 57 | - Improved testing and added code coverage reporting 58 | - Added tests for PHP 7.2 59 | 60 | ### Changed 61 | - Upgraded to the final version of PSR-15 `psr/http-server-middleware` 62 | 63 | ### Fixed 64 | - Updated license year 65 | 66 | ## [0.9.0] - 2017-12-16 67 | ### Changed 68 | - The request handler used to generate the response must implement `Interop\Http\Server\RequestHandlerInterface`. Removed support for callables. 69 | 70 | ### Removed 71 | - Removed `arguments()` option. 72 | 73 | ## [0.8.0] - 2017-11-13 74 | ### Changed 75 | - Replaced `http-interop/http-middleware` with `http-interop/http-server-middleware`. 76 | 77 | ### Removed 78 | - Removed support for PHP 5.x. 79 | 80 | ## [0.7.0] - 2017-09-21 81 | ### Changed 82 | - Append `.dist` suffix to phpcs.xml and phpunit.xml files 83 | - Changed the configuration of phpcs and php_cs 84 | - Upgraded phpunit to the latest version and improved its config file 85 | - Updated to `http-interop/http-middleware#0.5` 86 | 87 | ## [0.6.0] - 2017-03-26 88 | ### Changed 89 | - Added `Middlewares\HttpErrorException` class to allow to pass data context to the error handler 90 | - Changed the error handler signature. The attribute `error` contains an instance of `Middlewares\HttpErrorException` instead an array. 91 | - Updated to `middlewares/utils#~0.11` 92 | 93 | ## [0.5.0] - 2017-02-05 94 | ### Changed 95 | - Updated to `middlewares/utils#~0.9` 96 | 97 | ## [0.4.0] - 2016-12-26 98 | ### Changed 99 | - Updated tests 100 | - Updated to `http-interop/http-middleware#0.4` 101 | - Updated `friendsofphp/php-cs-fixer#2.0` 102 | 103 | ## [0.3.0] - 2016-11-22 104 | ### Changed 105 | - Updated to `http-interop/http-middleware#0.3` 106 | 107 | ## [0.2.0] - 2016-11-19 108 | ### Added 109 | - New option `attribute()` to change the attribute name used to pass the error info to the handler. 110 | 111 | ### Changed 112 | - Changed the handler signature to `function(ServerRequestInterface $request)`. 113 | - The error info is passed to the handler using an array stored in the request attribute `error`. 114 | 115 | ## [0.1.0] - 2016-10-03 116 | First version 117 | 118 | [#9]: https://github.com/middlewares/error-handler/issues/9 119 | 120 | [3.1.0]: https://github.com/middlewares/error-handler/compare/v3.0.2...v3.1.0 121 | [3.0.2]: https://github.com/middlewares/error-handler/compare/v3.0.1...v3.0.2 122 | [3.0.1]: https://github.com/middlewares/error-handler/compare/v3.0.0...v3.0.1 123 | [3.0.0]: https://github.com/middlewares/error-handler/compare/v2.0.0...v3.0.0 124 | [2.0.0]: https://github.com/middlewares/error-handler/compare/v1.2.0...v2.0.0 125 | [1.2.0]: https://github.com/middlewares/error-handler/compare/v1.1.0...v1.2.0 126 | [1.1.0]: https://github.com/middlewares/error-handler/compare/v1.0.0...v1.1.0 127 | [1.0.0]: https://github.com/middlewares/error-handler/compare/v0.9.0...v1.0.0 128 | [0.9.0]: https://github.com/middlewares/error-handler/compare/v0.8.0...v0.9.0 129 | [0.8.0]: https://github.com/middlewares/error-handler/compare/v0.7.0...v0.8.0 130 | [0.7.0]: https://github.com/middlewares/error-handler/compare/v0.6.0...v0.7.0 131 | [0.6.0]: https://github.com/middlewares/error-handler/compare/v0.5.0...v0.6.0 132 | [0.5.0]: https://github.com/middlewares/error-handler/compare/v0.4.0...v0.5.0 133 | [0.4.0]: https://github.com/middlewares/error-handler/compare/v0.3.0...v0.4.0 134 | [0.3.0]: https://github.com/middlewares/error-handler/compare/v0.2.0...v0.3.0 135 | [0.2.0]: https://github.com/middlewares/error-handler/compare/v0.1.0...v0.2.0 136 | [0.1.0]: https://github.com/middlewares/error-handler/releases/tag/v0.1.0 137 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guide 2 | 3 | This project adheres to [The Code Manifesto](http://codemanifesto.com) as its guidelines for contributor interactions. 4 | 5 | ## The Code Manifesto 6 | 7 | We want to work in an ecosystem that empowers developers to reach their potential--one that encourages growth and effective collaboration. A space that is safe for all. 8 | 9 | A space such as this benefits everyone that participates in it. It encourages new developers to enter our field. It is through discussion and collaboration that we grow, and through growth that we improve. 10 | 11 | In the effort to create such a place, we hold to these values: 12 | 13 | 1. **Discrimination limits us.** This includes discrimination on the basis of race, gender, sexual orientation, gender identity, age, nationality, technology and any other arbitrary exclusion of a group of people. 14 | 2. **Boundaries honor us.** Your comfort levels are not everyone’s comfort levels. Remember that, and if brought to your attention, heed it. 15 | 3. **We are our biggest assets.** None of us were born masters of our trade. Each of us has been helped along the way. Return that favor, when and where you can. 16 | 4. **We are resources for the future.** As an extension of #3, share what you know. Make yourself a resource to help those that come after you. 17 | 5. **Respect defines us.** Treat others as you wish to be treated. Make your discussions, criticisms and debates from a position of respectfulness. Ask yourself, is it true? Is it necessary? Is it constructive? Anything less is unacceptable. 18 | 6. **Reactions require grace.** Angry responses are valid, but abusive language and vindictive actions are toxic. When something happens that offends you, handle it assertively, but be respectful. Escalate reasonably, and try to allow the offender an opportunity to explain themselves, and possibly correct the issue. 19 | 7. **Opinions are just that: opinions.** Each and every one of us, due to our background and upbringing, have varying opinions. That is perfectly acceptable. Remember this: if you respect your own opinions, you should respect the opinions of others. 20 | 8. **To err is human.** You might not intend it, but mistakes do happen and contribute to build experience. Tolerate honest mistakes, and don't hesitate to apologize if you make one yourself. 21 | 22 | ## How to contribute 23 | 24 | This is a collaborative effort. We welcome all contributions submitted as pull requests. 25 | 26 | (Contributions on wording & style are also welcome.) 27 | 28 | ### Bugs 29 | 30 | A bug is a demonstrable problem that is caused by the code in the repository. Good bug reports are extremely helpful – thank you! 31 | 32 | Please try to be as detailed as possible in your report. Include specific information about the environment – version of PHP, etc, and steps required to reproduce the issue. 33 | 34 | ### Pull Requests 35 | 36 | Good pull requests – patches, improvements, new features – are a fantastic help. Before create a pull request, please follow these instructions: 37 | 38 | * The code must follow the [PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md). Run `composer cs-fix` to fix your code before commit. 39 | * Write tests 40 | * Document any change in `README.md` and `CHANGELOG.md` 41 | * One pull request per feature. If you want to do more than one thing, send multiple pull request 42 | 43 | ### Runing tests 44 | 45 | ```sh 46 | composer test 47 | ``` 48 | 49 | To get code coverage information execute the following comand: 50 | 51 | ```sh 52 | composer coverage 53 | ``` 54 | 55 | Then, open the `./coverage/index.html` file in your browser. 56 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019-2025 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # middlewares/error-handler 2 | 3 | [![Latest Version on Packagist][ico-version]][link-packagist] 4 | [![Software License][ico-license]](LICENSE) 5 | ![Testing][ico-ga] 6 | [![Total Downloads][ico-downloads]][link-downloads] 7 | 8 | Middleware to catch and format errors encountered while handling the request. 9 | 10 | ## Requirements 11 | 12 | * PHP >= 7.2 13 | * A [PSR-7 http library](https://github.com/middlewares/awesome-psr15-middlewares#psr-7-implementations) 14 | * A [PSR-15 middleware dispatcher](https://github.com/middlewares/awesome-psr15-middlewares#dispatcher) 15 | 16 | ## Installation 17 | 18 | This package is installable and autoloadable via Composer as [middlewares/error-handler](https://packagist.org/packages/middlewares/error-handler). 19 | 20 | ```shell 21 | composer require middlewares/error-handler 22 | ``` 23 | 24 | ## Example 25 | 26 | ```php 27 | use Middlewares\ErrorFormatter; 28 | use Middlewares\ErrorHandler; 29 | use Middlewares\Utils\Dispatcher; 30 | 31 | // Create a new ErrorHandler instance 32 | // Any number of formatters can be added. One will be picked based on the Accept 33 | // header of the request. If no formatter matches, the first formatter in the array 34 | // will be used. 35 | $errorHandler = new ErrorHandler([ 36 | new ErrorFormatter\HtmlFormatter(), 37 | new ErrorFormatter\ImageFormatter(), 38 | new ErrorFormatter\JsonFormatter(), 39 | new ErrorFormatter\PlainFormatter(), 40 | new ErrorFormatter\SvgFormatter(), 41 | new ErrorFormatter\XmlFormatter(), 42 | ]); 43 | 44 | // ErrorHandler should always be the first middleware in the stack! 45 | $dispatcher = new Dispatcher([ 46 | $errorHandler, 47 | // ... 48 | function ($request) { 49 | throw HttpErrorException::create(404); 50 | } 51 | ]); 52 | 53 | $request = $serverRequestFactory->createServerRequest('GET', '/'); 54 | $response = $dispatcher->dispatch($request); 55 | ``` 56 | 57 | ## Usage 58 | 59 | Add the [formatters](src/ErrorFormatter) to be used (instances of `Middlewares\ErrorFormatter\FormatterInterface`). If no formatters are provided, use all available. 60 | 61 | ```php 62 | $errorHandler = new ErrorHandler([ 63 | new ErrorFormatter\HtmlFormatter(), 64 | new ErrorFormatter\JsonFormatter() 65 | ]); 66 | ``` 67 | 68 | **Note:** If no formatter is found, the first value of the array will be used. In the example above, `HtmlFormatter`. 69 | 70 | ### How to log the error and delegate the formatting to the middleware 71 | 72 | Please note that the following snippet must go even before error-hander's middleware, which usually goes first. 73 | 74 | ```php 75 | public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface 76 | { 77 | try { 78 | return $handler->handle($request); 79 | } catch (Throwable $exception) { 80 | $this->logger->critical('Uncaught {error}', [ 81 | 'error' => $exception->getMessage(), 82 | 'exception' => $exception, // If you use Monolog, this is correct 83 | ]); 84 | 85 | // leave it for the middleware 86 | throw $exception; 87 | } 88 | } 89 | ``` 90 | 91 | ### How to use a custom response for Production 92 | 93 | This snippet might come handy when you want to customize your response in production. 94 | 95 | ```php 96 | class PrettyPage implements StreamFactoryInterface 97 | { 98 | public function createStream(string $content = ''): StreamInterface 99 | { 100 | return Factory::createStream('Pretty page'); 101 | } 102 | 103 | public function createStreamFromFile(string $filename, string $mode = 'r'): StreamInterface 104 | { 105 | // This is safe as the Middleware only uses createStream() 106 | throw new Exception('Not implemented'); 107 | } 108 | 109 | public function createStreamFromResource($resource): StreamInterface 110 | { 111 | // This is safe as the Middleware only uses createStream() 112 | throw new Exception('Not implemented'); 113 | } 114 | } 115 | 116 | 117 | $errorHandler = new ErrorHandler([ 118 | new HtmlFormatter( 119 | null, 120 | new PrettyPage, 121 | ), 122 | ]); 123 | ``` 124 | 125 | --- 126 | 127 | Please see [CHANGELOG](CHANGELOG.md) for more information about recent changes and [CONTRIBUTING](CONTRIBUTING.md) for contributing details. 128 | 129 | The MIT License (MIT). Please see [LICENSE](LICENSE) for more information. 130 | 131 | [ico-version]: https://img.shields.io/packagist/v/middlewares/error-handler.svg?style=flat-square 132 | [ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square 133 | [ico-ga]: https://github.com/middlewares/error-handler/workflows/testing/badge.svg 134 | [ico-downloads]: https://img.shields.io/packagist/dt/middlewares/error-handler.svg?style=flat-square 135 | 136 | [link-packagist]: https://packagist.org/packages/middlewares/error-handler 137 | [link-downloads]: https://packagist.org/packages/middlewares/error-handler 138 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middlewares/error-handler", 3 | "type": "library", 4 | "description": "Middleware to handle http errors", 5 | "license": "MIT", 6 | "keywords": [ 7 | "psr-7", 8 | "psr-15", 9 | "middleware", 10 | "server", 11 | "http", 12 | "exception", 13 | "error", 14 | "formatter", 15 | "handler" 16 | ], 17 | "homepage": "https://github.com/middlewares/error-handler", 18 | "support": { 19 | "issues": "https://github.com/middlewares/error-handler/issues" 20 | }, 21 | "require": { 22 | "php": "^7.2 || ^8.0", 23 | "middlewares/utils": "^2 || ^3 || ^4", 24 | "psr/http-server-middleware": "^1", 25 | "ext-gd": "*" 26 | }, 27 | "require-dev": { 28 | "phpunit/phpunit": "^8 || ^9", 29 | "friendsofphp/php-cs-fixer": "^3", 30 | "squizlabs/php_codesniffer": "^3", 31 | "oscarotero/php-cs-fixer-config": "^2", 32 | "phpstan/phpstan": "^1 || ^2", 33 | "laminas/laminas-diactoros": "^2 || ^3" 34 | }, 35 | "autoload": { 36 | "psr-4": { 37 | "Middlewares\\": "src/" 38 | } 39 | }, 40 | "autoload-dev": { 41 | "psr-4": { 42 | "Middlewares\\Tests\\": "tests/" 43 | } 44 | }, 45 | "scripts": { 46 | "cs": "phpcs", 47 | "cs-fix": "php-cs-fixer fix", 48 | "phpstan": "phpstan analyse", 49 | "test": "phpunit", 50 | "coverage": "phpunit --coverage-text", 51 | "coverage-html": "phpunit --coverage-html=coverage" 52 | } 53 | } -------------------------------------------------------------------------------- /src/ErrorFormatter/AbstractFormatter.php: -------------------------------------------------------------------------------- 1 | responseFactory = $responseFactory ?? Factory::getResponseFactory(); 30 | $this->streamFactory = $streamFactory ?? Factory::getStreamFactory(); 31 | } 32 | 33 | public function isValid(Throwable $error, ServerRequestInterface $request): bool 34 | { 35 | return $this->getContentType($request) ? true : false; 36 | } 37 | 38 | abstract protected function format(Throwable $error, string $contentType): string; 39 | 40 | public function handle(Throwable $error, ServerRequestInterface $request): ResponseInterface 41 | { 42 | $contentType = $this->getContentType($request) ?: $this->contentTypes[0]; 43 | $response = $this->responseFactory->createResponse($this->errorStatus($error)); 44 | $body = $this->streamFactory->createStream($this->format($error, $contentType)); 45 | 46 | return $response->withBody($body)->withHeader('Content-Type', $contentType); 47 | } 48 | 49 | protected function errorStatus(Throwable $error): int 50 | { 51 | if ($error instanceof HttpErrorException) { 52 | return $error->getCode(); 53 | } 54 | 55 | if (method_exists($error, 'getStatusCode')) { 56 | return $error->getStatusCode(); 57 | } 58 | 59 | return 500; 60 | } 61 | 62 | protected function getContentType(ServerRequestInterface $request): ?string 63 | { 64 | $accept = $request->getHeaderLine('Accept'); 65 | 66 | foreach ($this->contentTypes as $type) { 67 | if (stripos($accept, $type) !== false) { 68 | return $type; 69 | } 70 | } 71 | 72 | return null; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/ErrorFormatter/FormatterInterface.php: -------------------------------------------------------------------------------- 1 | getCode(); 18 | $message = $error->getMessage(); 19 | 20 | return << 22 | 23 |
24 | 25 |$message
32 | 33 | 34 | HTML; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/ErrorFormatter/ImageFormatter.php: -------------------------------------------------------------------------------- 1 | createImage($error); 21 | 22 | switch ($contentType) { 23 | case 'image/gif': 24 | imagegif($image); 25 | break; 26 | case 'image/jpeg': 27 | imagejpeg($image); 28 | break; 29 | case 'image/png': 30 | imagepng($image); 31 | break; 32 | case 'image/webp': 33 | imagewebp($image); 34 | break; 35 | } 36 | 37 | return (string) ob_get_clean(); 38 | } 39 | 40 | /** 41 | * Create an image resource from an error 42 | * 43 | * @return resource 44 | */ 45 | private function createImage(Throwable $error) 46 | { 47 | $type = get_class($error); 48 | $code = $error->getCode(); 49 | $message = $error->getMessage(); 50 | 51 | $size = 200; 52 | $image = imagecreatetruecolor($size, $size); 53 | $textColor = imagecolorallocate($image, 255, 255, 255); 54 | 55 | /* @phpstan-ignore-next-line */ 56 | imagestring($image, 5, 10, 10, "$type $code", $textColor); 57 | 58 | /* @phpstan-ignore-next-line */ 59 | foreach (str_split($message, intval($size / 10)) as $line => $text) { 60 | /* @phpstan-ignore-next-line */ 61 | imagestring($image, 5, 10, ($line * 18) + 28, $text, $textColor); 62 | } 63 | 64 | return $image; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/ErrorFormatter/JsonFormatter.php: -------------------------------------------------------------------------------- 1 | get_class($error), 18 | 'code' => $error->getCode(), 19 | 'message' => $error->getMessage(), 20 | ]; 21 | 22 | return (string) json_encode($json); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ErrorFormatter/PlainFormatter.php: -------------------------------------------------------------------------------- 1 | getCode(), $error->getMessage()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/ErrorFormatter/SvgFormatter.php: -------------------------------------------------------------------------------- 1 | getCode(); 18 | $message = $error->getMessage(); 19 | 20 | return << 26 | SVG; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/ErrorFormatter/XmlFormatter.php: -------------------------------------------------------------------------------- 1 | getCode(); 18 | $message = $error->getMessage(); 19 | 20 | return <<$code
25 |