From e169e1a4d556fc95e6637ab393a235168d6aa0be Mon Sep 17 00:00:00 2001 From: Amrouche Hamza Date: Tue, 23 Apr 2019 08:04:30 +0200 Subject: [PATCH] [FrameworkBundle] WebTestCase KernelBrowser::getContainer null return type --- UPGRADE-4.4.md | 55 ++++++++++--------- UPGRADE-5.0.md | 1 + .../FrameworkBundle/Test/KernelTestCase.php | 14 +++-- .../Tests/Functional/app/AppKernel.php | 10 ++++ .../Tests/Functional/app/AppKernel.php | 10 ++++ src/Symfony/Component/HttpKernel/CHANGELOG.md | 1 + src/Symfony/Component/HttpKernel/Kernel.php | 4 ++ .../Component/HttpKernel/KernelInterface.php | 2 +- .../Component/HttpKernel/Tests/KernelTest.php | 24 +++++++- 9 files changed, 87 insertions(+), 34 deletions(-) diff --git a/UPGRADE-4.4.md b/UPGRADE-4.4.md index ac716a4b0739..584eb693e2ab 100644 --- a/UPGRADE-4.4.md +++ b/UPGRADE-4.4.md @@ -60,7 +60,7 @@ DependencyInjection ```php new Definition('%my_class%'); ``` - + DoctrineBridge -------------- * Deprecated injecting `ClassMetadataFactory` in `DoctrineExtractor`, an instance of `EntityManagerInterface` should be @@ -96,7 +96,7 @@ FrameworkBundle * Deprecated `routing.loader.service`, use `routing.loader.container` instead. * Not tagging service route loaders with `routing.route_loader` has been deprecated. * Overriding the methods `KernelTestCase::tearDown()` and `WebTestCase::tearDown()` without the `void` return-type is deprecated. - + HttpClient ---------- @@ -139,7 +139,7 @@ HttpKernel } ``` - As many bundles must be compatible with a range of Symfony versions, the current + As many bundles must be compatible with a range of Symfony versions, the current directory convention is not deprecated yet, but it will be in the future. * Deprecated the second and third argument of `KernelInterface::locateResource` @@ -148,6 +148,7 @@ HttpKernel fallback directories. Resources like service definitions are usually loaded relative to the current directory or with a glob pattern. The fallback directories have never been advocated so you likely do not use those in any app based on the SF Standard or Flex edition. + * Getting the container from a non-booted kernel is deprecated Lock ---- @@ -171,7 +172,7 @@ MonologBridge -------------- * The `RouteProcessor` has been marked final. - + Process ------- @@ -195,14 +196,14 @@ Security * Implementations of `PasswordEncoderInterface` and `UserPasswordEncoderInterface` should add a new `needsRehash()` method * Deprecated returning a non-boolean value when implementing `Guard\AuthenticatorInterface::checkCredentials()`. Please explicitly return `false` to indicate invalid credentials. * Deprecated passing more than one attribute to `AccessDecisionManager::decide()` and `AuthorizationChecker::isGranted()` (and indirectly the `is_granted()` Twig and ExpressionLanguage function) - + **Before** ```php if ($this->authorizationChecker->isGranted(['ROLE_USER', 'ROLE_ADMIN'])) { // ... } ``` - + **After** ```php if ($this->authorizationChecker->isGranted(new Expression("has_role('ROLE_USER') or has_role('ROLE_ADMIN')"))) {} @@ -230,18 +231,18 @@ TwigBridge * Deprecated to pass `$rootDir` and `$fileLinkFormatter` as 5th and 6th argument respectively to the `DebugCommand::__construct()` method, swap the variables position. * Deprecated accepting STDIN implicitly when using the `lint:twig` command, use `lint:twig -` (append a dash) instead to make it explicit. - + TwigBundle ---------- * Deprecated `twig.exception_controller` configuration option, set it to "null" and use `framework.error_controller` instead: - + Before: ```yaml twig: exception_controller: 'App\Controller\MyExceptionController' ``` - + After: ```yaml twig: @@ -250,36 +251,36 @@ TwigBundle framework: error_controller: 'App\Controller\MyExceptionController' ``` - - The new default exception controller will also change the error response content according to + + The new default exception controller will also change the error response content according to https://tools.ietf.org/html/rfc7807 for `json`, `xml`, `atom` and `txt` formats: - + Before: ```json - { - "error": { - "code": 404, - "message": "Sorry, the page you are looking for could not be found" - } + { + "error": { + "code": 404, + "message": "Sorry, the page you are looking for could not be found" + } } ``` - + After: ```json - { + { "title": "Not Found", - "status": 404, + "status": 404, "detail": "Sorry, the page you are looking for could not be found" } ``` - + * Deprecated the `ExceptionController` and `PreviewErrorController` controllers, use `ErrorController` from the HttpKernel component instead * 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: + * 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`): ```twig - { + { "@id": "https://example.com", "@type": "error", "@context": { @@ -289,7 +290,7 @@ TwigBundle } } ``` - + After (`App\ErrorRenderer\JsonLdErrorRenderer`): ```php class JsonLdErrorRenderer implements ErrorRendererInterface @@ -298,7 +299,7 @@ TwigBundle { return 'jsonld'; } - + public function render(FlattenException $exception): string { return json_encode([ @@ -323,7 +324,7 @@ Validator * Deprecated using anything else than a `string` as the code of a `ConstraintViolation`, a `string` type-hint will be added to the constructor of the `ConstraintViolation` class and to the `ConstraintViolationBuilder::setCode()` method in 5.0. - * Deprecated passing an `ExpressionLanguage` instance as the second argument of `ExpressionValidator::__construct()`. + * Deprecated passing an `ExpressionLanguage` instance as the second argument of `ExpressionValidator::__construct()`. Pass it as the first argument instead. * The `Length` constraint expects the `allowEmptyString` option to be defined when the `min` option is used. @@ -343,7 +344,7 @@ WebServerBundle --------------- * The bundle is deprecated and will be removed in 5.0. - + Yaml ---- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 12a34a85d35d..1039e3a5fe03 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -288,6 +288,7 @@ HttpFoundation use `Symfony\Component\Mime\FileinfoMimeTypeGuesser` instead. * `ApacheRequest` has been removed, use the `Request` class instead. * The third argument of the `HeaderBag::get()` method has been removed, use method `all()` instead. + * Getting the container from a non-booted kernel is not possible anymore. HttpKernel ---------- diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php index 02806ad6a98c..8d0bc21ef556 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php @@ -127,11 +127,15 @@ protected static function createKernel(array $options = []) protected static function ensureKernelShutdown() { if (null !== static::$kernel) { - $container = static::$kernel->getContainer(); - static::$kernel->shutdown(); - static::$booted = false; - if ($container instanceof ResetInterface) { - $container->reset(); + $isBooted = (new \ReflectionClass(static::$kernel))->getProperty('booted'); + $isBooted->setAccessible(true); + if ($isBooted->getValue(static::$kernel)) { + $container = static::$kernel->getContainer(); + static::$kernel->shutdown(); + static::$booted = false; + if ($container instanceof ResetInterface) { + $container->reset(); + } } } static::$container = null; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php index 0d329582b39e..14cdef628598 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php @@ -14,6 +14,7 @@ use Psr\Log\NullLogger; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpKernel\Kernel; @@ -96,4 +97,13 @@ protected function getKernelParameters(): array return $parameters; } + + public function getContainer(): ContainerInterface + { + if (!$this->booted) { + throw new \LogicException('Cannot access the container on a non-booted kernel. Did you forget to boot it?'); + } + + return parent::getContainer(); + } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php index 8e622282c2c1..ca6f16c0d6ae 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\SecurityBundle\Tests\Functional\app; use Symfony\Component\Config\Loader\LoaderInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpKernel\Kernel; @@ -98,4 +99,13 @@ protected function getKernelParameters(): array return $parameters; } + + public function getContainer(): ContainerInterface + { + if (!$this->booted) { + throw new \LogicException('Cannot access the container on a non-booted kernel. Did you forget to boot it?'); + } + + return parent::getContainer(); + } } diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index 5eb335ac309f..6a11a170b310 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -14,6 +14,7 @@ CHANGELOG so you likely do not use those in any app based on the SF Standard or Flex edition. * Marked all dispatched event classes as `@final` * Added `ErrorController` to enable the preview and error rendering mechanism + * Getting the container from a non-booted kernel is deprecated. 4.3.0 ----- diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 0f4be74092a7..eeed399b0d5f 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -380,6 +380,10 @@ public function getProjectDir() */ public function getContainer() { + if (!$this->booted) { + @trigger_error('Getting the container from a non-booted kernel is deprecated since Symfony 4.4.', E_USER_DEPRECATED); + } + return $this->container; } diff --git a/src/Symfony/Component/HttpKernel/KernelInterface.php b/src/Symfony/Component/HttpKernel/KernelInterface.php index c97dde829271..00a1aec817e3 100644 --- a/src/Symfony/Component/HttpKernel/KernelInterface.php +++ b/src/Symfony/Component/HttpKernel/KernelInterface.php @@ -124,7 +124,7 @@ public function getRootDir(); /** * Gets the current container. * - * @return ContainerInterface|null A ContainerInterface instance or null when the Kernel is shutdown + * @return ContainerInterface */ public function getContainer(); diff --git a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php index 065a3ea14827..1f6811639b94 100644 --- a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php @@ -46,6 +46,17 @@ public function testConstructor() $this->assertEquals($debug, $kernel->isDebug()); $this->assertFalse($kernel->isBooted()); $this->assertLessThanOrEqual(microtime(true), $kernel->getStartTime()); + } + + /** + * @group legacy + * @expectedDeprecation Getting the container from a non-booted kernel is deprecated since Symfony 4.4. + */ + public function testGetContainerForANonBootedKernel() + { + $kernel = new KernelForTest('test_env', true); + + $this->assertFalse($kernel->isBooted()); $this->assertNull($kernel->getContainer()); } @@ -61,7 +72,6 @@ public function testClone() $this->assertEquals($debug, $clone->isDebug()); $this->assertFalse($clone->isBooted()); $this->assertLessThanOrEqual(microtime(true), $clone->getStartTime()); - $this->assertNull($clone->getContainer()); } public function testClassNameValidityGetter() @@ -486,6 +496,18 @@ public function testTerminateReturnsSilentlyIfKernelIsNotBooted() $kernel->terminate(Request::create('/'), new Response()); } + /** + * @group legacy + * @expectedDeprecation Getting the container from a non-booted kernel is deprecated since Symfony 4.4. + */ + public function testDeprecatedNullKernel() + { + $kernel = $this->getKernel(); + $kernel->shutdown(); + + $this->assertNull($kernel->getContainer()); + } + public function testTerminateDelegatesTerminationOnlyForTerminableInterface() { // does not implement TerminableInterface