From eecff075fe3deeebfb8280c9b01332adec3817bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 22 Sep 2021 19:36:17 +0200 Subject: [PATCH] [FrameworkBundle][HttpKernel] Add the ability to enable the profiler using a parameter --- .../Bundle/FrameworkBundle/CHANGELOG.md | 1 + .../DependencyInjection/Configuration.php | 1 + .../FrameworkExtension.php | 3 ++ .../Resources/config/schema/symfony-1.0.xsd | 1 + .../DependencyInjection/ConfigurationTest.php | 1 + .../Tests/Functional/ProfilerTest.php | 21 ++++++++++ .../app/ProfilerCollectParameter/bundles.php | 18 +++++++++ .../app/ProfilerCollectParameter/config.yml | 8 ++++ .../app/ProfilerCollectParameter/routing.yml | 2 + src/Symfony/Component/HttpKernel/CHANGELOG.md | 1 + .../EventListener/ProfilerListener.php | 8 +++- .../EventListener/ProfilerListenerTest.php | 38 +++++++++++++++++++ 12 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ProfilerCollectParameter/bundles.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ProfilerCollectParameter/config.yml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ProfilerCollectParameter/routing.yml diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index ffb02fe0d6700..fd0bdb9941a4e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -9,6 +9,7 @@ CHANGELOG * Add `set_content_language_from_locale` config option to automatically set the `Content-Language` HTTP response header based on the Request locale * Deprecate the `framework.translator.enabled_locales`, use `framework.enabled_locales` instead * Add autowiring alias for `HttpCache\StoreInterface` + * Add the ability to enable the profiler using a request query parameter, body parameter or attribute * Deprecate the `AdapterInterface` autowiring alias, use `CacheItemPoolInterface` instead * Deprecate the public `profiler` service to private * Deprecate `get()`, `has()`, `getDoctrine()`, and `dispatchMessage()` in `AbstractController`, use method/constructor injection instead diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index c902cf9da0e18..eb082169dc72c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -315,6 +315,7 @@ private function addProfilerSection(ArrayNodeDefinition $rootNode) ->canBeEnabled() ->children() ->booleanNode('collect')->defaultTrue()->end() + ->scalarNode('collect_parameter')->defaultNull()->info('The name of the parameter to use to enable or disable collection on a per request basis')->end() ->booleanNode('only_exceptions')->defaultFalse()->end() ->booleanNode('only_main_requests')->defaultFalse()->end() ->booleanNode('only_master_requests')->setDeprecated('symfony/framework-bundle', '5.3', 'Option "%node%" at "%path%" is deprecated, use "only_main_requests" instead.')->defaultFalse()->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index dc4dfc940f138..8009da4b671ff 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -770,6 +770,9 @@ private function registerProfilerConfiguration(array $config, ContainerBuilder $ $container->getDefinition('profiler') ->addArgument($config['collect']) ->addTag('kernel.reset', ['method' => 'reset']); + + $container->getDefinition('profiler_listener') + ->addArgument($config['collect_parameter']); } private function registerWorkflowConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 63b598ed18c3e..7bfe003fece40 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -91,6 +91,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index 4cb5149edeed6..9418e5b4795be 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -405,6 +405,7 @@ protected static function getBundleDefaultConfig() 'only_main_requests' => false, 'dsn' => 'file:%kernel.cache_dir%/profiler', 'collect' => true, + 'collect_parameter' => null, ], 'translator' => [ 'enabled' => !class_exists(FullStack::class), diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ProfilerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ProfilerTest.php index 35c2e63b7e04a..7b65ca5c276e8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ProfilerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ProfilerTest.php @@ -36,6 +36,27 @@ public function testProfilerIsDisabled($insulate) $this->assertNull($client->getProfile()); } + /** + * @dataProvider getConfigs + */ + public function testProfilerCollectParameter($insulate) + { + $client = $this->createClient(['test_case' => 'ProfilerCollectParameter', 'root_config' => 'config.yml']); + if ($insulate) { + $client->insulate(); + } + + $client->request('GET', '/profiler'); + $this->assertNull($client->getProfile()); + + // enable the profiler for the next request + $client->request('GET', '/profiler?profile=1'); + $this->assertIsObject($client->getProfile()); + + $client->request('GET', '/profiler'); + $this->assertNull($client->getProfile()); + } + public function getConfigs() { return [ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ProfilerCollectParameter/bundles.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ProfilerCollectParameter/bundles.php new file mode 100644 index 0000000000000..15ff182c6fed5 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ProfilerCollectParameter/bundles.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Bundle\FrameworkBundle\FrameworkBundle; +use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestBundle; + +return [ + new FrameworkBundle(), + new TestBundle(), +]; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ProfilerCollectParameter/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ProfilerCollectParameter/config.yml new file mode 100644 index 0000000000000..67360dd321681 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ProfilerCollectParameter/config.yml @@ -0,0 +1,8 @@ +imports: + - { resource: ../config/default.yml } + +framework: + profiler: + enabled: true + collect: false + collect_parameter: profile diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ProfilerCollectParameter/routing.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ProfilerCollectParameter/routing.yml new file mode 100644 index 0000000000000..d4b77c3f703d9 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ProfilerCollectParameter/routing.yml @@ -0,0 +1,2 @@ +_sessiontest_bundle: + resource: '@TestBundle/Resources/config/routing.yml' diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index 7df4eb26f304c..3acea2838d515 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 5.4 --- + * Add the ability to enable the profiler using a request query parameter, body parameter or attribute * Deprecate `AbstractTestSessionListener::getSession` inject a session in the request instead * Deprecate the `fileLinkFormat` parameter of `DebugHandlersListener` * Add support for configuring log level, and status code by exception class diff --git a/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php b/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php index a0e55563afb21..c2733b2856356 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php @@ -36,13 +36,14 @@ class ProfilerListener implements EventSubscriberInterface protected $exception; protected $profiles; protected $requestStack; + protected $collectParameter; protected $parents; /** * @param bool $onlyException True if the profiler only collects data when an exception occurs, false otherwise * @param bool $onlyMainRequests True if the profiler only collects data when the request is the main request, false otherwise */ - public function __construct(Profiler $profiler, RequestStack $requestStack, RequestMatcherInterface $matcher = null, bool $onlyException = false, bool $onlyMainRequests = false) + public function __construct(Profiler $profiler, RequestStack $requestStack, RequestMatcherInterface $matcher = null, bool $onlyException = false, bool $onlyMainRequests = false, string $collectParameter = null) { $this->profiler = $profiler; $this->matcher = $matcher; @@ -51,6 +52,7 @@ public function __construct(Profiler $profiler, RequestStack $requestStack, Requ $this->profiles = new \SplObjectStorage(); $this->parents = new \SplObjectStorage(); $this->requestStack = $requestStack; + $this->collectParameter = $collectParameter; } /** @@ -79,6 +81,10 @@ public function onKernelResponse(ResponseEvent $event) } $request = $event->getRequest(); + if (null !== $this->collectParameter && null !== $collectParameterValue = $request->get($this->collectParameter)) { + true === $collectParameterValue || filter_var($collectParameterValue, \FILTER_VALIDATE_BOOLEAN) ? $this->profiler->enable() : $this->profiler->disable(); + } + $exception = $this->exception; $this->exception = null; diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/ProfilerListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/ProfilerListenerTest.php index 10733d47e3b62..45272ceb026cd 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/ProfilerListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/ProfilerListenerTest.php @@ -59,4 +59,42 @@ public function testKernelTerminate() $listener->onKernelTerminate(new TerminateEvent($kernel, $mainRequest, $response)); } + + /** + * @dataProvider collectRequestProvider + */ + public function testCollectParameter(Request $request, ?bool $enable) + { + $profile = new Profile('token'); + + $profiler = $this->createMock(Profiler::class); + $profiler->expects($this->once()) + ->method('collect') + ->willReturn($profile); + + $profiler + ->expects(null === $enable ? $this->never() : $this->once()) + ->method($enable ? 'enable' : 'disable'); + + $kernel = $this->createMock(HttpKernelInterface::class); + $response = new Response(); + + $requestStack = new RequestStack(); + $requestStack->push($request); + + $listener = new ProfilerListener($profiler, $requestStack, null, false, false, 'profile'); + + $listener->onKernelResponse(new ResponseEvent($kernel, $request, Kernel::MAIN_REQUEST, $response)); + } + + public function collectRequestProvider(): iterable + { + yield [Request::create('/'), null]; + yield [Request::create('/', 'GET', ['profile' => '1']), true]; + yield [Request::create('/', 'GET', ['profile' => '0']), false]; + + $request = Request::create('/'); + $request->attributes->set('profile', true); + yield [$request, true]; + } }