From 8c39bf7845c1517284cacd979db16a0abaf20c83 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Thu, 5 Oct 2017 11:48:08 +0200 Subject: [PATCH] Reset profiler. --- UPGRADE-3.4.md | 14 +++++++-- UPGRADE-4.0.md | 10 +++++-- composer.json | 2 +- .../DataCollector/DoctrineDataCollector.php | 14 +++++++++ .../DoctrineDataCollectorTest.php | 14 +++++++++ src/Symfony/Bridge/Monolog/Logger.php | 10 +++++++ .../Monolog/Processor/DebugProcessor.php | 9 ++++++ .../Bridge/Monolog/Tests/LoggerTest.php | 13 ++++++++ .../Twig/DataCollector/TwigDataCollector.php | 10 +++++++ src/Symfony/Bridge/Twig/composer.json | 2 +- .../FrameworkExtension.php | 6 ++-- .../DataCollector/SecurityDataCollector.php | 8 +++++ .../DataCollector/CacheDataCollector.php | 9 ++++++ .../Component/EventDispatcher/CHANGELOG.md | 5 ++++ .../Debug/TraceableEventDispatcher.php | 5 ++++ .../TraceableEventDispatcherInterface.php | 2 ++ .../Debug/TraceableEventDispatcherTest.php | 15 ++++++++++ .../DataCollector/FormDataCollector.php | 16 ++++++---- .../DataCollector/FormDataCollectorTest.php | 30 +++++++++++++++++++ src/Symfony/Component/HttpKernel/CHANGELOG.md | 4 ++- .../DataCollector/AjaxDataCollector.php | 5 ++++ .../DataCollector/ConfigDataCollector.php | 8 +++++ .../DataCollector/DataCollectorInterface.php | 2 ++ .../DataCollector/EventDataCollector.php | 16 ++++++++++ .../DataCollector/ExceptionDataCollector.php | 8 +++++ .../DataCollector/LoggerDataCollector.php | 15 ++++++++++ .../DataCollector/MemoryDataCollector.php | 16 +++++++--- .../DataCollector/RequestDataCollector.php | 6 ++++ .../DataCollector/RouterDataCollector.php | 22 +++++++++----- .../DataCollector/TimeDataCollector.php | 8 +++++ .../HttpKernel/Log/DebugLoggerInterface.php | 2 ++ .../HttpKernel/Profiler/Profiler.php | 25 +++++++++++++++- .../ExceptionDataCollectorTest.php | 19 ++++++++++++ .../DataCollector/LoggerDataCollectorTest.php | 22 ++++++++++++-- .../DataCollector/CloneVarDataCollector.php | 5 ++++ .../Tests/Fixtures/TestEventDispatcher.php | 4 +++ .../Tests/Profiler/ProfilerTest.php | 14 +++++++++ .../TranslationDataCollector.php | 8 +++++ .../DataCollector/ValidatorDataCollector.php | 25 ++++++++++++---- .../ValidatorDataCollectorTest.php | 27 +++++++++++++++++ .../Validator/TraceableValidator.php | 8 +++-- 41 files changed, 426 insertions(+), 37 deletions(-) diff --git a/UPGRADE-3.4.md b/UPGRADE-3.4.md index e5b6434c37f4e..c0573eb219ab8 100644 --- a/UPGRADE-3.4.md +++ b/UPGRADE-3.4.md @@ -63,6 +63,12 @@ Debug * Support for stacked errors in the `ErrorHandler` is deprecated and will be removed in Symfony 4.0. +EventDispatcher +--------------- + + * Implementing `TraceableEventDispatcherInterface` without the `reset()` method + is deprecated and will be unsupported in 4.0. + Filesystem ---------- @@ -270,6 +276,10 @@ HttpKernel * The `Symfony\Component\HttpKernel\Config\EnvParametersResource` class has been deprecated and will be removed in 4.0. + * Implementing `DataCollectorInterface` without a `reset()` method has been deprecated and will be unsupported in 4.0. + + * Implementing `DebugLoggerInterface` without a `clear()` method has been deprecated and will be unsupported in 4.0. + * The `ChainCacheClearer::add()` method has been deprecated and will be removed in 4.0, inject the list of clearers as a constructor argument instead. @@ -320,11 +330,11 @@ SecurityBundle * Deprecated the HTTP digest authentication: `HttpDigestFactory` will be removed in 4.0. Use another authentication system like `http_basic` instead. - + * Deprecated setting the `switch_user.stateless` option to false when the firewall is `stateless`. Setting it to false will have no effect in 4.0. - * Not configuring explicitly the provider on a firewall is ambiguous when there is more than one registered provider. + * Not configuring explicitly the provider on a firewall is ambiguous when there is more than one registered provider. Using the first configured provider is deprecated since 3.4 and will throw an exception on 4.0. Explicitly configure the provider to use on your firewalls. diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md index 2d2e04899c18b..5bc486f44f466 100644 --- a/UPGRADE-4.0.md +++ b/UPGRADE-4.0.md @@ -192,6 +192,8 @@ EventDispatcher * The `ContainerAwareEventDispatcher` class has been removed. Use `EventDispatcher` with closure factories instead. + * The `reset()` method has been added to `TraceableEventDispatcherInterface`. + ExpressionLanguage ------------------ @@ -611,6 +613,10 @@ HttpKernel * The `Symfony\Component\HttpKernel\Config\EnvParametersResource` class has been removed. + * The `reset()` method has been added to `Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface`. + + * The `clear()` method has been added to `Symfony\Component\HttpKernel\Log\DebugLoggerInterface`. + * The `ChainCacheClearer::add()` method has been removed, inject the list of clearers as a constructor argument instead. @@ -693,10 +699,10 @@ SecurityBundle * Removed the HTTP digest authentication system. The `HttpDigestFactory` class has been removed. Use another authentication system like `http_basic` instead. - + * The `switch_user.stateless` option is now always true if the firewall is stateless. - * Not configuring explicitly the provider on a firewall is ambiguous when there is more than one registered provider. + * Not configuring explicitly the provider on a firewall is ambiguous when there is more than one registered provider. The first configured provider is not used anymore and an exception is thrown instead. Explicitly configure the provider to use on your firewalls. diff --git a/composer.json b/composer.json index 7b55e30efd330..373e4b6aca9c1 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "ext-xml": "*", "doctrine/common": "~2.4", "fig/link-util": "^1.0", - "twig/twig": "~1.34|~2.4", + "twig/twig": "^1.35|^2.4.4", "psr/cache": "~1.0", "psr/container": "^1.0", "psr/link": "^1.0", diff --git a/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php b/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php index 62c6a2381a940..bca53ef4092b7 100644 --- a/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php +++ b/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php @@ -28,6 +28,10 @@ class DoctrineDataCollector extends DataCollector private $registry; private $connections; private $managers; + + /** + * @var DebugStack[] + */ private $loggers = array(); public function __construct(ManagerRegistry $registry) @@ -65,6 +69,16 @@ public function collect(Request $request, Response $response, \Exception $except ); } + public function reset() + { + $this->data = array(); + + foreach ($this->loggers as $logger) { + $logger->queries = array(); + $logger->currentQuery = 0; + } + } + public function getManagers() { return $this->data['managers']; diff --git a/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php b/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php index 8cbd2c3eacb3c..cc20869c7c5c6 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php @@ -101,6 +101,20 @@ public function testCollectQueryWithNoParams() $this->assertTrue($collectedQueries['default'][1]['explainable']); } + public function testReset() + { + $queries = array( + array('sql' => 'SELECT * FROM table1', 'params' => array(), 'types' => array(), 'executionMS' => 1), + ); + $c = $this->createCollector($queries); + $c->collect(new Request(), new Response()); + + $c->reset(); + $c->collect(new Request(), new Response()); + + $this->assertEquals(array('default' => array()), $c->getQueries()); + } + /** * @dataProvider paramProvider */ diff --git a/src/Symfony/Bridge/Monolog/Logger.php b/src/Symfony/Bridge/Monolog/Logger.php index ec6434fe791b8..7cd75c5ec11ca 100644 --- a/src/Symfony/Bridge/Monolog/Logger.php +++ b/src/Symfony/Bridge/Monolog/Logger.php @@ -45,6 +45,16 @@ public function countErrors() return 0; } + /** + * {@inheritdoc} + */ + public function clear() + { + if (($logger = $this->getDebugLogger()) && method_exists($logger, 'clear')) { + $logger->clear(); + } + } + /** * Returns a DebugLoggerInterface instance if one is registered with this logger. * diff --git a/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php b/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php index 22a4faac5cc9a..8774045192f3b 100644 --- a/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php +++ b/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php @@ -55,4 +55,13 @@ public function countErrors() { return $this->errorCount; } + + /** + * {@inheritdoc} + */ + public function clear() + { + $this->records = array(); + $this->errorCount = 0; + } } diff --git a/src/Symfony/Bridge/Monolog/Tests/LoggerTest.php b/src/Symfony/Bridge/Monolog/Tests/LoggerTest.php index c24c7a4133baf..a5fab0583c749 100644 --- a/src/Symfony/Bridge/Monolog/Tests/LoggerTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/LoggerTest.php @@ -128,4 +128,17 @@ public function testGetLogsWithDebugProcessor2() $this->assertEquals('test', $record['message']); $this->assertEquals(Logger::INFO, $record['priority']); } + + public function testClear() + { + $handler = new TestHandler(); + $logger = new Logger('test', array($handler)); + $logger->pushProcessor(new DebugProcessor()); + + $logger->addInfo('test'); + $logger->clear(); + + $this->assertEmpty($logger->getLogs()); + $this->assertSame(0, $logger->countErrors()); + } } diff --git a/src/Symfony/Bridge/Twig/DataCollector/TwigDataCollector.php b/src/Symfony/Bridge/Twig/DataCollector/TwigDataCollector.php index d5efaa805362c..66f2a764e7617 100644 --- a/src/Symfony/Bridge/Twig/DataCollector/TwigDataCollector.php +++ b/src/Symfony/Bridge/Twig/DataCollector/TwigDataCollector.php @@ -44,6 +44,16 @@ public function collect(Request $request, Response $response, \Exception $except { } + /** + * {@inheritdoc} + */ + public function reset() + { + $this->profile->reset(); + $this->computed = null; + $this->data = array(); + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index e1e86408cff33..bf4deb3f6e787 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^5.5.9|>=7.0.8", - "twig/twig": "~1.34|~2.4" + "twig/twig": "^1.35|^2.4.4" }, "require-dev": { "fig/link-util": "^1.0", diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 0e136bfe436f7..90673719814b5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -609,9 +609,9 @@ private function registerProfilerConfiguration(array $config, ContainerBuilder $ } } - if (!$config['collect']) { - $container->getDefinition('profiler')->addMethodCall('disable', array()); - } + $container->getDefinition('profiler') + ->addArgument($config['collect']) + ->addTag('kernel.reset', array('method' => 'reset')); } /** diff --git a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php index fbd146452f26d..086cea89d9620 100644 --- a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php +++ b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php @@ -203,6 +203,14 @@ public function collect(Request $request, Response $response, \Exception $except } } + /** + * {@inheritdoc} + */ + public function reset() + { + $this->data = array(); + } + public function lateCollect() { $this->data = $this->cloneVar($this->data); diff --git a/src/Symfony/Component/Cache/DataCollector/CacheDataCollector.php b/src/Symfony/Component/Cache/DataCollector/CacheDataCollector.php index 07ddaf3f4790a..62d502f01fd6b 100644 --- a/src/Symfony/Component/Cache/DataCollector/CacheDataCollector.php +++ b/src/Symfony/Component/Cache/DataCollector/CacheDataCollector.php @@ -53,6 +53,15 @@ public function collect(Request $request, Response $response, \Exception $except $this->data['total']['statistics'] = $this->calculateTotalStatistics(); } + public function reset() + { + $this->data = array(); + foreach ($this->instances as $instance) { + // Calling getCalls() will clear the calls. + $instance->getCalls(); + } + } + public function lateCollect() { $this->data = $this->cloneVar($this->data); diff --git a/src/Symfony/Component/EventDispatcher/CHANGELOG.md b/src/Symfony/Component/EventDispatcher/CHANGELOG.md index 736bd84903b4b..c6aa5389ac724 100644 --- a/src/Symfony/Component/EventDispatcher/CHANGELOG.md +++ b/src/Symfony/Component/EventDispatcher/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +3.4.0 +----- + + * Implementing `TraceableEventDispatcherInterface` without the `reset()` method has been deprecated. + 3.3.0 ----- diff --git a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php index 3f1035e13dd98..2fb795f77b246 100644 --- a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php @@ -212,6 +212,11 @@ public function getNotCalledListeners() return $notCalled; } + public function reset() + { + $this->called = array(); + } + /** * Proxies all method calls to the original event dispatcher. * diff --git a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php index 5483e815068c4..f0212753be591 100644 --- a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php +++ b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php @@ -15,6 +15,8 @@ /** * @author Fabien Potencier + * + * @method reset() Resets the trace. */ interface TraceableEventDispatcherInterface extends EventDispatcherInterface { diff --git a/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php index a1cf6708b3a56..53a3421afaf6a 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php @@ -124,6 +124,21 @@ public function testGetCalledListeners() $this->assertEquals(array(), $tdispatcher->getNotCalledListeners()); } + public function testClearCalledListeners() + { + $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); + $tdispatcher->addListener('foo', function () {}, 5); + + $tdispatcher->dispatch('foo'); + $tdispatcher->reset(); + + $listeners = $tdispatcher->getNotCalledListeners(); + $this->assertArrayHasKey('stub', $listeners['foo.closure']); + unset($listeners['foo.closure']['stub']); + $this->assertEquals(array(), $tdispatcher->getCalledListeners()); + $this->assertEquals(array('foo.closure' => array('event' => 'foo', 'pretty' => 'closure', 'priority' => 5)), $listeners); + } + public function testGetCalledListenersNested() { $tdispatcher = null; diff --git a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php index 378edf563b972..db854b01bf7a0 100644 --- a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php +++ b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php @@ -72,12 +72,9 @@ class FormDataCollector extends DataCollector implements FormDataCollectorInterf public function __construct(FormDataExtractorInterface $dataExtractor) { $this->dataExtractor = $dataExtractor; - $this->data = array( - 'forms' => array(), - 'forms_by_hash' => array(), - 'nb_errors' => 0, - ); $this->hasVarDumper = class_exists(ClassStub::class); + + $this->reset(); } /** @@ -87,6 +84,15 @@ public function collect(Request $request, Response $response, \Exception $except { } + public function reset() + { + $this->data = array( + 'forms' => array(), + 'forms_by_hash' => array(), + 'nb_errors' => 0, + ); + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php index 24c0f8e871da1..7e591d414e456 100644 --- a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php @@ -695,6 +695,36 @@ public function testCollectSubmittedDataExpandedFormsErrors() $this->assertFalse(isset($child21Data['has_children_error']), 'The leaf data does not contains "has_children_error" property.'); } + public function testReset() + { + $form = $this->createForm('my_form'); + + $this->dataExtractor->expects($this->any()) + ->method('extractConfiguration') + ->will($this->returnValue(array())); + $this->dataExtractor->expects($this->any()) + ->method('extractDefaultData') + ->will($this->returnValue(array())); + $this->dataExtractor->expects($this->any()) + ->method('extractSubmittedData') + ->with($form) + ->will($this->returnValue(array('errors' => array('baz')))); + + $this->dataCollector->buildPreliminaryFormTree($form); + $this->dataCollector->collectSubmittedData($form); + + $this->dataCollector->reset(); + + $this->assertSame( + array( + 'forms' => array(), + 'forms_by_hash' => array(), + 'nb_errors' => 0, + ), + $this->dataCollector->getData() + ); + } + private function createForm($name) { $builder = new FormBuilder($name, null, $this->dispatcher, $this->factory); diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index 1da376f7ad36c..fb29f76962928 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -14,7 +14,9 @@ CHANGELOG * deprecated the `ChainCacheClearer::add()` method * deprecated the `CacheaWarmerAggregate::add()` and `setWarmers()` methods * made `CacheWarmerAggregate` and `ChainCacheClearer` classes final - + * added the possibility to reset the profiler to its initial state + * deprecated data collectors without a `reset()` method + * deprecated implementing `DebugLoggerInterface` without a `clear()` method 3.3.0 ----- diff --git a/src/Symfony/Component/HttpKernel/DataCollector/AjaxDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/AjaxDataCollector.php index b8405d5945af0..370a874fe5d5c 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/AjaxDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/AjaxDataCollector.php @@ -26,6 +26,11 @@ public function collect(Request $request, Response $response, \Exception $except // all collecting is done client side } + public function reset() + { + // all collecting is done client side + } + public function getName() { return 'ajax'; diff --git a/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php index 965342191b4cf..0a6aa82b263bd 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php @@ -95,6 +95,14 @@ public function collect(Request $request, Response $response, \Exception $except } } + /** + * {@inheritdoc} + */ + public function reset() + { + $this->data = array(); + } + public function lateCollect() { $this->data = $this->cloneVar($this->data); diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DataCollectorInterface.php b/src/Symfony/Component/HttpKernel/DataCollector/DataCollectorInterface.php index 2820ad5b289b5..c0a0c0a982b3b 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/DataCollectorInterface.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/DataCollectorInterface.php @@ -18,6 +18,8 @@ * DataCollectorInterface. * * @author Fabien Potencier + * + * @method reset() Resets this data collector to its initial state. */ interface DataCollectorInterface { diff --git a/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php index 3d75f322d831b..ab44405edb2e7 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php @@ -27,6 +27,9 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter public function __construct(EventDispatcherInterface $dispatcher = null) { + if ($dispatcher instanceof TraceableEventDispatcherInterface && !method_exists($dispatcher, 'reset')) { + @trigger_error(sprintf('Implementing "%s" without the "reset()" method is deprecated since version 3.4 and will be unsupported in 4.0 for class "%s".', TraceableEventDispatcherInterface::class, \get_class($dispatcher)), E_USER_DEPRECATED); + } $this->dispatcher = $dispatcher; } @@ -41,6 +44,19 @@ public function collect(Request $request, Response $response, \Exception $except ); } + public function reset() + { + $this->data = array(); + + if ($this->dispatcher instanceof TraceableEventDispatcherInterface) { + if (!method_exists($this->dispatcher, 'reset')) { + return; // @deprecated + } + + $this->dispatcher->reset(); + } + } + public function lateCollect() { if ($this->dispatcher instanceof TraceableEventDispatcherInterface) { diff --git a/src/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php index 9fe826446b195..7a25f149215b8 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php @@ -34,6 +34,14 @@ public function collect(Request $request, Response $response, \Exception $except } } + /** + * {@inheritdoc} + */ + public function reset() + { + $this->data = array(); + } + /** * Checks if the exception is not null. * diff --git a/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php index 92fd0da71e648..ee645d53e8fdb 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php @@ -29,6 +29,10 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte public function __construct($logger = null, $containerPathPrefix = null) { if (null !== $logger && $logger instanceof DebugLoggerInterface) { + if (!method_exists($logger, 'clear')) { + @trigger_error(sprintf('Implementing "%s" without the "clear()" method is deprecated since version 3.4 and will be unsupported in 4.0 for class "%s".', DebugLoggerInterface::class, \get_class($logger)), E_USER_DEPRECATED); + } + $this->logger = $logger; } @@ -43,6 +47,17 @@ public function collect(Request $request, Response $response, \Exception $except // everything is done as late as possible } + /** + * {@inheritdoc} + */ + public function reset() + { + if ($this->logger && method_exists($this->logger, 'clear')) { + $this->logger->clear(); + } + $this->data = array(); + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php index b7f61f46fd19b..8d8cc1a04d181 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php @@ -23,10 +23,7 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte { public function __construct() { - $this->data = array( - 'memory' => 0, - 'memory_limit' => $this->convertToBytes(ini_get('memory_limit')), - ); + $this->reset(); } /** @@ -37,6 +34,17 @@ public function collect(Request $request, Response $response, \Exception $except $this->updateMemoryUsage(); } + /** + * {@inheritdoc} + */ + public function reset() + { + $this->data = array( + 'memory' => 0, + 'memory_limit' => $this->convertToBytes(ini_get('memory_limit')), + ); + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php index 7049844f9ed5d..d27940266a8f1 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php @@ -156,6 +156,12 @@ public function lateCollect() $this->data = $this->cloneVar($this->data); } + public function reset() + { + $this->data = array(); + $this->controllers = new \SplObjectStorage(); + } + public function getMethod() { return $this->data['method']; diff --git a/src/Symfony/Component/HttpKernel/DataCollector/RouterDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/RouterDataCollector.php index 76d962346175e..59f77c4ba29d8 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/RouterDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/RouterDataCollector.php @@ -23,17 +23,14 @@ */ class RouterDataCollector extends DataCollector { + /** + * @var \SplObjectStorage + */ protected $controllers; public function __construct() { - $this->controllers = new \SplObjectStorage(); - - $this->data = array( - 'redirect' => false, - 'url' => null, - 'route' => null, - ); + $this->reset(); } /** @@ -53,6 +50,17 @@ public function collect(Request $request, Response $response, \Exception $except unset($this->controllers[$request]); } + public function reset() + { + $this->controllers = new \SplObjectStorage(); + + $this->data = array( + 'redirect' => false, + 'url' => null, + 'route' => null, + ); + } + protected function guessRoute(Request $request, $controller) { return 'n/a'; diff --git a/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php index 2d39156e69e44..6588304935d3d 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php @@ -49,6 +49,14 @@ public function collect(Request $request, Response $response, \Exception $except ); } + /** + * {@inheritdoc} + */ + public function reset() + { + $this->data = array(); + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/HttpKernel/Log/DebugLoggerInterface.php b/src/Symfony/Component/HttpKernel/Log/DebugLoggerInterface.php index 5635a2184f007..f0606d3b0e5ee 100644 --- a/src/Symfony/Component/HttpKernel/Log/DebugLoggerInterface.php +++ b/src/Symfony/Component/HttpKernel/Log/DebugLoggerInterface.php @@ -15,6 +15,8 @@ * DebugLoggerInterface. * * @author Fabien Potencier + * + * @method clear() Removes all log records. */ interface DebugLoggerInterface { diff --git a/src/Symfony/Component/HttpKernel/Profiler/Profiler.php b/src/Symfony/Component/HttpKernel/Profiler/Profiler.php index 2580b4fffa002..85a71641be6fe 100644 --- a/src/Symfony/Component/HttpKernel/Profiler/Profiler.php +++ b/src/Symfony/Component/HttpKernel/Profiler/Profiler.php @@ -40,6 +40,11 @@ class Profiler */ private $logger; + /** + * @var bool + */ + private $initiallyEnabled = true; + /** * @var bool */ @@ -48,11 +53,13 @@ class Profiler /** * @param ProfilerStorageInterface $storage A ProfilerStorageInterface instance * @param LoggerInterface $logger A LoggerInterface instance + * @param bool $enable The initial enabled state */ - public function __construct(ProfilerStorageInterface $storage, LoggerInterface $logger = null) + public function __construct(ProfilerStorageInterface $storage, LoggerInterface $logger = null, $enable = true) { $this->storage = $storage; $this->logger = $logger; + $this->initiallyEnabled = $this->enabled = (bool) $enable; } /** @@ -188,6 +195,18 @@ public function collect(Request $request, Response $response, \Exception $except return $profile; } + public function reset() + { + foreach ($this->collectors as $collector) { + if (!method_exists($collector, 'reset')) { + continue; + } + + $collector->reset(); + } + $this->enabled = $this->initiallyEnabled; + } + /** * Gets the Collectors associated with this profiler. * @@ -218,6 +237,10 @@ public function set(array $collectors = array()) */ public function add(DataCollectorInterface $collector) { + if (!method_exists($collector, 'reset')) { + @trigger_error(sprintf('Implementing "%s" without the "reset()" method is deprecated since version 3.4 and will be unsupported in 4.0 for class "%s".', DataCollectorInterface::class, \get_class($collector)), E_USER_DEPRECATED); + } + $this->collectors[$collector->getName()] = $collector; } diff --git a/src/Symfony/Component/HttpKernel/Tests/DataCollector/ExceptionDataCollectorTest.php b/src/Symfony/Component/HttpKernel/Tests/DataCollector/ExceptionDataCollectorTest.php index afad9f58af638..178f1f01a3fc0 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DataCollector/ExceptionDataCollectorTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DataCollector/ExceptionDataCollectorTest.php @@ -37,4 +37,23 @@ public function testCollect() $this->assertSame('exception', $c->getName()); $this->assertSame($trace, $c->getTrace()); } + + public function testCollectWithoutException() + { + $c = new ExceptionDataCollector(); + $c->collect(new Request(), new Response()); + + $this->assertFalse($c->hasException()); + } + + public function testReset() + { + $c = new ExceptionDataCollector(); + + $c->collect(new Request(), new Response(), new \Exception()); + $c->reset(); + $c->collect(new Request(), new Response()); + + $this->assertFalse($c->hasException()); + } } diff --git a/src/Symfony/Component/HttpKernel/Tests/DataCollector/LoggerDataCollectorTest.php b/src/Symfony/Component/HttpKernel/Tests/DataCollector/LoggerDataCollectorTest.php index 62bf2c00c7586..3dec3bd7f87a0 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DataCollector/LoggerDataCollectorTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DataCollector/LoggerDataCollectorTest.php @@ -19,7 +19,10 @@ class LoggerDataCollectorTest extends TestCase { public function testCollectWithUnexpectedFormat() { - $logger = $this->getMockBuilder('Symfony\Component\HttpKernel\Log\DebugLoggerInterface')->getMock(); + $logger = $this + ->getMockBuilder('Symfony\Component\HttpKernel\Log\DebugLoggerInterface') + ->setMethods(array('countErrors', 'getLogs', 'clear')) + ->getMock(); $logger->expects($this->once())->method('countErrors')->will($this->returnValue('foo')); $logger->expects($this->exactly(2))->method('getLogs')->will($this->returnValue(array())); @@ -43,7 +46,10 @@ public function testCollectWithUnexpectedFormat() */ public function testCollect($nb, $logs, $expectedLogs, $expectedDeprecationCount, $expectedScreamCount, $expectedPriorities = null) { - $logger = $this->getMockBuilder('Symfony\Component\HttpKernel\Log\DebugLoggerInterface')->getMock(); + $logger = $this + ->getMockBuilder('Symfony\Component\HttpKernel\Log\DebugLoggerInterface') + ->setMethods(array('countErrors', 'getLogs', 'clear')) + ->getMock(); $logger->expects($this->once())->method('countErrors')->will($this->returnValue($nb)); $logger->expects($this->exactly(2))->method('getLogs')->will($this->returnValue($logs)); @@ -70,6 +76,18 @@ public function testCollect($nb, $logs, $expectedLogs, $expectedDeprecationCount } } + public function testReset() + { + $logger = $this + ->getMockBuilder('Symfony\Component\HttpKernel\Log\DebugLoggerInterface') + ->setMethods(array('countErrors', 'getLogs', 'clear')) + ->getMock(); + $logger->expects($this->once())->method('clear'); + + $c = new LoggerDataCollector($logger); + $c->reset(); + } + public function getCollectTestData() { yield 'simple log' => array( diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/DataCollector/CloneVarDataCollector.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/DataCollector/CloneVarDataCollector.php index 867ccdce57892..89dec36af4110 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fixtures/DataCollector/CloneVarDataCollector.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/DataCollector/CloneVarDataCollector.php @@ -29,6 +29,11 @@ public function collect(Request $request, Response $response, \Exception $except $this->data = $this->cloneVar($this->varToClone); } + public function reset() + { + $this->data = array(); + } + public function getData() { return $this->data; diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/TestEventDispatcher.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/TestEventDispatcher.php index da7ef5bd60381..ca2e6a693da6e 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fixtures/TestEventDispatcher.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/TestEventDispatcher.php @@ -25,4 +25,8 @@ public function getNotCalledListeners() { return array('bar'); } + + public function reset() + { + } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Profiler/ProfilerTest.php b/src/Symfony/Component/HttpKernel/Tests/Profiler/ProfilerTest.php index 1a6f54636a508..243c3c5c5a7cb 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Profiler/ProfilerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Profiler/ProfilerTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\HttpKernel\Tests\Profiler; use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface; use Symfony\Component\HttpKernel\DataCollector\RequestDataCollector; use Symfony\Component\HttpKernel\Profiler\FileProfilerStorage; use Symfony\Component\HttpKernel\Profiler\Profiler; @@ -40,6 +41,19 @@ public function testCollect() $this->assertSame('bar', $profile->getCollector('request')->getRequestQuery()->all()['foo']->getValue()); } + public function testReset() + { + $collector = $this->getMockBuilder(DataCollectorInterface::class) + ->setMethods(['collect', 'getName', 'reset']) + ->getMock(); + $collector->expects($this->any())->method('getName')->willReturn('mock'); + $collector->expects($this->once())->method('reset'); + + $profiler = new Profiler($this->storage); + $profiler->add($collector); + $profiler->reset(); + } + public function testFindWorksWithDates() { $profiler = new Profiler($this->storage); diff --git a/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php b/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php index 1696fc71ffeea..da45cce31e659 100644 --- a/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php +++ b/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php @@ -58,6 +58,14 @@ public function collect(Request $request, Response $response, \Exception $except { } + /** + * {@inheritdoc} + */ + public function reset() + { + $this->data = array(); + } + /** * @return array */ diff --git a/src/Symfony/Component/Validator/DataCollector/ValidatorDataCollector.php b/src/Symfony/Component/Validator/DataCollector/ValidatorDataCollector.php index d2b3f4626264c..aa8c61f96bff9 100644 --- a/src/Symfony/Component/Validator/DataCollector/ValidatorDataCollector.php +++ b/src/Symfony/Component/Validator/DataCollector/ValidatorDataCollector.php @@ -19,6 +19,7 @@ use Symfony\Component\Validator\Validator\TraceableValidator; use Symfony\Component\VarDumper\Caster\Caster; use Symfony\Component\VarDumper\Caster\ClassStub; +use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Cloner\Stub; /** @@ -31,10 +32,7 @@ class ValidatorDataCollector extends DataCollector implements LateDataCollectorI public function __construct(TraceableValidator $validator) { $this->validator = $validator; - $this->data = array( - 'calls' => array(), - 'violations_count' => 0, - ); + $this->reset(); } /** @@ -45,6 +43,15 @@ public function collect(Request $request, Response $response, \Exception $except // Everything is collected once, on kernel terminate. } + public function reset() + { + $this->validator->reset(); + $this->data = array( + 'calls' => $this->cloneVar(array()), + 'violations_count' => 0, + ); + } + /** * {@inheritdoc} */ @@ -52,16 +59,22 @@ public function lateCollect() { $collected = $this->validator->getCollectedData(); $this->data['calls'] = $this->cloneVar($collected); - $this->data['violations_count'] += array_reduce($collected, function ($previous, $item) { - return $previous += count($item['violations']); + $this->data['violations_count'] = array_reduce($collected, function ($previous, $item) { + return $previous + count($item['violations']); }, 0); } + /** + * @return Data + */ public function getCalls() { return $this->data['calls']; } + /** + * @return int + */ public function getViolationsCount() { return $this->data['violations_count']; diff --git a/src/Symfony/Component/Validator/Tests/DataCollector/ValidatorDataCollectorTest.php b/src/Symfony/Component/Validator/Tests/DataCollector/ValidatorDataCollectorTest.php index 811a55829a479..c078d283509c6 100644 --- a/src/Symfony/Component/Validator/Tests/DataCollector/ValidatorDataCollectorTest.php +++ b/src/Symfony/Component/Validator/Tests/DataCollector/ValidatorDataCollectorTest.php @@ -50,6 +50,33 @@ public function testCollectsValidatorCalls() $this->assertCount(2, $call['violations']); } + public function testReset() + { + $originalValidator = $this->createMock(ValidatorInterface::class); + $validator = new TraceableValidator($originalValidator); + + $collector = new ValidatorDataCollector($validator); + + $violations = new ConstraintViolationList(array( + $this->createMock(ConstraintViolation::class), + $this->createMock(ConstraintViolation::class), + )); + $originalValidator->method('validate')->willReturn($violations); + + $validator->validate(new \stdClass()); + + $collector->lateCollect(); + $collector->reset(); + + $this->assertCount(0, $collector->getCalls()); + $this->assertSame(0, $collector->getViolationsCount()); + + $collector->lateCollect(); + + $this->assertCount(0, $collector->getCalls()); + $this->assertSame(0, $collector->getViolationsCount()); + } + protected function createMock($classname) { return $this->getMockBuilder($classname)->disableOriginalConstructor()->getMock(); diff --git a/src/Symfony/Component/Validator/Validator/TraceableValidator.php b/src/Symfony/Component/Validator/Validator/TraceableValidator.php index 019559ae0023d..96134e2767468 100644 --- a/src/Symfony/Component/Validator/Validator/TraceableValidator.php +++ b/src/Symfony/Component/Validator/Validator/TraceableValidator.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Validator\Validator; -use Symfony\Component\Validator\ConstraintViolationList; use Symfony\Component\Validator\Context\ExecutionContextInterface; /** @@ -30,13 +29,18 @@ public function __construct(ValidatorInterface $validator) } /** - * @return ConstraintViolationList[] + * @return array */ public function getCollectedData() { return $this->collectedData; } + public function reset() + { + $this->collectedData = array(); + } + /** * {@inheritdoc} */