diff --git a/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php b/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php index f3d4bc032a9a..3b2e778ac866 100644 --- a/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php +++ b/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Doctrine\Logger; use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Symfony\Component\HttpKernel\Debug\Stopwatch; use Doctrine\DBAL\Logging\DebugStack; /** @@ -22,15 +23,18 @@ class DbalLogger extends DebugStack { protected $logger; + protected $stopwatch; /** * Constructor. * - * @param LoggerInterface $logger A LoggerInterface instance + * @param LoggerInterface $logger A LoggerInterface instance + * @param Stopwatch $stopwatch A Stopwatch instance */ - public function __construct(LoggerInterface $logger = null) + public function __construct(LoggerInterface $logger = null, Stopwatch $stopwatch = null) { $this->logger = $logger; + $this->stopwatch = $stopwatch; } /** @@ -40,11 +44,27 @@ public function startQuery($sql, array $params = null, array $types = null) { parent::startQuery($sql, $params, $types); + if (null !== $this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + if (null !== $this->logger) { $this->log($sql.' ('.json_encode($params).')'); } } + /** + * {@inheritdoc} + */ + public function stopQuery() + { + parent::stopQuery(); + + if (null !== $this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + /** * Logs a message. * diff --git a/src/Symfony/Bundle/DoctrineBundle/Resources/config/dbal.xml b/src/Symfony/Bundle/DoctrineBundle/Resources/config/dbal.xml index 6c854b6280d9..874f9e2f15ed 100644 --- a/src/Symfony/Bundle/DoctrineBundle/Resources/config/dbal.xml +++ b/src/Symfony/Bundle/DoctrineBundle/Resources/config/dbal.xml @@ -22,6 +22,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/ContainerAwareEventDispatcher.php b/src/Symfony/Bundle/FrameworkBundle/ContainerAwareEventDispatcher.php index 44fc5c1d3ecd..af90bab5815a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/ContainerAwareEventDispatcher.php +++ b/src/Symfony/Bundle/FrameworkBundle/ContainerAwareEventDispatcher.php @@ -140,6 +140,11 @@ public function dispatch($eventName, Event $event = null) parent::dispatch($eventName, $event); } + public function getContainer() + { + return $this->container; + } + /** * Lazily loads listeners for this event from the dependency injection * container. diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/TraceableControllerResolver.php b/src/Symfony/Bundle/FrameworkBundle/Controller/TraceableControllerResolver.php new file mode 100644 index 000000000000..4994beaaa43f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/TraceableControllerResolver.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Controller; + +use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Symfony\Component\HttpKernel\Debug\Stopwatch; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser; + +/** + * TraceableControllerResolver. + * + * @author Fabien Potencier + */ +class TraceableControllerResolver extends ControllerResolver +{ + private $stopwatch; + + /** + * Constructor. + * + * @param ContainerInterface $container A ContainerInterface instance + * @param ControllerNameParser $parser A ControllerNameParser instance + * @param Stopwatch $stopwatch A Stopwatch instance + * @param LoggerInterface $logger A LoggerInterface instance + */ + public function __construct(ContainerInterface $container, ControllerNameParser $parser, Stopwatch $stopwatch, LoggerInterface $logger = null) + { + parent::__construct($container, $parser, $logger); + + $this->stopwatch = $stopwatch; + } + + /** + * @{inheritdoc} + */ + public function getController(Request $request) + { + $e = $this->stopwatch->start('controller.get_callable'); + + $ret = parent::getController($request); + + $e->stop(); + + return $ret; + } + + /** + * @{inheritdoc} + */ + public function getArguments(Request $request, $controller) + { + $e = $this->stopwatch->start('controller.get_arguments'); + + $ret = parent::getArguments($request, $controller); + + $e->stop(); + + return $ret; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Debug/TraceableEventDispatcher.php b/src/Symfony/Bundle/FrameworkBundle/Debug/TraceableEventDispatcher.php index e36fba9475be..27bda5c00a83 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Debug/TraceableEventDispatcher.php +++ b/src/Symfony/Bundle/FrameworkBundle/Debug/TraceableEventDispatcher.php @@ -12,10 +12,13 @@ namespace Symfony\Bundle\FrameworkBundle\Debug; use Symfony\Bundle\FrameworkBundle\ContainerAwareEventDispatcher; +use Symfony\Component\HttpKernel\Debug\Stopwatch; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpKernel\Debug\TraceableEventDispatcherInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\HttpKernel\Profiler\Profiler; +use Symfony\Component\HttpKernel\Profiler\Profile; /** * Extends the ContainerAwareEventDispatcher to add some debugging tools. @@ -26,21 +29,53 @@ class TraceableEventDispatcher extends ContainerAwareEventDispatcher implements { private $logger; private $called; + private $stopwatch; /** * Constructor. * * @param ContainerInterface $container A ContainerInterface instance + * @param Stopwatch $stopwatch A Stopwatch instance * @param LoggerInterface $logger A LoggerInterface instance */ - public function __construct(ContainerInterface $container, LoggerInterface $logger = null) + public function __construct(ContainerInterface $container, Stopwatch $stopwatch, LoggerInterface $logger = null) { parent::__construct($container); + $this->stopwatch = $stopwatch; $this->logger = $logger; $this->called = array(); } + public function dispatch($eventName, Event $event = null) + { + if ('kernel.request' === $eventName) { + $this->stopwatch->startSection(); + } elseif ('kernel.view' === $eventName || 'kernel.response' === $eventName) { + // stop only if a controller has been executed + try { + $this->stopwatch->stop('controller'); + } catch (\LogicException $e) { + } + } + + $e1 = $this->stopwatch->start($eventName, 'section'); + + parent::dispatch($eventName, $event); + + $e1->stop(); + + if ('kernel.controller' === $eventName) { + $this->stopwatch->start('controller', 'section'); + } elseif ('kernel.response' === $eventName) { + $token = $event->getResponse()->headers->get('X-Debug-Token'); + + $this->stopwatch->stopSection($token); + + $this->updateProfile($token); + } + } + /** * {@inheritDoc} * @@ -79,8 +114,12 @@ protected function doDispatch($listeners, $eventName, Event $event) $this->called[$eventName.'.'.$info['pretty']] = $info; + $e2 = $this->stopwatch->start(substr($info['class'], strrpos($info['class'], '\\') + 1), 'event_listener'); + call_user_func($listener, $event); + $e2->stop(); + if ($event->isPropagationStopped()) { if (null !== $this->logger) { $this->logger->debug(sprintf('Listener "%s" stopped propagation of the event "%s".', $info['pretty'], $eventName)); @@ -115,6 +154,18 @@ protected function doDispatch($listeners, $eventName, Event $event) } } + /** + * {@inheritDoc} + */ + protected function lazyLoad($eventName) + { + $e = $this->stopwatch->start($eventName.'.loading', 'event_listener_loading'); + + parent::lazyLoad($eventName); + + $e->stop(); + } + /** * {@inheritDoc} */ @@ -199,4 +250,25 @@ private function getListenerInfo($listener, $eventName) return $info; } + + private function updateProfile($token) + { + if (!$this->getContainer()->has('profiler')) { + return; + } + + $profiler = $this->getContainer()->get('profiler'); + if (!$profile = $profiler->loadProfile($token)) { + return; + } + + $profile->getCollector('time')->setEvents($this->stopwatch->getSectionEvents($profile->getToken())); + $profiler->saveProfile($profile); + + // children + foreach ($profile->getChildren() as $child) { + $child->getCollector('time')->setEvents($this->stopwatch->getSectionEvents($child->getToken())); + $profiler->saveProfile($child); + } + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 82765bab66bb..131f62fd8e18 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -53,6 +53,9 @@ public function load(array $configs, ContainerBuilder $container) $loader->load('debug.xml'); $container->setDefinition('event_dispatcher', $container->findDefinition('debug.event_dispatcher')); $container->setAlias('debug.event_dispatcher', 'event_dispatcher'); + + $container->setDefinition('controller_resolver', $container->findDefinition('debug.controller_resolver')); + $container->setAlias('debug.controller_resolver', 'controller_resolver'); } $configuration = new Configuration($container->getParameter('kernel.debug')); diff --git a/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php b/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php index 2f0ca70c88a0..73319e45cdd4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php +++ b/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php @@ -21,6 +21,7 @@ /** * This HttpKernel is used to manage scope changes of the DI container. * + * @author Fabien Potencier * @author Johannes M. Schmitt */ class HttpKernel extends BaseHttpKernel diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml index cdb7edf98745..d8b766010070 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml @@ -10,7 +10,7 @@ Symfony\Component\HttpKernel\DataCollector\ExceptionDataCollector Symfony\Component\HttpKernel\DataCollector\EventDataCollector Symfony\Component\HttpKernel\DataCollector\LoggerDataCollector - Symfony\Component\HttpKernel\DataCollector\TimerDataCollector + Symfony\Component\HttpKernel\DataCollector\TimeDataCollector Symfony\Component\HttpKernel\DataCollector\MemoryDataCollector @@ -21,7 +21,6 @@ - @@ -42,8 +41,8 @@ - - + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml index 9883dac38469..93964b89a70c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml @@ -6,14 +6,27 @@ Symfony\Bundle\FrameworkBundle\Debug\TraceableEventDispatcher + Symfony\Component\HttpKernel\Debug\Stopwatch %kernel.cache_dir%/%kernel.container_class%.xml + Symfony\Bundle\FrameworkBundle\Controller\TraceableControllerResolver + + + + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Debug/TraceableEventDispatcherTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Debug/TraceableEventDispatcherTest.php index 25d5f8992149..557ab433ed61 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Debug/TraceableEventDispatcherTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Debug/TraceableEventDispatcherTest.php @@ -13,6 +13,7 @@ use Symfony\Bundle\FrameworkBundle\Tests\TestCase; use Symfony\Bundle\FrameworkBundle\Debug\TraceableEventDispatcher; +use Symfony\Component\HttpKernel\Debug\Stopwatch; class TraceableEventDispatcherTest extends TestCase { @@ -23,7 +24,7 @@ class TraceableEventDispatcherTest extends TestCase public function testThrowsAnExceptionWhenAListenerMethodIsNotCallable() { $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'); - $dispatcher = new TraceableEventDispatcher($container); + $dispatcher = new TraceableEventDispatcher($container, new Stopwatch()); $dispatcher->addListener('onFooEvent', new \stdClass()); } } diff --git a/src/Symfony/Bundle/TwigBundle/Debug/TimedTwigEngine.php b/src/Symfony/Bundle/TwigBundle/Debug/TimedTwigEngine.php new file mode 100644 index 000000000000..1e06e4eda3b4 --- /dev/null +++ b/src/Symfony/Bundle/TwigBundle/Debug/TimedTwigEngine.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\TwigBundle\Debug; + +use Symfony\Bundle\TwigBundle\TwigEngine; +use Symfony\Bundle\FrameworkBundle\Templating\GlobalVariables; +use Symfony\Component\Templating\TemplateNameParserInterface; +use Symfony\Component\HttpKernel\Debug\Stopwatch; + +/** + * Times the time spent to render a template. + * + * @author Fabien Potencier + */ +class TimedTwigEngine extends TwigEngine +{ + protected $stopwatch; + + /** + * Constructor. + * + * @param \Twig_Environment $environment A \Twig_Environment instance + * @param TemplateNameParserInterface $parser A TemplateNameParserInterface instance + * @param GlobalVariables|null $globals A GlobalVariables instance or null + * @param Stopwatch $stopwatch A Stopwatch instance + */ + public function __construct(\Twig_Environment $environment, TemplateNameParserInterface $parser, Stopwatch $stopwatch, GlobalVariables $globals = null) + { + parent::__construct($environment, $parser, $globals); + + $this->stopwatch = $stopwatch; + } + + /** + * {@inheritdoc} + */ + public function render($name, array $parameters = array()) + { + $e = $this->stopwatch->start(sprintf('template.twig (%s)', $name), 'template'); + + $ret = $this->load($name)->render($parameters); + + $e->stop(); + + return $ret; + } +} diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php index f7a65debd4fc..a27e378f3f9c 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php @@ -63,6 +63,13 @@ public function load(array $configs, ContainerBuilder $container) $container->setParameter('twig.options', $config); + if ($container->getParameter('kernel.debug')) { + $loader->load('debug.xml'); + + $container->setDefinition('templating.engine.twig', $container->findDefinition('debug.templating.engine.twig')); + $container->setAlias('debug.templating.engine.twig', 'templating.engine.twig'); + } + $this->addClassesToCompile(array( 'Twig_Environment', 'Twig_ExtensionInterface', diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/debug.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/debug.xml new file mode 100644 index 000000000000..b83eb8b0dcb3 --- /dev/null +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/debug.xml @@ -0,0 +1,19 @@ + + + + + + Symfony\Bundle\TwigBundle\Debug\TimedTwigEngine + + + + + + + + + + + diff --git a/src/Symfony/Bundle/TwigBundle/TwigEngine.php b/src/Symfony/Bundle/TwigBundle/TwigEngine.php index 7c9a6b22f5d9..639212acc34f 100644 --- a/src/Symfony/Bundle/TwigBundle/TwigEngine.php +++ b/src/Symfony/Bundle/TwigBundle/TwigEngine.php @@ -15,7 +15,6 @@ use Symfony\Bundle\FrameworkBundle\Templating\GlobalVariables; use Symfony\Component\Templating\TemplateNameParserInterface; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\DependencyInjection\ContainerInterface; /** * This engine knows how to render Twig templates. diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/public/css/profiler.css b/src/Symfony/Bundle/WebProfilerBundle/Resources/public/css/profiler.css index 01a6aa669d52..15196a313ee9 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/public/css/profiler.css +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/public/css/profiler.css @@ -427,3 +427,9 @@ td.main, td.menu { #navigation .import input { width: 100px; } + +.timeline { + background-color: #fbfbfb; + margin-bottom: 15px; + margin-top: 5px; +} diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/public/images/profiler/time.png b/src/Symfony/Bundle/WebProfilerBundle/Resources/public/images/profiler/time.png new file mode 100644 index 000000000000..95ec7e55283b Binary files /dev/null and b/src/Symfony/Bundle/WebProfilerBundle/Resources/public/images/profiler/time.png differ diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/public/images/timer.png b/src/Symfony/Bundle/WebProfilerBundle/Resources/public/images/time.png similarity index 100% rename from src/Symfony/Bundle/WebProfilerBundle/Resources/public/images/timer.png rename to src/Symfony/Bundle/WebProfilerBundle/Resources/public/images/time.png diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.html.twig new file mode 100644 index 000000000000..962550b0e00b --- /dev/null +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.html.twig @@ -0,0 +1,323 @@ +{% extends 'WebProfilerBundle:Profiler:layout.html.twig' %} + +{% if colors is not defined %} + {% set colors = { + 'default': '#aacd4e', + 'section': '#666', + 'event_listener': '#3dd', + 'event_listener_loading': '#add', + 'template': '#dd3', + 'doctrine': '#d3d', + 'child_sections': '#eed', + } %} +{% endif %} + +{% block toolbar %} + {% set icon %} + Time + {% endset %} + {% set text %} + {{ '%.0f'|format(collector.totaltime) }} ms + {% endset %} + {% include 'WebProfilerBundle:Profiler:toolbar_item.html.twig' with { 'link': profiler_url } %} +{% endblock %} + +{% block menu %} + + Timeline + Timeline + +{% endblock %} + +{% block panel %} +

Timeline

+ + {% set threshold = app.request.query.get('threshold', 1) %} + {% set width = app.request.query.get('width', 990) %} + +
+ + + + + + + + + + + + + + + + + + + + + + +
Total time{{ '%.0f'|format(collector.totaltime) }} ms
Initialization time{{ '%.0f'|format(collector.inittime) }} ms
Threshold ms
Width px
 
+
+ +

+ Main Request + + - {{ collector.events.section.totaltime }} ms + {% if profile.parent %} + - parent + {% endif %} + +

+ + {% set max = collector.events.section.endtime %} + + {{ _self.display_timeline('timeline_' ~ token, collector.events, threshold, colors, width) }} + + {% if profile.children|length %} + {% for child in profile.children %} + {% set events = child.getcollector('time').events %} +

+ Sub-request "{{ child.getcollector('request').requestattributes.get('_controller') }}" + - {{ events.section.totaltime }} ms +

+ + {{ _self.display_timeline('timeline_' ~ child.token, events, threshold, colors, width) }} + {% endfor %} + {% endif %} + + +{% endblock %} + +{% macro dump_request_data(token, profile, events, origin) %} + { + "id": "{{ token }}", + "left": {{ events.section.origin - origin }}, + "events": [ +{{ _self.dump_events(events) }} + ] + } +{% endmacro %} + +{% macro dump_events(events) %} +{% for name, event in events %} +{% if 'section' != name %} + { + "name": "{{ name }}", + "category": "{{ event.category }}", + "origin": {{ event.origin }}, + "starttime": {{ event.starttime }}, + "endtime": {{ event.endtime }}, + "totaltime": {{ event.totaltime }}, + "periods": [ + {%- for period in event.periods -%} + {"begin": {{ period.0 }}, "end": {{ period.1 }}}{{ loop.last ? '' : ', ' }} + {%- endfor -%} + ] + }{{ loop.last ? '' : ',' }} +{% endif %} +{% endfor %} +{% endmacro %} + +{% macro display_timeline(id, events, threshold, colors, width) %} + {% set height = 0 %} + {% for name, event in events if 'section' != name and event.totaltime >= threshold %} + {% set height = height + 38 %} + {% endfor %} + +
+ + {% for category, color in colors %} +     {{ category }}   + {% endfor %} + +
+ + +{% endmacro %} diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/timer.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/timer.html.twig deleted file mode 100644 index bc734ad3d39d..000000000000 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/timer.html.twig +++ /dev/null @@ -1,11 +0,0 @@ -{% extends 'WebProfilerBundle:Profiler:layout.html.twig' %} - -{% block toolbar %} - {% set icon %} - Timers - {% endset %} - {% set text %} - {{ '%.0f'|format(collector.time * 1000) }} ms - {% endset %} - {% include 'WebProfilerBundle:Profiler:toolbar_item.html.twig' with { 'link': false } %} -{% endblock %} diff --git a/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php new file mode 100644 index 000000000000..5896bff2cd71 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\DataCollector; + +use Symfony\Component\HttpKernel\DataCollector\DataCollector; +use Symfony\Component\HttpKernel\KernelInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + +/** + * TimeDataCollector. + * + * @author Fabien Potencier + */ +class TimeDataCollector extends DataCollector +{ + protected $kernel; + + public function __construct(KernelInterface $kernel = null) + { + $this->kernel = $kernel; + } + + /** + * {@inheritdoc} + */ + public function collect(Request $request, Response $response, \Exception $exception = null) + { + $this->data = array( + 'start_time' => (null !== $this->kernel ? $this->kernel->getStartTime() : $_SERVER['REQUEST_TIME']) * 1000, + 'events' => array(), + ); + } + + /** + * Sets the request events. + * + * @param array $event The request events + */ + public function setEvents(array $events) + { + foreach ($events as $event) { + $event->ensureStopped(); + } + + $this->data['events'] = $events; + } + + /** + * Gets the request events. + * + * @return array The request events + */ + public function getEvents() + { + return $this->data['events']; + } + + /** + * Gets the request elapsed time. + * + * @return integer The elapsed time + */ + public function getTotalTime() + { + $values = array_values($this->data['events']); + $lastEvent = $values[count($values) - 1]; + + return $lastEvent->getOrigin() + $lastEvent->getEndTime() - $this->data['start_time']; + } + + /** + * Gets the initialization time. + * + * This is the time spent until the beginning of the request handling. + * + * @return integer The elapsed time + */ + public function getInitTime() + { + return $this->data['events']['section']->getOrigin() - $this->getStartTime(); + } + + /** + * Gets the request time. + * + * @return integer The time + */ + public function getStartTime() + { + return $this->data['start_time']; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'time'; + } +} diff --git a/src/Symfony/Component/HttpKernel/DataCollector/TimerDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/TimerDataCollector.php deleted file mode 100644 index 3c8839e503e8..000000000000 --- a/src/Symfony/Component/HttpKernel/DataCollector/TimerDataCollector.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\HttpKernel\DataCollector; - -use Symfony\Component\HttpKernel\DataCollector\DataCollector; -use Symfony\Component\HttpKernel\KernelInterface; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; - -/** - * TimerDataCollector. - * - * @author Fabien Potencier - */ -class TimerDataCollector extends DataCollector -{ - protected $kernel; - - public function __construct(KernelInterface $kernel) - { - $this->kernel = $kernel; - } - - /** - * {@inheritdoc} - */ - public function collect(Request $request, Response $response, \Exception $exception = null) - { - $this->data = array( - 'time' => microtime(true) - $this->kernel->getStartTime(), - ); - } - - /** - * Gets the request time. - * - * @return integer The time - */ - public function getTime() - { - return $this->data['time']; - } - - /** - * {@inheritdoc} - */ - public function getName() - { - return 'timer'; - } -}