diff --git a/UPGRADE-4.4.md b/UPGRADE-4.4.md index b4fb6a0a8e..6f50fce81d 100644 --- a/UPGRADE-4.4.md +++ b/UPGRADE-4.4.md @@ -18,7 +18,6 @@ Console Debug ----- - * Deprecated the `Debug` class, use the one from the `ErrorRenderer` component instead * Deprecated the `FlattenException` class, use the one from the `ErrorRenderer` component instead * Deprecated the component in favor of the `ErrorHandler` component @@ -309,45 +308,35 @@ TwigBundle * Deprecated all built-in error templates, use the error renderer mechanism of the `ErrorRenderer` component * Deprecated loading custom error templates in non-html formats. Custom HTML error pages based on Twig keep working as before: - Before (`templates/bundles/TwigBundle/Exception/error.jsonld.twig`): + Before (`templates/bundles/TwigBundle/Exception/error.json.twig`): ```twig { - "@id": "https://example.com", - "@type": "error", - "@context": { - "title": "{{ status_text }}", - "code": {{ status_code }}, - "message": "{{ exception.message }}" - } + "type": "https://example.com/error", + "title": "{{ status_text }}", + "status": {{ status_code }} } ``` - After (`App\ErrorRenderer\JsonLdErrorRenderer`): + After (`App\Serializer\ProblemJsonNormalizer`): ```php - class JsonLdErrorRenderer implements ErrorRendererInterface + class ProblemJsonNormalizer implements NormalizerInterface { - public static function getFormat(): string + public function normalize($exception, $format = null, array $context = []) { - return 'jsonld'; + return [ + 'type' => 'https://example.com/error', + 'title' => $exception->getStatusText(), + 'status' => $exception->getStatusCode(), + ]; } - public function render(FlattenException $exception): string + public function supportsNormalization($data, $format = null) { - return json_encode([ - '@id' => 'https://example.com', - '@type' => 'error', - '@context' => [ - 'title' => $exception->getTitle(), - 'code' => $exception->getStatusCode(), - 'message' => $exception->getMessage(), - ], - ]); + return 'json' === $format && $data instanceof FlattenException; } } ``` - Configure your rendering service tagging it with `error_renderer.renderer`. - Validator --------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 8fc53005b3..35dae96383 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -57,7 +57,6 @@ Console Debug ----- - * Removed the `Debug` class, use the one from the `ErrorRenderer` component instead * Removed the `FlattenException` class, use the one from the `ErrorRenderer` component instead * Removed the component in favor of the `ErrorHandler` component diff --git a/composer.json b/composer.json index 24bcc7650f..a432a159c0 100644 --- a/composer.json +++ b/composer.json @@ -48,7 +48,6 @@ "symfony/dom-crawler": "self.version", "symfony/dotenv": "self.version", "symfony/error-handler": "self.version", - "symfony/error-renderer": "self.version", "symfony/event-dispatcher": "self.version", "symfony/expression-language": "self.version", "symfony/filesystem": "self.version", diff --git a/src/Symfony/Bridge/Twig/Mime/NotificationEmail.php b/src/Symfony/Bridge/Twig/Mime/NotificationEmail.php index d1051596dd..b5118b7f08 100644 --- a/src/Symfony/Bridge/Twig/Mime/NotificationEmail.php +++ b/src/Symfony/Bridge/Twig/Mime/NotificationEmail.php @@ -11,7 +11,7 @@ namespace Symfony\Bridge\Twig\Mime; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\Mime\Header\Headers; use Symfony\Component\Mime\Part\AbstractPart; use Twig\Extra\CssInliner\CssInlinerExtension; diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php index 7ee9e12c0a..e21550115b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php @@ -32,7 +32,6 @@ class UnusedTagsPass implements CompilerPassInterface 'controller.service_arguments', 'config_cache.resource_checker', 'data_collector', - 'error_renderer.renderer', 'form.type', 'form.type_extension', 'form.type_guesser', diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 173165b03e..ed85fa2ea7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -33,7 +33,6 @@ use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\Compiler\RegisterReverseContainerPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\ErrorHandler\ErrorHandler; -use Symfony\Component\ErrorRenderer\DependencyInjection\ErrorRendererPass; use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass; use Symfony\Component\Form\DependencyInjection\FormPass; use Symfony\Component\HttpClient\DependencyInjection\HttpClientPass; @@ -92,7 +91,6 @@ class FrameworkBundle extends Bundle KernelEvents::FINISH_REQUEST, ]; - $container->addCompilerPass(new ErrorRendererPass()); $container->addCompilerPass(new LoggerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -32); $container->addCompilerPass(new RegisterControllerArgumentLocatorsPass()); $container->addCompilerPass(new RemoveEmptyControllerArgumentLocatorsPass(), PassConfig::TYPE_BEFORE_REMOVING); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml index 73b9eff6fe..7276892940 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml @@ -194,12 +194,6 @@ - - - - - - diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/error_renderer.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/error_renderer.xml index 4e3fc596f9..d072f6b227 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/error_renderer.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/error_renderer.xml @@ -5,12 +5,7 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd"> - - - - - - + %kernel.debug% %kernel.charset% @@ -19,21 +14,15 @@ - - + + + + %kernel.debug% - - - - %kernel.debug% - %kernel.charset% - - - - - %kernel.debug% - + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml index 23da8b07bc..4698c50593 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml @@ -12,6 +12,8 @@ + + @@ -59,6 +61,12 @@ + + %kernel.debug% + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index e3faf21102..46b1cd80e1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -21,7 +21,6 @@ "symfony/cache": "^4.4|^5.0", "symfony/config": "^4.3.4|^5.0", "symfony/dependency-injection": "^4.4|^5.0", - "symfony/error-renderer": "^4.4|^5.0", "symfony/http-foundation": "^4.4|^5.0", "symfony/http-kernel": "^4.4", "symfony/polyfill-mbstring": "~1.0", @@ -50,7 +49,7 @@ "symfony/process": "^3.4|^4.0|^5.0", "symfony/security-csrf": "^3.4|^4.0|^5.0", "symfony/security-http": "^3.4|^4.0|^5.0", - "symfony/serializer": "^4.3|^5.0", + "symfony/serializer": "^4.4|^5.0", "symfony/stopwatch": "^3.4|^4.0|^5.0", "symfony/translation": "^4.4|^5.0", "symfony/templating": "^3.4|^4.0|^5.0", diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/JsonLoginTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/JsonLoginTest.php index 4fbdb27c65..a69f5e591d 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/JsonLoginTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/JsonLoginTest.php @@ -70,6 +70,6 @@ class JsonLoginTest extends AbstractWebTestCase $this->assertSame(400, $response->getStatusCode()); $this->assertSame('application/json', $response->headers->get('Content-Type')); - $this->assertSame(['title' => 'Bad Request', 'status' => 400, 'detail' => 'Whoops, looks like something went wrong.'], json_decode($response->getContent(), true)); + $this->assertSame(['type' => 'https://tools.ietf.org/html/rfc2616#section-10', 'title' => 'An error occurred', 'status' => 400, 'detail' => 'Bad Request'], json_decode($response->getContent(), true)); } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/config.yml index d6ed10e896..3522f27f13 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/config.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/config.yml @@ -1,6 +1,9 @@ imports: - { resource: ./../config/framework.yml } +framework: + serializer: ~ + security: encoders: Symfony\Component\Security\Core\User\User: plaintext diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 7f3a55477b..c9202bad57 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -35,6 +35,7 @@ "symfony/form": "^3.4|^4.0|^5.0", "symfony/framework-bundle": "^4.4|^5.0", "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/serializer": "^4.4|^5.0", "symfony/translation": "^3.4|^4.0|^5.0", "symfony/twig-bundle": "^4.4|^5.0", "symfony/twig-bridge": "^3.4|^4.0|^5.0", diff --git a/src/Symfony/Bundle/TwigBundle/CHANGELOG.md b/src/Symfony/Bundle/TwigBundle/CHANGELOG.md index 99b14db8d5..28cca78447 100644 --- a/src/Symfony/Bundle/TwigBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/TwigBundle/CHANGELOG.md @@ -6,8 +6,8 @@ CHANGELOG * marked the `TemplateIterator` as `internal` * added HTML comment to beginning and end of `exception_full.html.twig` - * added a new `TwigHtmlErrorRenderer` for `html` format, integrated with the `ErrorRenderer` component - * deprecated `ExceptionController` and `PreviewErrorController` controllers, use `ErrorController` from the `HttpKernel` component instead + * added a new `TwigHtmlErrorRenderer` for `html` format, integrated with the `ErrorHandler` component + * deprecated `ExceptionController` and `PreviewErrorController` controllers, use `ErrorController` from the `HttpKernel` component instead * deprecated all built-in error templates in favor of the new error renderer mechanism * deprecated `twig.exception_controller` configuration option, set it to "null" and use `framework.error_controller` configuration instead diff --git a/src/Symfony/Bundle/TwigBundle/ErrorRenderer/TwigHtmlErrorRenderer.php b/src/Symfony/Bundle/TwigBundle/ErrorRenderer/TwigHtmlErrorRenderer.php index b9c876a273..1fae5eadd7 100644 --- a/src/Symfony/Bundle/TwigBundle/ErrorRenderer/TwigHtmlErrorRenderer.php +++ b/src/Symfony/Bundle/TwigBundle/ErrorRenderer/TwigHtmlErrorRenderer.php @@ -11,9 +11,9 @@ namespace Symfony\Bundle\TwigBundle\ErrorRenderer; -use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRendererInterface; -use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; +use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRendererInterface; +use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Twig\Environment; use Twig\Error\LoaderError; use Twig\Loader\ExistsLoaderInterface; @@ -40,34 +40,20 @@ class TwigHtmlErrorRenderer implements ErrorRendererInterface /** * {@inheritdoc} */ - public static function getFormat(): string + public function render(\Throwable $exception): FlattenException { - return 'html'; - } + $exception = $this->htmlErrorRenderer->render($exception); - /** - * {@inheritdoc} - */ - public function render(FlattenException $exception): string - { - $debug = $this->debug && ($exception->getHeaders()['X-Debug'] ?? true); - - if ($debug) { - return $this->htmlErrorRenderer->render($exception); + if ($this->debug || !$template = $this->findTemplate($exception->getStatusCode()); + return $exception; } - $template = $this->findTemplate($exception->getStatusCode()); - - if (null === $template) { - return $this->htmlErrorRenderer->render($exception); - } - - return $this->twig->render($template, [ + return $exception->setAsString($this->twig->render($template, [ 'legacy' => false, // to be removed in 5.0 'exception' => $exception, 'status_code' => $exception->getStatusCode(), - 'status_text' => $exception->getTitle(), - ]); + 'status_text' => $exception->getStatusText(), + ])); } private function findTemplate(int $statusCode): ?string diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml index fa886981e9..33f386608f 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml @@ -162,10 +162,9 @@ - - + - + %kernel.debug% diff --git a/src/Symfony/Bundle/TwigBundle/Tests/ErrorRenderer/TwigHtmlErrorRendererTest.php b/src/Symfony/Bundle/TwigBundle/Tests/ErrorRenderer/TwigHtmlErrorRendererTest.php index fa04d363ca..1d5841ae19 100644 --- a/src/Symfony/Bundle/TwigBundle/Tests/ErrorRenderer/TwigHtmlErrorRendererTest.php +++ b/src/Symfony/Bundle/TwigBundle/Tests/ErrorRenderer/TwigHtmlErrorRendererTest.php @@ -13,8 +13,7 @@ namespace Symfony\Bundle\TwigBundle\Tests\ErrorRenderer; use PHPUnit\Framework\TestCase; use Symfony\Bundle\TwigBundle\ErrorRenderer\TwigHtmlErrorRenderer; -use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; +use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Twig\Environment; use Twig\Loader\ArrayLoader; @@ -23,7 +22,7 @@ class TwigHtmlErrorRendererTest extends TestCase { public function testFallbackToNativeRendererIfDebugOn() { - $exception = FlattenException::createFromThrowable(new \Exception()); + $exception = new \Exception(); $twig = $this->createMock(Environment::class); $nativeRenderer = $this->createMock(HtmlErrorRenderer::class); @@ -33,12 +32,12 @@ class TwigHtmlErrorRendererTest extends TestCase ->with($exception) ; - (new TwigHtmlErrorRenderer($twig, $nativeRenderer, true))->render($exception); + (new TwigHtmlErrorRenderer($twig, $nativeRenderer, true))->render(new \Exception()); } public function testFallbackToNativeRendererIfCustomTemplateNotFound() { - $exception = FlattenException::createFromThrowable(new NotFoundHttpException()); + $exception = new NotFoundHttpException(); $twig = new Environment(new ArrayLoader([])); @@ -54,7 +53,7 @@ class TwigHtmlErrorRendererTest extends TestCase public function testRenderCustomErrorTemplate() { - $exception = FlattenException::createFromThrowable(new NotFoundHttpException()); + $exception = new NotFoundHttpException(); $twig = new Environment(new ArrayLoader([ '@Twig/Exception/error404.html.twig' => '

Page Not Found

', @@ -68,6 +67,6 @@ class TwigHtmlErrorRendererTest extends TestCase $content = (new TwigHtmlErrorRenderer($twig, $nativeRenderer, false))->render($exception); - $this->assertSame('

Page Not Found

', $content); + $this->assertSame('

Page Not Found

', $content->getAsString()); } } diff --git a/src/Symfony/Bundle/TwigBundle/Tests/Functional/EmptyAppTest.php b/src/Symfony/Bundle/TwigBundle/Tests/Functional/EmptyAppTest.php index 55851f1d69..a7f3bc27da 100644 --- a/src/Symfony/Bundle/TwigBundle/Tests/Functional/EmptyAppTest.php +++ b/src/Symfony/Bundle/TwigBundle/Tests/Functional/EmptyAppTest.php @@ -15,7 +15,7 @@ use Symfony\Bundle\TwigBundle\Tests\TestCase; use Symfony\Bundle\TwigBundle\TwigBundle; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\ErrorRenderer\ErrorRenderer; +use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpKernel\Kernel; @@ -65,7 +65,8 @@ class EmptyAppKernel extends Kernel 'strict_variables' => false, 'exception_controller' => null, ]); - $container->register('error_renderer', ErrorRenderer::class); + $container->register('error_renderer.html', HtmlErrorRenderer::class); + $container->setAlias('error_renderer', 'error_renderer.html'); $container->setParameter('debug.file_link_format', null); }); } diff --git a/src/Symfony/Bundle/TwigBundle/composer.json b/src/Symfony/Bundle/TwigBundle/composer.json index c10735b578..d9bf24fa48 100644 --- a/src/Symfony/Bundle/TwigBundle/composer.json +++ b/src/Symfony/Bundle/TwigBundle/composer.json @@ -17,7 +17,6 @@ ], "require": { "php": "^7.1.3", - "symfony/error-renderer": "^4.4|^5.0", "symfony/twig-bridge": "^4.4|^5.0", "symfony/http-foundation": "^4.3|^5.0", "symfony/http-kernel": "^4.4", diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionController.php index 168f2ca2ce..095d65486a 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionController.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionController.php @@ -11,7 +11,7 @@ namespace Symfony\Bundle\WebProfilerBundle\Controller; -use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer; +use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -42,11 +42,7 @@ class ExceptionController $this->profiler = $profiler; $this->twig = $twig; $this->debug = $debug; - $this->errorRenderer = $errorRenderer; - - if (null === $errorRenderer) { - $this->errorRenderer = new HtmlErrorRenderer($debug, $this->twig->getCharset(), $fileLinkFormat); - } + $this->errorRenderer = $errorRenderer ?? new HtmlErrorRenderer($debug, $this->twig->getCharset(), $fileLinkFormat); } /** diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionPanelController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionPanelController.php index cff1f39400..4941208c88 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionPanelController.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionPanelController.php @@ -11,7 +11,7 @@ namespace Symfony\Bundle\WebProfilerBundle\Controller; -use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer; +use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Profiler\Profiler; @@ -25,12 +25,12 @@ use Symfony\Component\HttpKernel\Profiler\Profiler; */ class ExceptionPanelController { - private $htmlErrorRenderer; + private $errorRenderer; private $profiler; - public function __construct(HtmlErrorRenderer $htmlErrorRenderer, ?Profiler $profiler) + public function __construct(HtmlErrorRenderer $errorRenderer, Profiler $profiler = null) { - $this->htmlErrorRenderer = $htmlErrorRenderer; + $this->errorRenderer = $errorRenderer; $this->profiler = $profiler; } @@ -48,7 +48,7 @@ class ExceptionPanelController ->getException() ; - return new Response($this->htmlErrorRenderer->getBody($exception), 200, ['Content-Type' => 'text/html']); + return new Response($this->errorRenderer->getBody($exception), 200, ['Content-Type' => 'text/html']); } /** @@ -56,6 +56,6 @@ class ExceptionPanelController */ public function stylesheet(): Response { - return new Response($this->htmlErrorRenderer->getStylesheet(), 200, ['Content-Type' => 'text/css']); + return new Response($this->errorRenderer->getStylesheet(), 200, ['Content-Type' => 'text/css']); } } diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/config/profiler.xml b/src/Symfony/Bundle/WebProfilerBundle/Resources/config/profiler.xml index 0d68bf00b0..89ecca5baf 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/config/profiler.xml +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/config/profiler.xml @@ -27,12 +27,12 @@ %kernel.debug% - + The "%service_id%" service is deprecated since Symfony 4.4, use the "web_profiler.controller.exception_panel" service instead.
- + diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php index 9934077cf1..e9bffb4d06 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php @@ -17,7 +17,7 @@ use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer; +use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer; use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass; use Symfony\Component\EventDispatcher\EventDispatcher; @@ -54,7 +54,7 @@ class WebProfilerExtensionTest extends TestCase $this->kernel = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\KernelInterface')->getMock(); $this->container = new ContainerBuilder(); - $this->container->register('error_renderer.renderer.html', HtmlErrorRenderer::class)->setPublic(true); + $this->container->register('error_renderer.html', HtmlErrorRenderer::class)->setPublic(true); $this->container->register('event_dispatcher', EventDispatcher::class)->setPublic(true); $this->container->register('router', $this->getMockClass('Symfony\\Component\\Routing\\RouterInterface'))->setPublic(true); $this->container->register('twig', 'Twig\Environment')->setPublic(true); diff --git a/src/Symfony/Bundle/WebProfilerBundle/composer.json b/src/Symfony/Bundle/WebProfilerBundle/composer.json index bb131bea9f..e3f7bc0107 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/composer.json +++ b/src/Symfony/Bundle/WebProfilerBundle/composer.json @@ -18,7 +18,6 @@ "require": { "php": "^7.1.3", "symfony/config": "^4.2|^5.0", - "symfony/error-renderer": "^4.4|^5.0", "symfony/http-kernel": "^4.4", "symfony/routing": "^3.4|^4.0|^5.0", "symfony/twig-bundle": "^4.2|^5.0", diff --git a/src/Symfony/Component/Debug/CHANGELOG.md b/src/Symfony/Component/Debug/CHANGELOG.md index b2e17f3821..989c1a72da 100644 --- a/src/Symfony/Component/Debug/CHANGELOG.md +++ b/src/Symfony/Component/Debug/CHANGELOG.md @@ -4,7 +4,7 @@ CHANGELOG 4.4.0 ----- - * deprecated `FlattenException`, use the `FlattenException` of the `ErrorRenderer` component + * deprecated `FlattenException`, use the `FlattenException` of the `ErrorHandler` component * deprecated the whole component in favor of the `ErrorHandler` component 4.3.0 diff --git a/src/Symfony/Component/Debug/Exception/FlattenException.php b/src/Symfony/Component/Debug/Exception/FlattenException.php index 4e213b1bd9..f55f71b0c9 100644 --- a/src/Symfony/Component/Debug/Exception/FlattenException.php +++ b/src/Symfony/Component/Debug/Exception/FlattenException.php @@ -21,7 +21,7 @@ use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; * * @author Fabien Potencier * - * @deprecated since Symfony 4.4, use Symfony\Component\ErrorRenderer\Exception\FlattenException instead. + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Exception\FlattenException instead. */ class FlattenException { diff --git a/src/Symfony/Component/ErrorHandler/BufferingLogger.php b/src/Symfony/Component/ErrorHandler/BufferingLogger.php index 49c838f272..16e433dedf 100644 --- a/src/Symfony/Component/ErrorHandler/BufferingLogger.php +++ b/src/Symfony/Component/ErrorHandler/BufferingLogger.php @@ -34,4 +34,25 @@ class BufferingLogger extends AbstractLogger return $logs; } + + public function __destruct() + { + foreach ($this->logs as [$level, $message, $context]) { + if (false !== strpos($message, '{')) { + foreach ($context as $key => $val) { + if (null === $val || is_scalar($val) || (\is_object($val) && \is_callable([$val, '__toString']))) { + $message = str_replace("{{$key}}", $val, $message); + } elseif ($val instanceof \DateTimeInterface) { + $message = str_replace("{{$key}}", $val->format(\DateTime::RFC3339), $message); + } elseif (\is_object($val)) { + $message = str_replace("{{$key}}", '[object '.\get_class($val).']', $message); + } else { + $message = str_replace("{{$key}}", '['.\gettype($val).']', $message); + } + } + } + + error_log(sprintf('%s [%s] %s', date(\DateTime::RFC3339), $level, $message)); + } + } } diff --git a/src/Symfony/Component/ErrorHandler/Debug.php b/src/Symfony/Component/ErrorHandler/Debug.php index 6f75dbf60e..f95334e01a 100644 --- a/src/Symfony/Component/ErrorHandler/Debug.php +++ b/src/Symfony/Component/ErrorHandler/Debug.php @@ -18,39 +18,19 @@ namespace Symfony\Component\ErrorHandler; */ class Debug { - private static $enabled = false; - - /** - * Enables the debug tools. - * - * This method registers an error handler and an exception handler. - */ - public static function enable(int $errorReportingLevel = E_ALL, bool $displayErrors = true): void + public static function enable(): ErrorHandler { - if (static::$enabled) { - return; - } - - static::$enabled = true; - - if (null !== $errorReportingLevel) { - error_reporting($errorReportingLevel); - } else { - error_reporting(E_ALL); - } + error_reporting(-1); if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) { ini_set('display_errors', 0); - } elseif ($displayErrors && (!filter_var(ini_get('log_errors'), FILTER_VALIDATE_BOOLEAN) || ini_get('error_log'))) { + } elseif (!filter_var(ini_get('log_errors'), FILTER_VALIDATE_BOOLEAN) || ini_get('error_log')) { // CLI - display errors only if they're not already logged to STDERR ini_set('display_errors', 1); } - if ($displayErrors) { - ErrorHandler::register(new ErrorHandler(new BufferingLogger())); - } else { - ErrorHandler::register()->throwAt(0, true); - } DebugClassLoader::enable(); + + return ErrorHandler::register(new ErrorHandler(new BufferingLogger())); } } diff --git a/src/Symfony/Component/ErrorHandler/ErrorHandler.php b/src/Symfony/Component/ErrorHandler/ErrorHandler.php index ab6df70bd8..8144f0de66 100644 --- a/src/Symfony/Component/ErrorHandler/ErrorHandler.php +++ b/src/Symfony/Component/ErrorHandler/ErrorHandler.php @@ -19,9 +19,10 @@ use Symfony\Component\ErrorHandler\ErrorEnhancer\ClassNotFoundErrorEnhancer; use Symfony\Component\ErrorHandler\ErrorEnhancer\ErrorEnhancerInterface; use Symfony\Component\ErrorHandler\ErrorEnhancer\UndefinedFunctionErrorEnhancer; use Symfony\Component\ErrorHandler\ErrorEnhancer\UndefinedMethodErrorEnhancer; +use Symfony\Component\ErrorHandler\ErrorRenderer\CliErrorRenderer; +use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext; -use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; /** * A generic ErrorHandler for the PHP engine. @@ -45,10 +46,8 @@ use Symfony\Component\ErrorRenderer\Exception\FlattenException; * * @author Nicolas Grekas * @author Grégoire Pineau - * - * @final since Symfony 4.3 */ -class ErrorHandler +final class ErrorHandler { private $levels = [ E_DEPRECATED => 'Deprecated', @@ -145,10 +144,8 @@ class ErrorHandler $handler->setExceptionHandler($p); $prev[0]->setExceptionHandler($p); } - } elseif (null === $prev && !\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) { - $handler->setExceptionHandler([$handler, 'sendPhpResponse']); } else { - $handler->setExceptionHandler($prev); + $handler->setExceptionHandler($prev ?? [$handler, 'renderException']); } $handler->throwAt(E_ALL & $handler->thrownErrors, true); @@ -280,7 +277,7 @@ class ErrorHandler /** * Sets a user exception handler. * - * @param callable|null $handler A handler that must support \Throwable instances that will be called on Exception + * @param callable(\Throwable $e)|null $handler * * @return callable|null The previous exception handler */ @@ -583,11 +580,7 @@ class ErrorHandler } $exceptionHandler = $this->exceptionHandler; - if ((!\is_array($exceptionHandler) || !$exceptionHandler[0] instanceof self || 'sendPhpResponse' !== $exceptionHandler[1]) && !\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) { - $this->exceptionHandler = [$this, 'sendPhpResponse']; - } else { - $this->exceptionHandler = null; - } + $this->exceptionHandler = null; try { if (null !== $exceptionHandler) { return $exceptionHandler($exception); @@ -684,36 +677,26 @@ class ErrorHandler } /** - * Sends the error associated with the given Exception as a plain PHP response. + * Renders the given exception. * - * As this method is mainly called during Kernel boot, where nothing is yet - * available, the Response content is always HTML. + * As this method is mainly called during boot where nothing is yet available, + * the output is always either HTML or CLI depending where PHP runs. */ - private function sendPhpResponse(\Throwable $exception) + private function renderException(\Throwable $exception): void { - $charset = ini_get('default_charset') ?: 'UTF-8'; - $statusCode = 500; - $headers = []; + $renderer = \in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) ? new CliErrorRenderer() : new HtmlErrorRenderer(0 !== $this->scopedErrors); - if (class_exists(HtmlErrorRenderer::class)) { - $exception = FlattenException::createFromThrowable($exception); - $statusCode = $exception->getStatusCode(); - $headers = $exception->getHeaders(); - $response = (new HtmlErrorRenderer(0 !== $this->scopedErrors))->render($exception); - } else { - $message = htmlspecialchars($exception->getMessage(), ENT_COMPAT | ENT_SUBSTITUTE, $charset); - $response = sprintf('%s', $charset, $message); - } + $exception = $renderer->render($exception); if (!headers_sent()) { - header(sprintf('HTTP/1.0 %s', $statusCode)); - foreach ($headers as $name => $value) { + http_response_code($exception->getStatusCode()); + + foreach ($exception->getHeaders() as $name => $value) { header($name.': '.$value, false); } - header('Content-Type: text/html; charset='.$charset); } - echo $response; + echo $exception->getAsString(); } /** diff --git a/src/Symfony/Component/ErrorHandler/ErrorRenderer/CliErrorRenderer.php b/src/Symfony/Component/ErrorHandler/ErrorRenderer/CliErrorRenderer.php new file mode 100644 index 0000000000..fbe0b5bb23 --- /dev/null +++ b/src/Symfony/Component/ErrorHandler/ErrorRenderer/CliErrorRenderer.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\ErrorRenderer; + +use Symfony\Component\ErrorHandler\Exception\FlattenException; +use Symfony\Component\VarDumper\Cloner\VarCloner; +use Symfony\Component\VarDumper\Dumper\CliDumper; + +/** + * @author Nicolas Grekas + */ +class CliErrorRenderer implements ErrorRendererInterface +{ + /** + * {@inheritdoc} + */ + public function render(\Throwable $exception): FlattenException + { + $cloner = new VarCloner(); + $dumper = new class() extends CliDumper { + protected function supportsColors(): bool + { + $outputStream = $this->outputStream; + $this->outputStream = STDOUT; + + try { + return parent::supportsColors(); + } finally { + $this->outputStream = $outputStream; + } + } + }; + + return FlattenException::createFromThrowable($exception) + ->setAsString($dumper->dump($cloner->cloneVar($exception), true)); + } +} diff --git a/src/Symfony/Component/ErrorHandler/ErrorRenderer/ErrorRendererInterface.php b/src/Symfony/Component/ErrorHandler/ErrorRenderer/ErrorRendererInterface.php new file mode 100644 index 0000000000..aba196603f --- /dev/null +++ b/src/Symfony/Component/ErrorHandler/ErrorRenderer/ErrorRendererInterface.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\ErrorRenderer; + +use Symfony\Component\ErrorHandler\Exception\FlattenException; + +/** + * Formats an exception to be used as response content. + * + * @author Yonel Ceruto + */ +interface ErrorRendererInterface +{ + /** + * Renders a Throwable as a FlattenException. + */ + public function render(\Throwable $exception): FlattenException; +} diff --git a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/HtmlErrorRenderer.php b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php similarity index 96% rename from src/Symfony/Component/ErrorRenderer/ErrorRenderer/HtmlErrorRenderer.php rename to src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php index a9d0af516d..92eeba2cf0 100644 --- a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/HtmlErrorRenderer.php +++ b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php @@ -9,10 +9,10 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\ErrorRenderer\ErrorRenderer; +namespace Symfony\Component\ErrorHandler\ErrorRenderer; use Psr\Log\LoggerInterface; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; @@ -52,23 +52,17 @@ class HtmlErrorRenderer implements ErrorRendererInterface /** * {@inheritdoc} */ - public static function getFormat(): string + public function render(\Throwable $exception): FlattenException { - return 'html'; - } - - /** - * {@inheritdoc} - */ - public function render(FlattenException $exception): string - { - return $this->renderException($exception); + $exception = FlattenException::createFromThrowable($exception, null, [ + 'Content-Type' => 'text/html; charset='.$this->charset, + ]); + + return $exception->setAsString($this->renderException($exception)); } /** * Gets the HTML content associated with the given exception. - * - * @internal */ public function getBody(FlattenException $exception): string { @@ -77,8 +71,6 @@ class HtmlErrorRenderer implements ErrorRendererInterface /** * Gets the stylesheet associated with the given exception. - * - * @internal */ public function getStylesheet(): string { @@ -91,11 +83,10 @@ class HtmlErrorRenderer implements ErrorRendererInterface private function renderException(FlattenException $exception, string $debugTemplate = 'views/exception_full.html.php'): string { - $debug = $this->debug && ($exception->getHeaders()['X-Debug'] ?? true); - $statusText = $this->escape($exception->getTitle()); + $statusText = $this->escape($exception->getStatusText()); $statusCode = $this->escape($exception->getStatusCode()); - if (!$debug) { + if (!$this->debug) { return $this->include('views/error.html.php', [ 'statusText' => $statusText, 'statusCode' => $statusCode, @@ -111,13 +102,13 @@ class HtmlErrorRenderer implements ErrorRendererInterface 'statusText' => $statusText, 'statusCode' => $statusCode, 'logger' => $this->logger instanceof DebugLoggerInterface ? $this->logger : null, - 'currentContent' => $request ? $this->getAndCleanOutputBuffering($request->headers->get('X-Php-Ob-Level')) : null, + 'currentContent' => $request ? $this->getAndCleanOutputBuffering($request->headers->get('X-Php-Ob-Level')) : '', ]); } - private function getAndCleanOutputBuffering(int $startObLevel): string + private function getAndCleanOutputBuffering(?int $startObLevel): string { - if (ob_get_level() <= $startObLevel) { + if (null === $startObLevel || ob_get_level() <= $startObLevel) { return ''; } @@ -321,7 +312,7 @@ class HtmlErrorRenderer implements ErrorRendererInterface { extract($context, EXTR_SKIP); ob_start(); - include __DIR__.'/../Resources/'.$name; + include __DIR__ . '/../Resources/' .$name; return trim(ob_get_clean()); } diff --git a/src/Symfony/Component/ErrorHandler/ErrorRenderer/SerializerErrorRenderer.php b/src/Symfony/Component/ErrorHandler/ErrorRenderer/SerializerErrorRenderer.php new file mode 100644 index 0000000000..2485ee3f3a --- /dev/null +++ b/src/Symfony/Component/ErrorHandler/ErrorRenderer/SerializerErrorRenderer.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\ErrorRenderer; + +use Symfony\Component\ErrorRenderer\Exception\FlattenException; +use Symfony\Component\Serializer\Exception\NotEncodableValueException; +use Symfony\Component\Serializer\SerializerInterface; + +/** + * Formats an exception using Serializer for rendering. + * + * @author Nicolas Grekas + */ +class SerializerErrorRenderer +{ + private $serializer; + private $requestStack; + private $debug; + + public function __construct(SerializerInterface $serializer, RequestStack $requestStack, bool $debug = true) + { + $this->serializer = $serializer; + $this->requestStack = $requestStack; + $this->debug = $debug; + } + + /** + * {@inheritdoc} + */ + public function render(\Throwable $exception): FlattenException + { + $format = $this->requestStack->getCurrentRequest()->getPreferredFormat(); + $flattenException = FlattenException::createFromThrowable($exception); + + try { + return $flattenException->setAsString($this->serializer->serialize($flattenException, $format, ['exception' => $exception])); + } catch (NotEncodableValueException $_) { + return (new HtmlErrorHandler($this->debug))->render($exception); + } + } +} diff --git a/src/Symfony/Component/ErrorRenderer/Exception/FlattenException.php b/src/Symfony/Component/ErrorHandler/Exception/FlattenException.php similarity index 93% rename from src/Symfony/Component/ErrorRenderer/Exception/FlattenException.php rename to src/Symfony/Component/ErrorHandler/Exception/FlattenException.php index dd86f5b74b..61af8a7e1d 100644 --- a/src/Symfony/Component/ErrorRenderer/Exception/FlattenException.php +++ b/src/Symfony/Component/ErrorHandler/Exception/FlattenException.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\ErrorRenderer\Exception; +namespace Symfony\Component\ErrorHandler\Exception; use Symfony\Component\Debug\Exception\FlattenException as LegacyFlattenException; use Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface; @@ -25,7 +25,6 @@ use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; */ class FlattenException extends LegacyFlattenException { - private $title; private $message; private $code; private $previous; @@ -33,9 +32,11 @@ class FlattenException extends LegacyFlattenException private $traceAsString; private $class; private $statusCode; + private $statusText; private $headers; private $file; private $line; + private $asString; public static function create(\Exception $exception, $statusCode = null, array $headers = []): self { @@ -60,12 +61,12 @@ class FlattenException extends LegacyFlattenException } if (class_exists(Response::class) && isset(Response::$statusTexts[$statusCode])) { - $title = Response::$statusTexts[$statusCode]; + $statusText = Response::$statusTexts[$statusCode]; } else { - $title = 'Whoops, looks like something went wrong.'; + $statusText = 'Whoops, looks like something went wrong.'; } - $e->setTitle($title); + $e->setStatusText($statusText); $e->setStatusCode($statusCode); $e->setHeaders($headers); $e->setTraceFromThrowable($exception); @@ -171,14 +172,14 @@ class FlattenException extends LegacyFlattenException return $this; } - public function getTitle() + public function getStatusText() { - return $this->title; + return $this->statusText; } - public function setTitle(string $title): self + public function setStatusText(string $statusText): self { - $this->title = $title; + $this->statusText = $statusText; return $this; } @@ -355,8 +356,19 @@ class FlattenException extends LegacyFlattenException return $this->traceAsString; } + public function setAsString(?string $asString) + { + $this->asString = $asString; + + return $this; + } + public function getAsString() { + if (null !== $this->asString) { + return $this->asString; + } + $message = ''; $next = false; diff --git a/src/Symfony/Component/ErrorRenderer/Resources/assets/css/error.css b/src/Symfony/Component/ErrorHandler/Resources/assets/css/error.css similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/assets/css/error.css rename to src/Symfony/Component/ErrorHandler/Resources/assets/css/error.css diff --git a/src/Symfony/Component/ErrorRenderer/Resources/assets/css/exception.css b/src/Symfony/Component/ErrorHandler/Resources/assets/css/exception.css similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/assets/css/exception.css rename to src/Symfony/Component/ErrorHandler/Resources/assets/css/exception.css diff --git a/src/Symfony/Component/ErrorRenderer/Resources/assets/css/exception_full.css b/src/Symfony/Component/ErrorHandler/Resources/assets/css/exception_full.css similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/assets/css/exception_full.css rename to src/Symfony/Component/ErrorHandler/Resources/assets/css/exception_full.css diff --git a/src/Symfony/Component/ErrorRenderer/Resources/assets/images/chevron-right.svg b/src/Symfony/Component/ErrorHandler/Resources/assets/images/chevron-right.svg similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/assets/images/chevron-right.svg rename to src/Symfony/Component/ErrorHandler/Resources/assets/images/chevron-right.svg diff --git a/src/Symfony/Component/ErrorRenderer/Resources/assets/images/favicon.png.base64 b/src/Symfony/Component/ErrorHandler/Resources/assets/images/favicon.png.base64 similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/assets/images/favicon.png.base64 rename to src/Symfony/Component/ErrorHandler/Resources/assets/images/favicon.png.base64 diff --git a/src/Symfony/Component/ErrorRenderer/Resources/assets/images/icon-book.svg b/src/Symfony/Component/ErrorHandler/Resources/assets/images/icon-book.svg similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/assets/images/icon-book.svg rename to src/Symfony/Component/ErrorHandler/Resources/assets/images/icon-book.svg diff --git a/src/Symfony/Component/ErrorRenderer/Resources/assets/images/icon-minus-square-o.svg b/src/Symfony/Component/ErrorHandler/Resources/assets/images/icon-minus-square-o.svg similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/assets/images/icon-minus-square-o.svg rename to src/Symfony/Component/ErrorHandler/Resources/assets/images/icon-minus-square-o.svg diff --git a/src/Symfony/Component/ErrorRenderer/Resources/assets/images/icon-minus-square.svg b/src/Symfony/Component/ErrorHandler/Resources/assets/images/icon-minus-square.svg similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/assets/images/icon-minus-square.svg rename to src/Symfony/Component/ErrorHandler/Resources/assets/images/icon-minus-square.svg diff --git a/src/Symfony/Component/ErrorRenderer/Resources/assets/images/icon-plus-square-o.svg b/src/Symfony/Component/ErrorHandler/Resources/assets/images/icon-plus-square-o.svg similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/assets/images/icon-plus-square-o.svg rename to src/Symfony/Component/ErrorHandler/Resources/assets/images/icon-plus-square-o.svg diff --git a/src/Symfony/Component/ErrorRenderer/Resources/assets/images/icon-plus-square.svg b/src/Symfony/Component/ErrorHandler/Resources/assets/images/icon-plus-square.svg similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/assets/images/icon-plus-square.svg rename to src/Symfony/Component/ErrorHandler/Resources/assets/images/icon-plus-square.svg diff --git a/src/Symfony/Component/ErrorRenderer/Resources/assets/images/icon-support.svg b/src/Symfony/Component/ErrorHandler/Resources/assets/images/icon-support.svg similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/assets/images/icon-support.svg rename to src/Symfony/Component/ErrorHandler/Resources/assets/images/icon-support.svg diff --git a/src/Symfony/Component/ErrorRenderer/Resources/assets/images/symfony-ghost.svg.php b/src/Symfony/Component/ErrorHandler/Resources/assets/images/symfony-ghost.svg.php similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/assets/images/symfony-ghost.svg.php rename to src/Symfony/Component/ErrorHandler/Resources/assets/images/symfony-ghost.svg.php diff --git a/src/Symfony/Component/ErrorRenderer/Resources/assets/images/symfony-logo.svg b/src/Symfony/Component/ErrorHandler/Resources/assets/images/symfony-logo.svg similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/assets/images/symfony-logo.svg rename to src/Symfony/Component/ErrorHandler/Resources/assets/images/symfony-logo.svg diff --git a/src/Symfony/Component/ErrorRenderer/Resources/assets/js/exception.js b/src/Symfony/Component/ErrorHandler/Resources/assets/js/exception.js similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/assets/js/exception.js rename to src/Symfony/Component/ErrorHandler/Resources/assets/js/exception.js diff --git a/src/Symfony/Component/ErrorHandler/Resources/stubs/Debug.php b/src/Symfony/Component/ErrorHandler/Resources/stubs/Debug.php deleted file mode 100644 index 2a3f8bed79..0000000000 --- a/src/Symfony/Component/ErrorHandler/Resources/stubs/Debug.php +++ /dev/null @@ -1,25 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Debug; - -if (!class_exists(Debug::class, false)) { - class_alias(\Symfony\Component\ErrorHandler\Debug::class, Debug::class); -} - -if (false) { - /** - * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Debug instead. - */ - class Debug extends \Symfony\Component\ErrorHandler\Debug - { - } -} diff --git a/src/Symfony/Component/ErrorRenderer/Resources/views/error.html.php b/src/Symfony/Component/ErrorHandler/Resources/views/error.html.php similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/views/error.html.php rename to src/Symfony/Component/ErrorHandler/Resources/views/error.html.php diff --git a/src/Symfony/Component/ErrorRenderer/Resources/views/exception.html.php b/src/Symfony/Component/ErrorHandler/Resources/views/exception.html.php similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/views/exception.html.php rename to src/Symfony/Component/ErrorHandler/Resources/views/exception.html.php diff --git a/src/Symfony/Component/ErrorHandler/Resources/views/exception_full.html.php b/src/Symfony/Component/ErrorHandler/Resources/views/exception_full.html.php new file mode 100644 index 0000000000..4d46d59de5 --- /dev/null +++ b/src/Symfony/Component/ErrorHandler/Resources/views/exception_full.html.php @@ -0,0 +1,43 @@ + + + + + + + + <?= $_message; ?> + + + + + + +
+ +
+ + + include('views/exception.html.php', $context); ?> + + + + + diff --git a/src/Symfony/Component/ErrorRenderer/Resources/views/logs.html.php b/src/Symfony/Component/ErrorHandler/Resources/views/logs.html.php similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/views/logs.html.php rename to src/Symfony/Component/ErrorHandler/Resources/views/logs.html.php diff --git a/src/Symfony/Component/ErrorRenderer/Resources/views/trace.html.php b/src/Symfony/Component/ErrorHandler/Resources/views/trace.html.php similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/views/trace.html.php rename to src/Symfony/Component/ErrorHandler/Resources/views/trace.html.php diff --git a/src/Symfony/Component/ErrorRenderer/Resources/views/traces.html.php b/src/Symfony/Component/ErrorHandler/Resources/views/traces.html.php similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/views/traces.html.php rename to src/Symfony/Component/ErrorHandler/Resources/views/traces.html.php diff --git a/src/Symfony/Component/ErrorRenderer/Resources/views/traces_text.html.php b/src/Symfony/Component/ErrorHandler/Resources/views/traces_text.html.php similarity index 100% rename from src/Symfony/Component/ErrorRenderer/Resources/views/traces_text.html.php rename to src/Symfony/Component/ErrorHandler/Resources/views/traces_text.html.php diff --git a/src/Symfony/Component/ErrorHandler/Tests/ErrorRenderer/ErrorRendererTest.php b/src/Symfony/Component/ErrorHandler/Tests/ErrorRenderer/ErrorRendererTest.php new file mode 100644 index 0000000000..6ac134b793 --- /dev/null +++ b/src/Symfony/Component/ErrorHandler/Tests/ErrorRenderer/ErrorRendererTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\Tests\ErrorRenderer; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRenderer; +use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRendererInterface; +use Symfony\Component\ErrorHandler\Exception\FlattenException; +use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Symfony\Component\Serializer\Normalizer\ProblemNormalizer; +use Symfony\Component\Serializer\Serializer; + +class ErrorRendererTest extends TestCase +{ + public function testDefaultContent() + { + $errorRenderer = new ErrorRenderer(); + + self::assertStringContainsString('

The server returned a "500 Internal Server Error".

', $errorRenderer->render(new \RuntimeException(), 'html')); + } + + public function testCustomContent() + { + $errorRenderer = new ErrorRenderer(new CustomHtmlErrorRenderer()); + + $this->assertSame('Foo', $errorRenderer->render(new \RuntimeException('Foo'), 'html')); + } + + public function testSerializerContent() + { + $exception = new \RuntimeException('Foo'); + $errorRenderer = new ErrorRenderer(null, new Serializer([new ProblemNormalizer()], [new JsonEncoder()])); + + $this->assertSame('{"type":"https:\/\/tools.ietf.org\/html\/rfc2616#section-10","title":"An error occurred","status":500,"detail":"Internal Server Error"}', $errorRenderer->render($exception, 'json')); + } +} + +class CustomHtmlErrorRenderer implements HtmlErrorRendererInterface +{ + public function render(FlattenException $exception): string + { + return $exception->getMessage(); + } +} diff --git a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/HtmlErrorRendererTest.php b/src/Symfony/Component/ErrorHandler/Tests/ErrorRenderer/HtmlErrorRendererTest.php similarity index 58% rename from src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/HtmlErrorRendererTest.php rename to src/Symfony/Component/ErrorHandler/Tests/ErrorRenderer/HtmlErrorRendererTest.php index 4868d215c4..e2b81f20e5 100644 --- a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/HtmlErrorRendererTest.php +++ b/src/Symfony/Component/ErrorHandler/Tests/ErrorRenderer/HtmlErrorRendererTest.php @@ -9,21 +9,20 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\ErrorRenderer\Tests\ErrorRenderer; +namespace Symfony\Component\ErrorHandler\Tests\ErrorRenderer; use PHPUnit\Framework\TestCase; -use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRendererInterface; -use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; +use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer; +use Symfony\Component\ErrorHandler\Exception\FlattenException; class HtmlErrorRendererTest extends TestCase { /** * @dataProvider getRenderData */ - public function testRender(FlattenException $exception, ErrorRendererInterface $errorRenderer, string $expected) + public function testRender(FlattenException $exception, HtmlErrorRenderer $errorRenderer, string $expected) { - $this->assertStringMatchesFormat($expected, $errorRenderer->render($exception)); + $this->assertStringMatchesFormat($expected, $errorRenderer->render($exception)->getAsString()); } public function getRenderData(): iterable @@ -55,17 +54,5 @@ HTML; new HtmlErrorRenderer(false), $expectedNonDebug, ]; - - yield '->render() returns the HTML content WITHOUT stack traces in debug mode FORCING non-debug via X-Debug header' => [ - FlattenException::createFromThrowable(new \RuntimeException('Foo'), null, ['X-Debug' => false]), - new HtmlErrorRenderer(true), - $expectedNonDebug, - ]; - - yield '->render() returns the HTML content WITHOUT stack traces in non-debug mode EVEN FORCING debug via X-Debug header' => [ - FlattenException::createFromThrowable(new \RuntimeException('Foo'), null, ['X-Debug' => true]), - new HtmlErrorRenderer(false), - $expectedNonDebug, - ]; } } diff --git a/src/Symfony/Component/ErrorRenderer/Tests/Exception/FlattenExceptionTest.php b/src/Symfony/Component/ErrorHandler/Tests/Exception/FlattenExceptionTest.php similarity index 99% rename from src/Symfony/Component/ErrorRenderer/Tests/Exception/FlattenExceptionTest.php rename to src/Symfony/Component/ErrorHandler/Tests/Exception/FlattenExceptionTest.php index dad78d1525..3413bd484e 100644 --- a/src/Symfony/Component/ErrorRenderer/Tests/Exception/FlattenExceptionTest.php +++ b/src/Symfony/Component/ErrorHandler/Tests/Exception/FlattenExceptionTest.php @@ -9,10 +9,10 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\ErrorRenderer\Tests\Exception; +namespace Symfony\Component\ErrorHandler\Tests\Exception; use PHPUnit\Framework\TestCase; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; diff --git a/src/Symfony/Component/ErrorHandler/composer.json b/src/Symfony/Component/ErrorHandler/composer.json index dd5e0d0679..bbde24ad91 100644 --- a/src/Symfony/Component/ErrorHandler/composer.json +++ b/src/Symfony/Component/ErrorHandler/composer.json @@ -17,20 +17,18 @@ ], "require": { "php": "^7.1.3", - "psr/log": "~1.0" + "psr/log": "~1.0", + "symfony/debug": "^4.4", + "symfony/var-dumper": "^4.4|^5.0" }, "require-dev": { - "symfony/http-kernel": "^3.4|^4.0|^5.0" - }, - "suggest": { - "symfony/error-renderer": "For better error rendering" + "symfony/http-kernel": "^4.4|^5.0" }, "conflict": { - "symfony/http-kernel": "<3.4" + "symfony/http-kernel": "<4.4" }, "autoload": { "psr-4": { "Symfony\\Component\\ErrorHandler\\": "" }, - "classmap": [ "Resources/stubs/Debug.php" ], "exclude-from-classmap": [ "/Tests/" ] diff --git a/src/Symfony/Component/ErrorRenderer/.gitattributes b/src/Symfony/Component/ErrorRenderer/.gitattributes deleted file mode 100644 index ebb9287043..0000000000 --- a/src/Symfony/Component/ErrorRenderer/.gitattributes +++ /dev/null @@ -1,3 +0,0 @@ -/Tests export-ignore -/phpunit.xml.dist export-ignore -/.gitignore export-ignore diff --git a/src/Symfony/Component/ErrorRenderer/.gitignore b/src/Symfony/Component/ErrorRenderer/.gitignore deleted file mode 100644 index c49a5d8df5..0000000000 --- a/src/Symfony/Component/ErrorRenderer/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -vendor/ -composer.lock -phpunit.xml diff --git a/src/Symfony/Component/ErrorRenderer/CHANGELOG.md b/src/Symfony/Component/ErrorRenderer/CHANGELOG.md deleted file mode 100644 index 094072510d..0000000000 --- a/src/Symfony/Component/ErrorRenderer/CHANGELOG.md +++ /dev/null @@ -1,7 +0,0 @@ -CHANGELOG -========= - -4.4.0 ------ - - * added the component diff --git a/src/Symfony/Component/ErrorRenderer/Command/DebugCommand.php b/src/Symfony/Component/ErrorRenderer/Command/DebugCommand.php deleted file mode 100644 index 58cb57b68c..0000000000 --- a/src/Symfony/Component/ErrorRenderer/Command/DebugCommand.php +++ /dev/null @@ -1,125 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorRenderer\Command; - -use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Exception\InvalidArgumentException; -use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Style\SymfonyStyle; -use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRendererInterface; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; -use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; - -/** - * A console command for retrieving information about error renderers. - * - * @author Yonel Ceruto - * - * @internal - */ -class DebugCommand extends Command -{ - protected static $defaultName = 'debug:error-renderer'; - - private $renderers; - private $fileLinkFormatter; - - /** - * @param ErrorRendererInterface[] $renderers - */ - public function __construct(array $renderers, FileLinkFormatter $fileLinkFormatter = null) - { - $this->renderers = $renderers; - $this->fileLinkFormatter = $fileLinkFormatter; - - parent::__construct(); - } - - /** - * {@inheritdoc} - */ - protected function configure(): void - { - $this - ->addArgument('format', InputArgument::OPTIONAL, sprintf('Outputs a sample in a specific format (one of %s)', implode(', ', array_keys($this->renderers)))) - ->setDescription('Displays all available error renderers and their formats.') - ->setHelp(<<<'EOF' -The %command.name% command displays all available error renderers and -their formats: - - php %command.full_name% - -Or output a sample in a specific format: - - php %command.full_name% json - -EOF - ) - ; - } - - /** - * {@inheritdoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) - { - $io = new SymfonyStyle($input, $output); - $renderers = $this->renderers; - - if ($format = $input->getArgument('format')) { - if (!isset($renderers[$format])) { - throw new InvalidArgumentException(sprintf('No error renderer found for format "%s". Known format are %s.', $format, implode(', ', array_keys($this->renderers)))); - } - - $exception = FlattenException::createFromThrowable(new \Exception('This is a sample exception.'), 500, ['X-Debug' => false]); - $io->writeln($renderers[$format]->render($exception)); - } else { - $tableRows = []; - foreach ($renderers as $format => $renderer) { - $tableRows[] = [sprintf('%s', $format), $this->formatClassLink(\get_class($renderer))]; - } - - $io->title('Error Renderers'); - $io->text('The following error renderers are available:'); - $io->newLine(); - $io->table(['Format', 'Class'], $tableRows); - } - - return 0; - } - - private function formatClassLink(string $class): string - { - if ('' === $fileLink = $this->getFileLink($class)) { - return $class; - } - - return sprintf('%s', $fileLink, $class); - } - - private function getFileLink(string $class): string - { - if (null === $this->fileLinkFormatter) { - return ''; - } - - try { - $r = new \ReflectionClass($class); - } catch (\ReflectionException $e) { - return ''; - } - - return $this->fileLinkFormatter->format($r->getFileName(), $r->getStartLine()); - } -} diff --git a/src/Symfony/Component/ErrorRenderer/DependencyInjection/ErrorRendererPass.php b/src/Symfony/Component/ErrorRenderer/DependencyInjection/ErrorRendererPass.php deleted file mode 100644 index 1e297b7de1..0000000000 --- a/src/Symfony/Component/ErrorRenderer/DependencyInjection/ErrorRendererPass.php +++ /dev/null @@ -1,71 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorRenderer\DependencyInjection; - -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRendererInterface; - -/** - * @author Yonel Ceruto - */ -class ErrorRendererPass implements CompilerPassInterface -{ - private $rendererService; - private $rendererTag; - private $debugCommandService; - - public function __construct(string $rendererService = 'error_renderer', string $rendererTag = 'error_renderer.renderer', string $debugCommandService = 'console.command.error_renderer_debug') - { - $this->rendererService = $rendererService; - $this->rendererTag = $rendererTag; - $this->debugCommandService = $debugCommandService; - } - - /** - * {@inheritdoc} - */ - public function process(ContainerBuilder $container) - { - if (!$container->hasDefinition($this->rendererService)) { - return; - } - - $renderers = []; - foreach ($container->findTaggedServiceIds($this->rendererTag, true) as $serviceId => $tags) { - /** @var ErrorRendererInterface $class */ - $class = $container->getDefinition($serviceId)->getClass(); - - foreach ($tags as $tag) { - $format = $tag['format'] ?? $class::getFormat(); - $priority = $tag['priority'] ?? 0; - if (!isset($renderers[$priority][$format])) { - $renderers[$priority][$format] = new Reference($serviceId); - } - } - } - - if ($renderers) { - ksort($renderers); - $renderers = array_merge(...$renderers); - } - - $definition = $container->getDefinition($this->rendererService); - $definition->replaceArgument(0, ServiceLocatorTagPass::register($container, $renderers)); - - if ($container->hasDefinition($this->debugCommandService)) { - $container->getDefinition($this->debugCommandService)->replaceArgument(0, $renderers); - } - } -} diff --git a/src/Symfony/Component/ErrorRenderer/DependencyInjection/LazyLoadingErrorRenderer.php b/src/Symfony/Component/ErrorRenderer/DependencyInjection/LazyLoadingErrorRenderer.php deleted file mode 100644 index 82936a29af..0000000000 --- a/src/Symfony/Component/ErrorRenderer/DependencyInjection/LazyLoadingErrorRenderer.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorRenderer\DependencyInjection; - -use Psr\Container\ContainerInterface; -use Symfony\Component\ErrorRenderer\ErrorRenderer; - -/** - * Lazily loads error renderers from the dependency injection container. - * - * @author Yonel Ceruto - */ -class LazyLoadingErrorRenderer extends ErrorRenderer -{ - private $container; - private $initialized = []; - - public function __construct(ContainerInterface $container) - { - $this->container = $container; - } - - /** - * {@inheritdoc} - */ - public function render($exception, string $format = 'html'): string - { - if (!isset($this->initialized[$format]) && $this->container->has($format)) { - $this->addRenderer($this->container->get($format), $format); - $this->initialized[$format] = true; - } - - return parent::render($exception, $format); - } -} diff --git a/src/Symfony/Component/ErrorRenderer/ErrorRenderer.php b/src/Symfony/Component/ErrorRenderer/ErrorRenderer.php deleted file mode 100644 index da984bdd18..0000000000 --- a/src/Symfony/Component/ErrorRenderer/ErrorRenderer.php +++ /dev/null @@ -1,77 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorRenderer; - -use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRendererInterface; -use Symfony\Component\ErrorRenderer\Exception\ErrorRendererNotFoundException; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; - -/** - * Formats an exception to be used as response content. - * - * It delegates to implementations of ErrorRendererInterface depending on the format. - * - * @see ErrorRendererInterface - * - * @author Yonel Ceruto - */ -class ErrorRenderer -{ - private $renderers = []; - - /** - * @param ErrorRendererInterface[] $renderers - */ - public function __construct(iterable $renderers) - { - foreach ($renderers as $renderer) { - $this->addRenderer($renderer); - } - } - - /** - * Registers an error renderer that is format specific. - * - * By passing an explicit format you can register a renderer for a different format than what - * ErrorRendererInterface::getFormat() would return in order to register the same renderer for - * several format aliases. - */ - public function addRenderer(ErrorRendererInterface $renderer, string $format = null): self - { - $this->renderers[$format ?? $renderer::getFormat()] = $renderer; - - return $this; - } - - /** - * Renders an Exception and returns the Response content. - * - * @param \Throwable|FlattenException $exception A \Throwable or FlattenException instance - * @param string $format The request format (html, json, xml, etc.) - * - * @return string The Response content as a string - * - * @throws ErrorRendererNotFoundException if no renderer is found - */ - public function render($exception, string $format = 'html'): string - { - if (!isset($this->renderers[$format])) { - throw new ErrorRendererNotFoundException(sprintf('No error renderer found for format "%s".', $format)); - } - - if ($exception instanceof \Throwable) { - $exception = FlattenException::createFromThrowable($exception); - } - - return $this->renderers[$format]->render($exception); - } -} diff --git a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/ErrorRendererInterface.php b/src/Symfony/Component/ErrorRenderer/ErrorRenderer/ErrorRendererInterface.php deleted file mode 100644 index 5c0d580602..0000000000 --- a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/ErrorRendererInterface.php +++ /dev/null @@ -1,32 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorRenderer\ErrorRenderer; - -use Symfony\Component\ErrorRenderer\Exception\FlattenException; - -/** - * Interface for classes that can render errors in a specific format. - * - * @author Yonel Ceruto - */ -interface ErrorRendererInterface -{ - /** - * Gets the format this renderer can return errors as. - */ - public static function getFormat(): string; - - /** - * Returns the response content of the rendered exception. - */ - public function render(FlattenException $exception): string; -} diff --git a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/JsonErrorRenderer.php b/src/Symfony/Component/ErrorRenderer/ErrorRenderer/JsonErrorRenderer.php deleted file mode 100644 index d708fb0f15..0000000000 --- a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/JsonErrorRenderer.php +++ /dev/null @@ -1,60 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorRenderer\ErrorRenderer; - -use Symfony\Component\ErrorRenderer\Exception\FlattenException; - -/** - * @author Yonel Ceruto - */ -class JsonErrorRenderer implements ErrorRendererInterface -{ - private $debug; - - public function __construct(bool $debug = false) - { - $this->debug = $debug; - } - - /** - * {@inheritdoc} - */ - public static function getFormat(): string - { - return 'json'; - } - - /** - * {@inheritdoc} - */ - public function render(FlattenException $exception): string - { - $debug = $this->debug && ($exception->getHeaders()['X-Debug'] ?? true); - - if ($debug) { - $message = $exception->getMessage(); - } else { - $message = 404 === $exception->getStatusCode() ? 'Sorry, the page you are looking for could not be found.' : 'Whoops, looks like something went wrong.'; - } - - $content = [ - 'title' => $exception->getTitle(), - 'status' => $exception->getStatusCode(), - 'detail' => $message, - ]; - if ($debug) { - $content['exceptions'] = $exception->toArray(); - } - - return (string) json_encode($content, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_LINE_TERMINATORS | JSON_PRESERVE_ZERO_FRACTION); - } -} diff --git a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/TxtErrorRenderer.php b/src/Symfony/Component/ErrorRenderer/ErrorRenderer/TxtErrorRenderer.php deleted file mode 100644 index 2bafb2cfb4..0000000000 --- a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/TxtErrorRenderer.php +++ /dev/null @@ -1,104 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorRenderer\ErrorRenderer; - -use Symfony\Component\ErrorRenderer\Exception\FlattenException; - -/** - * @author Yonel Ceruto - */ -class TxtErrorRenderer implements ErrorRendererInterface -{ - private $debug; - - public function __construct(bool $debug = false) - { - $this->debug = $debug; - } - - /** - * {@inheritdoc} - */ - public static function getFormat(): string - { - return 'txt'; - } - - /** - * {@inheritdoc} - */ - public function render(FlattenException $exception): string - { - $debug = $this->debug && ($exception->getHeaders()['X-Debug'] ?? true); - - if ($debug) { - $message = $exception->getMessage(); - } else { - $message = 404 === $exception->getStatusCode() ? 'Sorry, the page you are looking for could not be found.' : 'Whoops, looks like something went wrong.'; - } - - $content = sprintf("[title] %s\n", $exception->getTitle()); - $content .= sprintf("[status] %s\n", $exception->getStatusCode()); - $content .= sprintf("[detail] %s\n", $message); - - if ($debug) { - foreach ($exception->toArray() as $i => $e) { - $content .= sprintf("[%d] %s: %s\n", $i + 1, $e['class'], $e['message']); - foreach ($e['trace'] as $trace) { - if ($trace['function']) { - $content .= sprintf('at %s%s%s(%s) ', $trace['class'], $trace['type'], $trace['function'], $this->formatArgs($trace['args'])); - } - if (isset($trace['file'], $trace['line'])) { - $content .= $this->formatPath($trace['file'], $trace['line']); - } - $content .= "\n"; - } - } - } - - return $content; - } - - private function formatPath(string $path, int $line): string - { - $file = preg_match('#[^/\\\\]*+$#', $path, $file) ? $file[0] : $path; - - return sprintf('in %s %s', $path, 0 < $line ? ' line '.$line : ''); - } - - /** - * Formats an array as a string. - */ - private function formatArgs(array $args): string - { - $result = []; - foreach ($args as $key => $item) { - if ('object' === $item[0]) { - $formattedValue = sprintf('object(%s)', $item[1]); - } elseif ('array' === $item[0]) { - $formattedValue = sprintf('array(%s)', \is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]); - } elseif ('null' === $item[0]) { - $formattedValue = 'null'; - } elseif ('boolean' === $item[0]) { - $formattedValue = strtolower(var_export($item[1], true)); - } elseif ('resource' === $item[0]) { - $formattedValue = 'resource'; - } else { - $formattedValue = str_replace("\n", '', var_export($item[1], true)); - } - - $result[] = \is_int($key) ? $formattedValue : sprintf("'%s' => %s", $key, $formattedValue); - } - - return implode(', ', $result); - } -} diff --git a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/XmlErrorRenderer.php b/src/Symfony/Component/ErrorRenderer/ErrorRenderer/XmlErrorRenderer.php deleted file mode 100644 index 290e0a63ff..0000000000 --- a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/XmlErrorRenderer.php +++ /dev/null @@ -1,125 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorRenderer\ErrorRenderer; - -use Symfony\Component\ErrorRenderer\Exception\FlattenException; - -/** - * @author Yonel Ceruto - */ -class XmlErrorRenderer implements ErrorRendererInterface -{ - private $debug; - private $charset; - - public function __construct(bool $debug = false, string $charset = null) - { - $this->debug = $debug; - $this->charset = $charset ?: (ini_get('default_charset') ?: 'UTF-8'); - } - - /** - * {@inheritdoc} - */ - public static function getFormat(): string - { - return 'xml'; - } - - /** - * {@inheritdoc} - */ - public function render(FlattenException $exception): string - { - $debug = $this->debug && ($exception->getHeaders()['X-Debug'] ?? true); - $title = $this->escapeXml($exception->getTitle()); - if ($debug) { - $message = $this->escapeXml($exception->getMessage()); - } else { - $message = 404 === $exception->getStatusCode() ? 'Sorry, the page you are looking for could not be found.' : 'Whoops, looks like something went wrong.'; - } - $statusCode = $this->escapeXml($exception->getStatusCode()); - $charset = $this->escapeXml($this->charset); - - $exceptions = ''; - if ($debug) { - $exceptions .= ''; - foreach ($exception->toArray() as $e) { - $exceptions .= sprintf('', $e['class'], $this->escapeXml($e['message'])); - foreach ($e['trace'] as $trace) { - $exceptions .= ''; - if ($trace['function']) { - $exceptions .= sprintf('at %s%s%s(%s) ', $trace['class'], $trace['type'], $trace['function'], $this->formatArgs($trace['args'])); - } - if (isset($trace['file'], $trace['line'])) { - $exceptions .= $this->formatPath($trace['file'], $trace['line']); - } - $exceptions .= ''; - } - $exceptions .= ''; - } - $exceptions .= ''; - } - - return << - - {$title} - {$statusCode} - {$message} - {$exceptions} - -EOF; - } - - /** - * XML-encodes a string. - */ - private function escapeXml(string $str): string - { - return htmlspecialchars($str, ENT_COMPAT | ENT_SUBSTITUTE, $this->charset); - } - - private function formatPath(string $path, int $line): string - { - $file = $this->escapeXml(preg_match('#[^/\\\\]*+$#', $path, $file) ? $file[0] : $path); - - return sprintf('in %s %s', $this->escapeXml($path), 0 < $line ? ' line '.$line : ''); - } - - /** - * Formats an array as a string. - */ - private function formatArgs(array $args): string - { - $result = []; - foreach ($args as $key => $item) { - if ('object' === $item[0]) { - $formattedValue = sprintf('object(%s)', $item[1]); - } elseif ('array' === $item[0]) { - $formattedValue = sprintf('array(%s)', \is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]); - } elseif ('null' === $item[0]) { - $formattedValue = 'null'; - } elseif ('boolean' === $item[0]) { - $formattedValue = strtolower(var_export($item[1], true)); - } elseif ('resource' === $item[0]) { - $formattedValue = 'resource'; - } else { - $formattedValue = str_replace("\n", '', $this->escapeXml(var_export($item[1], true))); - } - - $result[] = \is_int($key) ? $formattedValue : sprintf("'%s' => %s", $this->escapeXml($key), $formattedValue); - } - - return implode(', ', $result); - } -} diff --git a/src/Symfony/Component/ErrorRenderer/Exception/ErrorRendererNotFoundException.php b/src/Symfony/Component/ErrorRenderer/Exception/ErrorRendererNotFoundException.php deleted file mode 100644 index 4020ced161..0000000000 --- a/src/Symfony/Component/ErrorRenderer/Exception/ErrorRendererNotFoundException.php +++ /dev/null @@ -1,16 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorRenderer\Exception; - -class ErrorRendererNotFoundException extends \RuntimeException -{ -} diff --git a/src/Symfony/Component/ErrorRenderer/LICENSE b/src/Symfony/Component/ErrorRenderer/LICENSE deleted file mode 100644 index 1a1869751d..0000000000 --- a/src/Symfony/Component/ErrorRenderer/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2019 Fabien Potencier - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/src/Symfony/Component/ErrorRenderer/README.md b/src/Symfony/Component/ErrorRenderer/README.md deleted file mode 100644 index 272c2924d8..0000000000 --- a/src/Symfony/Component/ErrorRenderer/README.md +++ /dev/null @@ -1,12 +0,0 @@ -ErrorRenderer Component -====================== - -The ErrorRenderer component provides tools to display errors and exceptions. - -Resources ---------- - - * [Contributing](https://symfony.com/doc/current/contributing/index.html) - * [Report issues](https://github.com/symfony/symfony/issues) and - [send Pull Requests](https://github.com/symfony/symfony/pulls) - in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/src/Symfony/Component/ErrorRenderer/Resources/views/exception_full.html.php b/src/Symfony/Component/ErrorRenderer/Resources/views/exception_full.html.php deleted file mode 100644 index 7ce8de0666..0000000000 --- a/src/Symfony/Component/ErrorRenderer/Resources/views/exception_full.html.php +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - <?= $_message; ?> - - - - - -
- -
- - include('views/exception.html.php', $context); ?> - - - - - diff --git a/src/Symfony/Component/ErrorRenderer/Tests/Command/DebugCommandTest.php b/src/Symfony/Component/ErrorRenderer/Tests/Command/DebugCommandTest.php deleted file mode 100644 index c5a9768c8b..0000000000 --- a/src/Symfony/Component/ErrorRenderer/Tests/Command/DebugCommandTest.php +++ /dev/null @@ -1,88 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorRenderer\Tests\Command; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Console\Application; -use Symfony\Component\Console\Tester\CommandTester; -use Symfony\Component\ErrorRenderer\Command\DebugCommand; -use Symfony\Component\ErrorRenderer\ErrorRenderer\JsonErrorRenderer; -use Symfony\Component\ErrorRenderer\ErrorRenderer\TxtErrorRenderer; -use Symfony\Component\ErrorRenderer\ErrorRenderer\XmlErrorRenderer; - -class DebugCommandTest extends TestCase -{ - public function testAvailableRenderers() - { - $tester = $this->createCommandTester(); - $ret = $tester->execute([], ['decorated' => false]); - - $this->assertEquals(0, $ret, 'Returns 0 in case of success'); - $this->assertSame(<<getDisplay(true)); - } - - public function testFormatArgument() - { - $tester = $this->createCommandTester(); - $ret = $tester->execute(['format' => 'json'], ['decorated' => false]); - - $this->assertEquals(0, $ret, 'Returns 0 in case of success'); - $this->assertSame(<<getDisplay(true)); - } - - private function createCommandTester() - { - $command = new DebugCommand([ - 'json' => new JsonErrorRenderer(false), - 'xml' => new XmlErrorRenderer(false), - 'txt' => new TxtErrorRenderer(false), - ]); - - $application = new Application(); - $application->add($command); - - return new CommandTester($application->find('debug:error-renderer')); - } - - public function testInvalidFormat() - { - $this->expectException('Symfony\Component\Console\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('No error renderer found for format "foo". Known format are json, xml, txt.'); - $tester = $this->createCommandTester(); - $tester->execute(['format' => 'foo'], ['decorated' => false]); - } -} diff --git a/src/Symfony/Component/ErrorRenderer/Tests/DependencyInjection/ErrorRendererPassTest.php b/src/Symfony/Component/ErrorRenderer/Tests/DependencyInjection/ErrorRendererPassTest.php deleted file mode 100644 index e69fd860b8..0000000000 --- a/src/Symfony/Component/ErrorRenderer/Tests/DependencyInjection/ErrorRendererPassTest.php +++ /dev/null @@ -1,67 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorRenderer\Tests\DependencyInjection; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\ServiceLocator; -use Symfony\Component\ErrorRenderer\DependencyInjection\ErrorRendererPass; -use Symfony\Component\ErrorRenderer\DependencyInjection\LazyLoadingErrorRenderer; -use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer; -use Symfony\Component\ErrorRenderer\ErrorRenderer\JsonErrorRenderer; - -class ErrorRendererPassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - $container->setParameter('kernel.debug', true); - $definition = $container->register('error_renderer', LazyLoadingErrorRenderer::class) - ->addArgument([]) - ; - $container->register('error_renderer.renderer.html', HtmlErrorRenderer::class) - ->addTag('error_renderer.renderer') - ; - $container->register('error_renderer.renderer.json', JsonErrorRenderer::class) - ->addTag('error_renderer.renderer') - ; - - (new ErrorRendererPass())->process($container); - - $serviceLocatorDefinition = $container->getDefinition((string) $definition->getArgument(0)); - $this->assertSame(ServiceLocator::class, $serviceLocatorDefinition->getClass()); - - $expected = [ - 'html' => new ServiceClosureArgument(new Reference('error_renderer.renderer.html')), - 'json' => new ServiceClosureArgument(new Reference('error_renderer.renderer.json')), - ]; - $this->assertEquals($expected, $serviceLocatorDefinition->getArgument(0)); - } - - public function testServicesAreOrderedAccordingToPriority() - { - $container = new ContainerBuilder(); - $definition = $container->register('error_renderer')->setArguments([null]); - $container->register('r2')->addTag('error_renderer.renderer', ['format' => 'json', 'priority' => 100]); - $container->register('r1')->addTag('error_renderer.renderer', ['format' => 'json', 'priority' => 200]); - $container->register('r3')->addTag('error_renderer.renderer', ['format' => 'json']); - (new ErrorRendererPass())->process($container); - - $expected = [ - 'json' => new ServiceClosureArgument(new Reference('r1')), - ]; - $serviceLocatorDefinition = $container->getDefinition((string) $definition->getArgument(0)); - $this->assertEquals($expected, $serviceLocatorDefinition->getArgument(0)); - } -} diff --git a/src/Symfony/Component/ErrorRenderer/Tests/DependencyInjection/LazyLoadingErrorRendererTest.php b/src/Symfony/Component/ErrorRenderer/Tests/DependencyInjection/LazyLoadingErrorRendererTest.php deleted file mode 100644 index 5811a0c026..0000000000 --- a/src/Symfony/Component/ErrorRenderer/Tests/DependencyInjection/LazyLoadingErrorRendererTest.php +++ /dev/null @@ -1,66 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorRenderer\Tests\DependencyInjection; - -use PHPUnit\Framework\TestCase; -use Psr\Container\ContainerInterface; -use Symfony\Component\ErrorRenderer\DependencyInjection\LazyLoadingErrorRenderer; -use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRendererInterface; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; - -class LazyLoadingErrorRendererTest extends TestCase -{ - public function testInvalidErrorRenderer() - { - $this->expectException('Symfony\Component\ErrorRenderer\Exception\ErrorRendererNotFoundException'); - $this->expectExceptionMessage('No error renderer found for format "foo".'); - $container = $this->getMockBuilder(ContainerInterface::class)->getMock(); - $container->expects($this->once())->method('has')->with('foo')->willReturn(false); - - $exception = FlattenException::createFromThrowable(new \Exception('Foo')); - (new LazyLoadingErrorRenderer($container))->render($exception, 'foo'); - } - - public function testCustomErrorRenderer() - { - $container = $this->getMockBuilder(ContainerInterface::class)->getMock(); - $container - ->expects($this->once()) - ->method('has') - ->with('foo') - ->willReturn(true) - ; - $container - ->expects($this->once()) - ->method('get') - ->willReturn(new FooErrorRenderer()) - ; - - $errorRenderer = new LazyLoadingErrorRenderer($container); - - $exception = FlattenException::createFromThrowable(new \RuntimeException('Foo')); - $this->assertSame('Foo', $errorRenderer->render($exception, 'foo')); - } -} - -class FooErrorRenderer implements ErrorRendererInterface -{ - public static function getFormat(): string - { - return 'foo'; - } - - public function render(FlattenException $exception): string - { - return $exception->getMessage(); - } -} diff --git a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/JsonErrorRendererTest.php b/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/JsonErrorRendererTest.php deleted file mode 100644 index 55e6d5cdf2..0000000000 --- a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/JsonErrorRendererTest.php +++ /dev/null @@ -1,76 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorRenderer\Tests\ErrorRenderer; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRendererInterface; -use Symfony\Component\ErrorRenderer\ErrorRenderer\JsonErrorRenderer; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; - -class JsonErrorRendererTest extends TestCase -{ - /** - * @dataProvider getRenderData - */ - public function testRender(FlattenException $exception, ErrorRendererInterface $errorRenderer, string $expected) - { - $this->assertStringMatchesFormat($expected, $errorRenderer->render($exception)); - } - - public function getRenderData(): iterable - { - $expectedDebug = <<render() returns the JSON content WITH stack traces in debug mode' => [ - FlattenException::createFromThrowable(new \RuntimeException('Foo')), - new JsonErrorRenderer(true), - $expectedDebug, - ]; - - yield '->render() returns the JSON content WITHOUT stack traces in non-debug mode' => [ - FlattenException::createFromThrowable(new \RuntimeException('Foo')), - new JsonErrorRenderer(false), - $expectedNonDebug, - ]; - - yield '->render() returns the JSON content WITHOUT stack traces in debug mode FORCING non-debug via X-Debug header' => [ - FlattenException::createFromThrowable(new \RuntimeException('Foo'), null, ['X-Debug' => false]), - new JsonErrorRenderer(true), - $expectedNonDebug, - ]; - - yield '->render() returns the JSON content WITHOUT stack traces in non-debug mode EVEN FORCING debug via X-Debug header' => [ - FlattenException::createFromThrowable(new \RuntimeException('Foo'), null, ['X-Debug' => true]), - new JsonErrorRenderer(false), - $expectedNonDebug, - ]; - } -} diff --git a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/TxtErrorRendererTest.php b/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/TxtErrorRendererTest.php deleted file mode 100644 index b6c1570df8..0000000000 --- a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/TxtErrorRendererTest.php +++ /dev/null @@ -1,69 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorRenderer\Tests\ErrorRenderer; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRendererInterface; -use Symfony\Component\ErrorRenderer\ErrorRenderer\TxtErrorRenderer; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; - -class TxtErrorRendererTest extends TestCase -{ - /** - * @dataProvider getRenderData - */ - public function testRender(FlattenException $exception, ErrorRendererInterface $errorRenderer, string $expected) - { - $this->assertStringMatchesFormat($expected, $errorRenderer->render($exception)); - } - - public function getRenderData(): iterable - { - $expectedDebug = <<render() returns the TXT content WITH stack traces in debug mode' => [ - FlattenException::createFromThrowable(new \RuntimeException('Foo')), - new TxtErrorRenderer(true), - $expectedDebug, - ]; - - yield '->render() returns the TXT content WITHOUT stack traces in non-debug mode' => [ - FlattenException::createFromThrowable(new \RuntimeException('Foo')), - new TxtErrorRenderer(false), - $expectedNonDebug, - ]; - - yield '->render() returns the TXT content WITHOUT stack traces in debug mode FORCING non-debug via X-Debug header' => [ - FlattenException::createFromThrowable(new \RuntimeException('Foo'), null, ['X-Debug' => false]), - new TxtErrorRenderer(true), - $expectedNonDebug, - ]; - - yield '->render() returns the TXT content WITHOUT stack traces in non-debug mode EVEN FORCING debug via X-Debug header' => [ - FlattenException::createFromThrowable(new \RuntimeException('Foo'), null, ['X-Debug' => true]), - new TxtErrorRenderer(false), - $expectedNonDebug, - ]; - } -} diff --git a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/XmlErrorRendererTest.php b/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/XmlErrorRendererTest.php deleted file mode 100644 index 3a756720ec..0000000000 --- a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/XmlErrorRendererTest.php +++ /dev/null @@ -1,75 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorRenderer\Tests\ErrorRenderer; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRendererInterface; -use Symfony\Component\ErrorRenderer\ErrorRenderer\XmlErrorRenderer; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; - -class XmlErrorRendererTest extends TestCase -{ - /** - * @dataProvider getRenderData - */ - public function testRender(FlattenException $exception, ErrorRendererInterface $errorRenderer, string $expected) - { - $this->assertStringMatchesFormat($expected, $errorRenderer->render($exception)); - } - - public function getRenderData(): iterable - { - $expectedDebug = << - - Internal Server Error - 500 - Foo - %A - -XML; - - $expectedNonDebug = << - - Internal Server Error - 500 - Whoops, looks like something went wrong. - - -XML; - - yield '->render() returns the XML content WITH stack traces in debug mode' => [ - FlattenException::createFromThrowable(new \RuntimeException('Foo')), - new XmlErrorRenderer(true), - $expectedDebug, - ]; - - yield '->render() returns the XML content WITHOUT stack traces in non-debug mode' => [ - FlattenException::createFromThrowable(new \RuntimeException('Foo')), - new XmlErrorRenderer(false), - $expectedNonDebug, - ]; - - yield '->render() returns the XML content WITHOUT stack traces in debug mode FORCING non-debug via X-Debug header' => [ - FlattenException::createFromThrowable(new \RuntimeException('Foo'), null, ['X-Debug' => false]), - new XmlErrorRenderer(true), - $expectedNonDebug, - ]; - - yield '->render() returns the XML content WITHOUT stack traces in non-debug mode EVEN FORCING debug via X-Debug header' => [ - FlattenException::createFromThrowable(new \RuntimeException('Foo'), null, ['X-Debug' => true]), - new XmlErrorRenderer(false), - $expectedNonDebug, - ]; - } -} diff --git a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRendererTest.php b/src/Symfony/Component/ErrorRenderer/Tests/ErrorRendererTest.php deleted file mode 100644 index 11ef6a7d7e..0000000000 --- a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRendererTest.php +++ /dev/null @@ -1,56 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorRenderer\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\ErrorRenderer\ErrorRenderer; -use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRendererInterface; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; - -class ErrorRendererTest extends TestCase -{ - public function testErrorRendererNotFound() - { - $this->expectException('Symfony\Component\ErrorRenderer\Exception\ErrorRendererNotFoundException'); - $this->expectExceptionMessage('No error renderer found for format "foo".'); - $exception = FlattenException::createFromThrowable(new \Exception('foo')); - (new ErrorRenderer([]))->render($exception, 'foo'); - } - - public function testInvalidErrorRenderer() - { - $this->expectException('TypeError'); - new ErrorRenderer([new \stdClass()]); - } - - public function testCustomErrorRenderer() - { - $renderers = [new FooErrorRenderer()]; - $errorRenderer = new ErrorRenderer($renderers); - - $exception = FlattenException::createFromThrowable(new \RuntimeException('Foo')); - $this->assertSame('Foo', $errorRenderer->render($exception, 'foo')); - } -} - -class FooErrorRenderer implements ErrorRendererInterface -{ - public static function getFormat(): string - { - return 'foo'; - } - - public function render(FlattenException $exception): string - { - return $exception->getMessage(); - } -} diff --git a/src/Symfony/Component/ErrorRenderer/composer.json b/src/Symfony/Component/ErrorRenderer/composer.json deleted file mode 100644 index 90351239fc..0000000000 --- a/src/Symfony/Component/ErrorRenderer/composer.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "symfony/error-renderer", - "type": "library", - "description": "Symfony ErrorRenderer Component", - "keywords": [], - "homepage": "https://symfony.com", - "license": "MIT", - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Yonel Ceruto", - "email": "yonelceruto@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "require": { - "php": "^7.1.3", - "psr/log": "~1.0", - "symfony/debug": "^4.4" - }, - "require-dev": { - "symfony/console": "^4.4", - "symfony/dependency-injection": "^4.4", - "symfony/http-kernel": "^4.4" - }, - "conflict": { - "symfony/http-kernel": "<4.4" - }, - "autoload": { - "psr-4": { "Symfony\\Component\\ErrorRenderer\\": "" }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "minimum-stability": "dev", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - } -} diff --git a/src/Symfony/Component/ErrorRenderer/phpunit.xml.dist b/src/Symfony/Component/ErrorRenderer/phpunit.xml.dist deleted file mode 100644 index c4c29459f3..0000000000 --- a/src/Symfony/Component/ErrorRenderer/phpunit.xml.dist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - ./Tests/ - - - - - - ./ - - ./Tests - ./vendor - - - - diff --git a/src/Symfony/Component/HttpKernel/Controller/ErrorController.php b/src/Symfony/Component/HttpKernel/Controller/ErrorController.php index a86fa5c5cf..3e5447928b 100644 --- a/src/Symfony/Component/HttpKernel/Controller/ErrorController.php +++ b/src/Symfony/Component/HttpKernel/Controller/ErrorController.php @@ -11,9 +11,8 @@ namespace Symfony\Component\HttpKernel\Controller; -use Symfony\Component\ErrorRenderer\ErrorRenderer; -use Symfony\Component\ErrorRenderer\Exception\ErrorRendererNotFoundException; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; +use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRendererInterface; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -30,26 +29,22 @@ class ErrorController private $controller; private $errorRenderer; - public function __construct(HttpKernelInterface $kernel, $controller, ErrorRenderer $errorRenderer) + public function __construct(HttpKernelInterface $kernel, $controller, ErrorRendererInterface $errorRenderer) { $this->kernel = $kernel; $this->controller = $controller; $this->errorRenderer = $errorRenderer; } - public function __invoke(Request $request, FlattenException $exception): Response + public function __invoke(\Throwable $exception): Response { - try { - return new Response($this->errorRenderer->render($exception, $request->getPreferredFormat()), $exception->getStatusCode(), $exception->getHeaders()); - } catch (ErrorRendererNotFoundException $_) { - return new Response($this->errorRenderer->render($exception), $exception->getStatusCode(), $exception->getHeaders()); - } + $exception = $this->errorRenderer->render($exception); + + return new Response($exception->getAsString(), $exception->getStatusCode(), $exception->getHeaders()); } public function preview(Request $request, int $code): Response { - $exception = FlattenException::createFromThrowable(new \Exception('This is a sample exception.'), $code, ['X-Debug' => false]); - /* * This Request mimics the parameters set by * \Symfony\Component\HttpKernel\EventListener\ErrorListener::duplicateRequest, with @@ -57,7 +52,7 @@ class ErrorController */ $subRequest = $request->duplicate(null, null, [ '_controller' => $this->controller, - 'exception' => $exception, + 'exception' => new \Exception('This is a sample exception.'), 'logger' => null, 'showException' => false, ]); diff --git a/src/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php index 08e79c53e1..0a00a2e40e 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php @@ -11,7 +11,7 @@ namespace Symfony\Component\HttpKernel\DataCollector; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; diff --git a/src/Symfony/Component/HttpKernel/EventListener/ErrorListener.php b/src/Symfony/Component/HttpKernel/EventListener/ErrorListener.php index 9a16cde741..fa3300b73e 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/ErrorListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/ErrorListener.php @@ -123,7 +123,7 @@ class ErrorListener implements EventSubscriberInterface { $attributes = [ '_controller' => $this->controller, - 'exception' => FlattenException::createFromThrowable($exception), + 'exception' => $exception, 'logger' => $this->logger instanceof DebugLoggerInterface ? $this->logger : null, ]; $request = $request->duplicate(null, null, $attributes); diff --git a/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php b/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php index dc2fd818ce..aa4349428a 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php @@ -12,7 +12,7 @@ namespace Symfony\Component\HttpKernel\EventListener; use Psr\Log\LoggerInterface; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; diff --git a/src/Symfony/Component/HttpKernel/Tests/Controller/ErrorControllerTest.php b/src/Symfony/Component/HttpKernel/Tests/Controller/ErrorControllerTest.php index 4a64af3ab1..7548dc19e4 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Controller/ErrorControllerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Controller/ErrorControllerTest.php @@ -12,10 +12,9 @@ namespace Symfony\Component\HttpKernel\Tests\Controller; use PHPUnit\Framework\TestCase; -use Symfony\Component\ErrorRenderer\ErrorRenderer; -use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer; -use Symfony\Component\ErrorRenderer\ErrorRenderer\JsonErrorRenderer; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; +use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRenderer; +use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Controller\ErrorController; @@ -31,7 +30,7 @@ class ErrorControllerTest extends TestCase public function testInvokeController(Request $request, FlattenException $exception, int $statusCode, string $content) { $kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock(); - $errorRenderer = new ErrorRenderer([new HtmlErrorRenderer(), new JsonErrorRenderer()]); + $errorRenderer = new ErrorRenderer(new HtmlErrorRenderer()); $controller = new ErrorController($kernel, null, $errorRenderer); $response = $controller($request, $exception); @@ -55,33 +54,6 @@ class ErrorControllerTest extends TestCase 'The server returned a "404 Not Found".', ]; - $request = new Request(); - $request->attributes->set('_format', 'json'); - yield 'custom format via _format attribute' => [ - $request, - FlattenException::createFromThrowable(new \Exception('foo')), - 500, - '{"title": "Internal Server Error","status": 500,"detail": "Whoops, looks like something went wrong."}', - ]; - - $request = new Request(); - $request->headers->set('Accept', 'application/json'); - yield 'custom format via Accept header' => [ - $request, - FlattenException::createFromThrowable(new HttpException(405, 'Invalid request.')), - 405, - '{"title": "Method Not Allowed","status": 405,"detail": "Whoops, looks like something went wrong."}', - ]; - - $request = new Request(); - $request->headers->set('Content-Type', 'application/json'); - yield 'custom format via Content-Type header' => [ - $request, - FlattenException::createFromThrowable(new HttpException(405, 'Invalid request.')), - 405, - '{"title": "Method Not Allowed","status": 405,"detail": "Whoops, looks like something went wrong."}', - ]; - $request = new Request(); $request->attributes->set('_format', 'unknown'); yield 'default HTML format for unknown formats' => [ @@ -116,7 +88,7 @@ class ErrorControllerTest extends TestCase ) ->willReturn($response = new Response()); - $controller = new ErrorController($kernel, $_controller, new ErrorRenderer([])); + $controller = new ErrorController($kernel, $_controller, new ErrorRenderer()); $this->assertSame($response, $controller->preview(new Request(), $code)); } diff --git a/src/Symfony/Component/HttpKernel/Tests/DataCollector/ExceptionDataCollectorTest.php b/src/Symfony/Component/HttpKernel/Tests/DataCollector/ExceptionDataCollectorTest.php index 8b1d1317d8..d1fc578b13 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DataCollector/ExceptionDataCollectorTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DataCollector/ExceptionDataCollectorTest.php @@ -12,7 +12,7 @@ namespace Symfony\Component\HttpKernel\Tests\DataCollector; use PHPUnit\Framework\TestCase; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\DataCollector\ExceptionDataCollector; diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index 51f0d919a7..ba6ab33de8 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -18,7 +18,6 @@ "require": { "php": "^7.1.3", "symfony/error-handler": "^4.4|^5.0", - "symfony/error-renderer": "^4.4|^5.0", "symfony/event-dispatcher": "^4.4", "symfony/http-foundation": "^4.4|^5.0", "symfony/polyfill-ctype": "^1.8", @@ -40,7 +39,6 @@ "symfony/templating": "^3.4|^4.0|^5.0", "symfony/translation": "^4.2|^5.0", "symfony/translation-contracts": "^1.1|^2", - "symfony/var-dumper": "^4.1.1|^5.0", "psr/cache": "~1.0", "twig/twig": "^1.34|^2.4|^3.0" }, @@ -53,15 +51,13 @@ "symfony/console": ">=5", "symfony/dependency-injection": "<4.3", "symfony/translation": "<4.2", - "symfony/var-dumper": "<4.1.1", "twig/twig": "<1.34|<2.4,>=2" }, "suggest": { "symfony/browser-kit": "", "symfony/config": "", "symfony/console": "", - "symfony/dependency-injection": "", - "symfony/var-dumper": "" + "symfony/dependency-injection": "" }, "autoload": { "psr-4": { "Symfony\\Component\\HttpKernel\\": "" }, diff --git a/src/Symfony/Component/Messenger/EventListener/SendFailedMessageToFailureTransportListener.php b/src/Symfony/Component/Messenger/EventListener/SendFailedMessageToFailureTransportListener.php index 0aa8fd5ea7..8c84cf7992 100644 --- a/src/Symfony/Component/Messenger/EventListener/SendFailedMessageToFailureTransportListener.php +++ b/src/Symfony/Component/Messenger/EventListener/SendFailedMessageToFailureTransportListener.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Messenger\EventListener; use Psr\Log\LoggerInterface; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent; use Symfony\Component\Messenger\Exception\HandlerFailedException; diff --git a/src/Symfony/Component/Messenger/Stamp/RedeliveryStamp.php b/src/Symfony/Component/Messenger/Stamp/RedeliveryStamp.php index 49bbf2f778..60c3898b08 100644 --- a/src/Symfony/Component/Messenger/Stamp/RedeliveryStamp.php +++ b/src/Symfony/Component/Messenger/Stamp/RedeliveryStamp.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Messenger\Stamp; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\Messenger\Envelope; /** diff --git a/src/Symfony/Component/Messenger/Tests/Stamp/RedeliveryStampTest.php b/src/Symfony/Component/Messenger/Tests/Stamp/RedeliveryStampTest.php index c55a670bf3..7fcabfc2d6 100644 --- a/src/Symfony/Component/Messenger/Tests/Stamp/RedeliveryStampTest.php +++ b/src/Symfony/Component/Messenger/Tests/Stamp/RedeliveryStampTest.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Messenger\Tests\Stamp; use PHPUnit\Framework\TestCase; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\Messenger\Stamp\RedeliveryStamp; class RedeliveryStampTest extends TestCase diff --git a/src/Symfony/Component/Messenger/composer.json b/src/Symfony/Component/Messenger/composer.json index 48f85f2b63..62b5240b82 100644 --- a/src/Symfony/Component/Messenger/composer.json +++ b/src/Symfony/Component/Messenger/composer.json @@ -25,7 +25,6 @@ "doctrine/persistence": "~1.0", "symfony/console": "^3.4|^4.0|^5.0", "symfony/dependency-injection": "^3.4.19|^4.1.8|^5.0", - "symfony/error-renderer": "^4.4|^5.0", "symfony/event-dispatcher": "^4.3|^5.0", "symfony/http-kernel": "^4.4", "symfony/process": "^3.4|^4.0|^5.0", diff --git a/src/Symfony/Component/Serializer/CHANGELOG.md b/src/Symfony/Component/Serializer/CHANGELOG.md index 0958f50540..7f213186e3 100644 --- a/src/Symfony/Component/Serializer/CHANGELOG.md +++ b/src/Symfony/Component/Serializer/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * deprecated the `XmlEncoder::TYPE_CASE_ATTRIBUTES` constant, use `XmlEncoder::TYPE_CAST_ATTRIBUTES` instead * added option to output a UTF-8 BOM in CSV encoder via `CsvEncoder::OUTPUT_UTF8_BOM_KEY` context option + * added `ProblemNormalizer` to normalize errors according to the API Problem spec (RFC 7807) 4.3.0 ----- diff --git a/src/Symfony/Component/Serializer/Normalizer/ProblemNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ProblemNormalizer.php new file mode 100644 index 0000000000..0569c2923b --- /dev/null +++ b/src/Symfony/Component/Serializer/Normalizer/ProblemNormalizer.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Normalizer; + +use Symfony\Component\ErrorHandler\Exception\FlattenException; + +/** + * Normalizes errors according to the API Problem spec (RFC 7807). + * + * @see https://tools.ietf.org/html/rfc7807 + * + * @author Kévin Dunglas + * @author Yonel Ceruto + */ +class ProblemNormalizer implements NormalizerInterface, CacheableSupportsMethodInterface +{ + private $debug; + private $defaultContext = [ + 'type' => 'https://tools.ietf.org/html/rfc2616#section-10', + 'title' => 'An error occurred', + ]; + + public function __construct(bool $debug = false, array $defaultContext = []) + { + $this->debug = $debug; + $this->defaultContext = $defaultContext + $this->defaultContext; + } + + /** + * {@inheritdoc} + */ + public function normalize($exception, $format = null, array $context = []) + { + $context += $this->defaultContext; + + $data = [ + 'type' => $context['type'], + 'title' => $context['title'], + 'status' => $context['status'] ?? $exception->getStatusCode(), + 'detail' => $this->debug ? $exception->getMessage() : $exception->getStatusText(), + ]; + if ($this->debug) { + $data['class'] = $exception->getClass(); + $data['trace'] = $exception->getTrace(); + } + + return $data; + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null): bool + { + return $data instanceof FlattenException; + } + + /** + * {@inheritdoc} + */ + public function hasCacheableSupportsMethod(): bool + { + return true; + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ProblemNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ProblemNormalizerTest.php new file mode 100644 index 0000000000..4a754ac5b7 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ProblemNormalizerTest.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Normalizer; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\ErrorHandler\Exception\FlattenException; +use Symfony\Component\Serializer\Normalizer\ProblemNormalizer; + +class ProblemNormalizerTest extends TestCase +{ + /** + * @var ProblemNormalizer + */ + private $normalizer; + + protected function setUp(): void + { + $this->normalizer = new ProblemNormalizer(false); + } + + public function testSupportNormalization() + { + $this->assertTrue($this->normalizer->supportsNormalization(FlattenException::createFromThrowable(new \Exception()))); + $this->assertFalse($this->normalizer->supportsNormalization(new \Exception())); + $this->assertFalse($this->normalizer->supportsNormalization(new \stdClass())); + } + + public function testNormalize() + { + $expected = [ + 'type' => 'https://tools.ietf.org/html/rfc2616#section-10', + 'title' => 'An error occurred', + 'status' => 500, + 'detail' => 'Internal Server Error', + ]; + + $this->assertSame($expected, $this->normalizer->normalize(FlattenException::createFromThrowable(new \RuntimeException('Error')))); + } +} diff --git a/src/Symfony/Component/Serializer/composer.json b/src/Symfony/Component/Serializer/composer.json index 45c185a364..dfee783304 100644 --- a/src/Symfony/Component/Serializer/composer.json +++ b/src/Symfony/Component/Serializer/composer.json @@ -20,17 +20,18 @@ "symfony/polyfill-ctype": "~1.8" }, "require-dev": { - "symfony/yaml": "^3.4|^4.0|^5.0", - "symfony/config": "^3.4|^4.0|^5.0", - "symfony/property-access": "^3.4|^4.0|^5.0", - "symfony/http-foundation": "^3.4|^4.0|^5.0", + "doctrine/annotations": "~1.0", + "doctrine/cache": "~1.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0", "symfony/cache": "^3.4|^4.0|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/error-handler": "^4.4|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/property-access": "^3.4|^4.0|^5.0", "symfony/property-info": "^3.4.13|~4.0|^5.0", "symfony/validator": "^3.4|^4.0|^5.0", - "doctrine/annotations": "~1.0", - "symfony/dependency-injection": "^3.4|^4.0|^5.0", - "doctrine/cache": "~1.0", - "phpdocumentor/reflection-docblock": "^3.0|^4.0" + "symfony/yaml": "^3.4|^4.0|^5.0" }, "conflict": { "phpdocumentor/type-resolver": "<0.2.1",