Skip to content

Commit

Permalink
[ErrorHandler] merge and remove the ErrorRenderer component
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolas-grekas committed Nov 10, 2019
1 parent 10a349c commit d1e9c16
Show file tree
Hide file tree
Showing 99 changed files with 541 additions and 1,640 deletions.
39 changes: 14 additions & 25 deletions UPGRADE-4.4.md
Expand Up @@ -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

Expand Down Expand Up @@ -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
---------

Expand Down
1 change: 0 additions & 1 deletion UPGRADE-5.0.md
Expand Up @@ -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

Expand Down
1 change: 0 additions & 1 deletion composer.json
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Bridge/Twig/Mime/NotificationEmail.php
Expand Up @@ -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;
Expand Down
Expand Up @@ -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',
Expand Down
2 changes: 0 additions & 2 deletions src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
Expand Up @@ -33,7 +33,6 @@
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;
Expand Down Expand Up @@ -92,7 +91,6 @@ public function build(ContainerBuilder $container)
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);
Expand Down
Expand Up @@ -194,12 +194,6 @@
<tag name="console.command" command="debug:form" />
</service>

<service id="console.command.error_renderer_debug" class="Symfony\Component\ErrorRenderer\Command\DebugCommand">
<argument type="collection" /> <!-- All error renderers are injected here by ErrorRendererPass -->
<argument type="service" id="debug.file_link_formatter" on-invalid="null" />
<tag name="console.command" command="debug:error-renderer" />
</service>

<service id="console.command.secrets_set" class="Symfony\Bundle\FrameworkBundle\Command\SecretsSetCommand">
<argument type="service" id="secrets.vault" />
<argument type="service" id="secrets.local_vault" on-invalid="ignore" />
Expand Down
Expand Up @@ -5,12 +5,7 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd">

<services>
<service id="error_renderer" class="Symfony\Component\ErrorRenderer\DependencyInjection\LazyLoadingErrorRenderer">
<argument /> <!-- error renderer locator -->
</service>

<service id="error_renderer.renderer.html" class="Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer">
<tag name="error_renderer.renderer" />
<service id="error_handler.error_renderer.html" class="Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer">
<argument>%kernel.debug%</argument>
<argument>%kernel.charset%</argument>
<argument type="service" id="debug.file_link_formatter" on-invalid="null" />
Expand All @@ -19,21 +14,15 @@
<argument type="service" id="logger" on-invalid="null" />
</service>

<service id="error_renderer.renderer.json" class="Symfony\Component\ErrorRenderer\ErrorRenderer\JsonErrorRenderer">
<tag name="error_renderer.renderer" />
<argument>%kernel.debug%</argument>
</service>

<service id="error_renderer.renderer.xml" class="Symfony\Component\ErrorRenderer\ErrorRenderer\XmlErrorRenderer">
<tag name="error_renderer.renderer" format="atom" />
<tag name="error_renderer.renderer" />
<service id="error_handler.error_renderer.serializer" class="Symfony\Component\ErrorHandler\ErrorRenderer\SerializerErrorRenderer">
<argument type="service" id="serializer" />
<argument type="service" id="request_stack" />
<argument type="service" id="error_renderer.html" />
<argument>%kernel.debug%</argument>
<argument>%kernel.charset%</argument>
</service>

<service id="error_renderer.renderer.txt" class="Symfony\Component\ErrorRenderer\ErrorRenderer\TxtErrorRenderer">
<tag name="error_renderer.renderer" />
<argument>%kernel.debug%</argument>
</service>
<service id="error_renderer.html" alias="error_handler.error_renderer.html" />
<service id="error_renderer.serializer" alias="error_handler.error_renderer.serializer" />
<service id="error_renderer" alias="error_renderer.html" />
</services>
</container>
Expand Up @@ -12,6 +12,8 @@
<services>
<defaults public="false" />

<service id="error_renderer" alias="error_renderer.serializer" />

<service id="serializer" class="Symfony\Component\Serializer\Serializer" public="true">
<argument type="collection" />
<argument type="collection" />
Expand Down Expand Up @@ -59,6 +61,12 @@
<tag name="serializer.normalizer" priority="-900" />
</service>

<service id="serializer.normalizer.problem" class="Symfony\Component\Serializer\Normalizer\ProblemNormalizer">
<argument>%kernel.debug%</argument>
<!-- Run before serializer.normalizer.object -->
<tag name="serializer.normalizer" priority="-890" />
</service>

<service id="serializer.normalizer.object" class="Symfony\Component\Serializer\Normalizer\ObjectNormalizer">
<argument type="service" id="serializer.mapping.class_metadata_factory" />
<argument type="service" id="serializer.name_converter.metadata_aware" />
Expand Down
3 changes: 1 addition & 2 deletions src/Symfony/Bundle/FrameworkBundle/composer.json
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
Expand Up @@ -70,6 +70,6 @@ public function testDefaultJsonLoginBadRequest()

$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));
}
}
@@ -1,6 +1,9 @@
imports:
- { resource: ./../config/framework.yml }

framework:
serializer: ~

security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Bundle/SecurityBundle/composer.json
Expand Up @@ -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",
Expand Down
4 changes: 2 additions & 2 deletions src/Symfony/Bundle/TwigBundle/CHANGELOG.md
Expand Up @@ -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

Expand Down
Expand Up @@ -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;
Expand All @@ -40,34 +40,20 @@ public function __construct(Environment $twig, HtmlErrorRenderer $htmlErrorRende
/**
* {@inheritdoc}
*/
public static function getFormat(): string
public function render(\Throwable $exception): FlattenException
{
return 'html';
}

/**
* {@inheritdoc}
*/
public function render(FlattenException $exception): string
{
$debug = $this->debug && ($exception->getHeaders()['X-Debug'] ?? true);

if ($debug) {
return $this->htmlErrorRenderer->render($exception);
}

$template = $this->findTemplate($exception->getStatusCode());
$exception = $this->htmlErrorRenderer->render($exception);

if (null === $template) {
return $this->htmlErrorRenderer->render($exception);
if ($this->debug || !$template = $this->findTemplate($exception->getStatusCode());
return $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
Expand Down
5 changes: 2 additions & 3 deletions src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml
Expand Up @@ -162,10 +162,9 @@
<argument /> <!-- runtime locator -->
</service>

<service id="twig.error_renderer.html" class="Symfony\Bundle\TwigBundle\ErrorRenderer\TwigHtmlErrorRenderer">
<tag name="error_renderer.renderer" priority="1" />
<service id="twig.error_renderer.html" class="Symfony\Bundle\TwigBundle\ErrorRenderer\TwigHtmlErrorRenderer" decorates="error_renderer.html">
<argument type="service" id="twig" />
<argument type="service" id="error_renderer.renderer.html" />
<argument type="service" id="twig.error_renderer.html.inner" />
<argument>%kernel.debug%</argument>
</service>
</services>
Expand Down
Expand Up @@ -13,8 +13,7 @@

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;
Expand All @@ -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);
Expand All @@ -33,12 +32,12 @@ public function testFallbackToNativeRendererIfDebugOn()
->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([]));

Expand All @@ -54,7 +53,7 @@ public function testFallbackToNativeRendererIfCustomTemplateNotFound()

public function testRenderCustomErrorTemplate()
{
$exception = FlattenException::createFromThrowable(new NotFoundHttpException());
$exception = new NotFoundHttpException();

$twig = new Environment(new ArrayLoader([
'@Twig/Exception/error404.html.twig' => '<h1>Page Not Found</h1>',
Expand All @@ -68,6 +67,6 @@ public function testRenderCustomErrorTemplate()

$content = (new TwigHtmlErrorRenderer($twig, $nativeRenderer, false))->render($exception);

$this->assertSame('<h1>Page Not Found</h1>', $content);
$this->assertSame('<h1>Page Not Found</h1>', $content->getAsString());
}
}
Expand Up @@ -15,7 +15,7 @@
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;

Expand Down Expand Up @@ -65,7 +65,8 @@ public function registerContainerConfiguration(LoaderInterface $loader)
'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);
});
}
Expand Down
1 change: 0 additions & 1 deletion src/Symfony/Bundle/TwigBundle/composer.json
Expand Up @@ -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",
Expand Down

0 comments on commit d1e9c16

Please sign in to comment.