diff --git a/src/Symfony/Bundle/DoctrineBundle/DataCollector/DoctrineDataCollector.php b/src/Symfony/Bundle/DoctrineBundle/DataCollector/DoctrineDataCollector.php
index f7caa76284..8ff36ff17a 100644
--- a/src/Symfony/Bundle/DoctrineBundle/DataCollector/DoctrineDataCollector.php
+++ b/src/Symfony/Bundle/DoctrineBundle/DataCollector/DoctrineDataCollector.php
@@ -2,8 +2,10 @@
namespace Symfony\Bundle\DoctrineBundle\DataCollector;
-use Symfony\Component\HttpKernel\Profiler\DataCollector\DataCollector;
-use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpKernel\DataCollector\DataCollector;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Bundle\DoctrineBundle\Logger\DbalLogger;
/*
* This file is part of the Symfony framework.
@@ -21,21 +23,21 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/
class DoctrineDataCollector extends DataCollector
{
- protected $container;
+ protected $logger;
- public function __construct(ContainerInterface $container)
+ public function __construct(DbalLogger $logger = null)
{
- $this->container = $container;
+ $this->logger = $logger;
}
- public function collect()
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
{
- $this->data = array();
- if ($this->container->has('doctrine.dbal.logger')) {
- $this->data = array(
- 'queries' => $this->container->getDoctrine_Dbal_LoggerService()->queries,
- );
- }
+ $this->data = array(
+ 'queries' => null !== $this->logger ? $this->logger->queries : array(),
+ );
}
public function getQueryCount()
@@ -48,16 +50,9 @@ class DoctrineDataCollector extends DataCollector
return $this->data['queries'];
}
- public function getSummary()
- {
- $queries = count($this->data['queries']);
- $queriesColor = $queries < 10 ? '#2d2' : '#d22';
-
- return sprintf('
- %d
- ', $queriesColor, $queries);
- }
-
+ /**
+ * {@inheritdoc}
+ */
public function getName()
{
return 'db';
diff --git a/src/Symfony/Bundle/DoctrineBundle/Resources/config/dbal.xml b/src/Symfony/Bundle/DoctrineBundle/Resources/config/dbal.xml
index b326e2456e..fd7cbe7ba0 100644
--- a/src/Symfony/Bundle/DoctrineBundle/Resources/config/dbal.xml
+++ b/src/Symfony/Bundle/DoctrineBundle/Resources/config/dbal.xml
@@ -21,7 +21,7 @@
-
+
diff --git a/src/Symfony/Bundle/DoctrineMongoDBBundle/DataCollector/DoctrineMongoDBDataCollector.php b/src/Symfony/Bundle/DoctrineMongoDBBundle/DataCollector/DoctrineMongoDBDataCollector.php
index 620efb0ea9..0574ccf2cd 100644
--- a/src/Symfony/Bundle/DoctrineMongoDBBundle/DataCollector/DoctrineMongoDBDataCollector.php
+++ b/src/Symfony/Bundle/DoctrineMongoDBBundle/DataCollector/DoctrineMongoDBDataCollector.php
@@ -2,8 +2,10 @@
namespace Symfony\Bundle\DoctrineMongoDBBundle\DataCollector;
-use Symfony\Component\HttpKernel\Profiler\DataCollector\DataCollector;
+use Symfony\Component\HttpKernel\DataCollector\DataCollector;
use Symfony\Bundle\DoctrineMongoDBBundle\Logger\DoctrineMongoDBLogger;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
/**
* Data collector for the Doctrine MongoDB ODM.
@@ -19,20 +21,22 @@ class DoctrineMongoDBDataCollector extends DataCollector
$this->logger = $logger;
}
- public function collect()
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
{
$this->data['nb_queries'] = $this->logger->getNbQueries();
}
- public function getSummary()
+ public function getQueryCount()
{
- $color = $this->data['nb_queries'] < 10 ? '#2d2' : '#d22';
-
- return sprintf('
- %d
- ', $color, $this->data['nb_queries']);
+ return $this->data['nb_queries'];
}
+ /**
+ * {@inheritdoc}
+ */
public function getName()
{
return 'mongodb';
diff --git a/src/Symfony/Bundle/FrameworkBundle/DataCollector/AppDataCollector.php b/src/Symfony/Bundle/FrameworkBundle/DataCollector/AppDataCollector.php
deleted file mode 100644
index fdc853d2e9..0000000000
--- a/src/Symfony/Bundle/FrameworkBundle/DataCollector/AppDataCollector.php
+++ /dev/null
@@ -1,64 +0,0 @@
-
- *
- * This source file is subject to the MIT license that is bundled
- * with this source code in the file LICENSE.
- */
-
-/**
- * AppDataCollector.
- *
- * @author Fabien Potencier
- */
-class AppDataCollector extends DataCollector
-{
- protected $container;
-
- public function __construct(ContainerInterface $container)
- {
- $this->container = $container;
- }
-
- public function collect()
- {
- $request = $this->container->getRequestService();
-
- $this->data = array(
- 'route' => $request->attributes->get('_route') ? $request->attributes->get('_route') : 'NONE',
- 'format' => $request->getRequestFormat(),
- 'content_type' => $this->profiler->getResponse()->headers->get('Content-Type') ? $this->profiler->getResponse()->headers->get('Content-Type') : 'text/html',
- 'code' => $this->profiler->getResponse()->getStatusCode(),
- );
- }
-
- public function getRoute()
- {
- return $this->data['route'];
- }
-
- public function getFormat()
- {
- return $this->data['format'];
- }
-
- public function getSummary()
- {
- return sprintf('
- %s/%s/%s/%s
- ', $this->data['route'], $this->data['format'], 200 == $this->data['code'] ? '#3a3' : '#a33', $this->data['code'], $this->data['content_type']);
- }
-
- public function getName()
- {
- return 'app';
- }
-}
diff --git a/src/Symfony/Bundle/FrameworkBundle/DataCollector/ConfigDataCollector.php b/src/Symfony/Bundle/FrameworkBundle/DataCollector/ConfigDataCollector.php
index e2ea32c838..eb1d90ecf3 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DataCollector/ConfigDataCollector.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DataCollector/ConfigDataCollector.php
@@ -3,8 +3,10 @@
namespace Symfony\Bundle\FrameworkBundle\DataCollector;
use Symfony\Framework\Kernel;
-use Symfony\Component\HttpKernel\Profiler\DataCollector\DataCollector;
-use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpKernel\DataCollector\DataCollector;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Routing\RouterInterface;
/*
* This file is part of the Symfony framework.
@@ -22,23 +24,32 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/
class ConfigDataCollector extends DataCollector
{
- protected $container;
+ protected $kernel;
+ protected $router;
- public function __construct(ContainerInterface $container)
+ /**
+ * Constructor.
+ *
+ * @param Kernel $kernel A Kernel instance
+ * @param RouterInterface $router A Router instance
+ */
+ public function __construct(Kernel $kernel, RouterInterface $router = null)
{
- $this->container = $container;
+ $this->kernel = $kernel;
+ $this->router = $router;
}
- public function collect()
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
{
- $kernel = $this->container->getKernelService();
-
$this->data = array(
- 'token' => $this->profiler->getProfilerStorage()->getToken(),
+ 'token' => $response->headers->get('X-Debug-Token'),
'symfony_version' => Kernel::VERSION,
- 'name' => $kernel->getName(),
- 'env' => $kernel->getEnvironment(),
- 'debug' => $kernel->isDebug(),
+ 'name' => $this->kernel->getName(),
+ 'env' => $this->kernel->getEnvironment(),
+ 'debug' => $this->kernel->isDebug(),
'php_version' => PHP_VERSION,
'xdebug' => extension_loaded('xdebug'),
'accel' => (
@@ -51,17 +62,107 @@ class ConfigDataCollector extends DataCollector
);
}
- public function getSummary()
+ /**
+ * Gets the URL.
+ *
+ * @return string The URL
+ */
+ public function getUrl()
{
- return sprintf('
- %s
-
- %s/xdebug/accel
-
- %s/%s/%s/%s
- ', $this->data['symfony_version'], $this->data['php_version'], $this->data['xdebug'] ? '#3a3' : '#a33', $this->data['accel'] ? '#3a3' : '#a33', $this->data['name'], $this->data['env'], $this->data['debug'] ? 'debug' : 'no-debug', $this->data['token'], $this->data['token']);
+ if (null !== $this->router) {
+ try {
+ return $this->router->generate('_profiler', array('token' => $this->data['token']));
+ } catch (\Exception $e) {
+ // the route is not registered
+ }
+ }
+
+ return false;
}
+ /**
+ * Gets the token.
+ *
+ * @return string The token
+ */
+ public function getToken()
+ {
+ return $this->data['token'];
+ }
+
+ /**
+ * Gets the Symfony version.
+ *
+ * @return string The Symfony version
+ */
+ public function getSymfonyVersion()
+ {
+ return $this->data['symfony_version'];
+ }
+
+ /**
+ * Gets the PHP version.
+ *
+ * @return string The PHP version
+ */
+ public function getPhpVersion()
+ {
+ return $this->data['php_version'];
+ }
+
+ /**
+ * Gets the application name.
+ *
+ * @return string The application name
+ */
+ public function getAppName()
+ {
+ return $this->data['name'];
+ }
+
+ /**
+ * Gets the environment.
+ *
+ * @return string The environment
+ */
+ public function getEnv()
+ {
+ return $this->data['env'];
+ }
+
+ /**
+ * Returns true if the debug is enabled.
+ *
+ * @return Boolean true if debug is enabled, false otherwise
+ */
+ public function isDebug()
+ {
+ return $this->data['debug'];
+ }
+
+ /**
+ * Returns true if the XDebug is enabled.
+ *
+ * @return Boolean true if XDebug is enabled, false otherwise
+ */
+ public function hasXDebug()
+ {
+ return $this->data['xdebug'];
+ }
+
+ /**
+ * Returns true if an accelerator is enabled.
+ *
+ * @return Boolean true if an accelerator is enabled, false otherwise
+ */
+ public function hasAccelerator()
+ {
+ return $this->data['accel'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
public function getName()
{
return 'config';
diff --git a/src/Symfony/Bundle/FrameworkBundle/DataCollector/RequestDataCollector.php b/src/Symfony/Bundle/FrameworkBundle/DataCollector/RequestDataCollector.php
new file mode 100644
index 0000000000..160b79e823
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/DataCollector/RequestDataCollector.php
@@ -0,0 +1,44 @@
+
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+/**
+ * RequestDataCollector.
+ *
+ * @author Fabien Potencier
+ */
+class RequestDataCollector extends BaseRequestDataCollector
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
+ {
+ parent::collect($request, $response, $exception);
+
+ $this->data['route'] = $request->attributes->get('_route');
+ }
+
+ /**
+ * Gets the route.
+ *
+ * @return string The route
+ */
+ public function getRoute()
+ {
+ return $this->data['route'];
+ }
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/DataCollector/TimerDataCollector.php b/src/Symfony/Bundle/FrameworkBundle/DataCollector/TimerDataCollector.php
index f418a4569b..96be260889 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DataCollector/TimerDataCollector.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DataCollector/TimerDataCollector.php
@@ -2,8 +2,10 @@
namespace Symfony\Bundle\FrameworkBundle\DataCollector;
-use Symfony\Component\HttpKernel\Profiler\DataCollector\DataCollector;
-use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpKernel\DataCollector\DataCollector;
+use Symfony\Framework\Kernel;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
/*
* This file is part of the Symfony framework.
@@ -21,32 +23,36 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/
class TimerDataCollector extends DataCollector
{
- protected $container;
+ protected $kernel;
- public function __construct(ContainerInterface $container)
+ public function __construct(Kernel $kernel)
{
- $this->container = $container;
+ $this->kernel = $kernel;
}
- public function collect()
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
{
$this->data = array(
- 'time' => microtime(true) - $this->container->getKernelService()->getStartTime(),
+ 'time' => microtime(true) - $this->kernel->getStartTime(),
);
}
+ /**
+ * Gets the request time.
+ *
+ * @return integer The time
+ */
public function getTime()
{
return $this->data['time'];
}
- public function getSummary()
- {
- return sprintf('
- %.0f ms
- ', $this->data['time'] * 1000);
- }
-
+ /**
+ * {@inheritdoc}
+ */
public function getName()
{
return 'timer';
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/WebExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/WebExtension.php
index 7cbb089d8a..d2da5e87ee 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/WebExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/WebExtension.php
@@ -74,10 +74,6 @@ class WebExtension extends Extension
));
}
- if (isset($config['toolbar']) && $config['toolbar']) {
- $config['profiler'] = true;
- }
-
if (isset($config['profiler'])) {
if ($config['profiler']) {
if (!$container->hasDefinition('profiler')) {
@@ -90,18 +86,6 @@ class WebExtension extends Extension
}
}
- // toolbar need to be registered after the profiler
- if (isset($config['toolbar'])) {
- if ($config['toolbar']) {
- if (!$container->hasDefinition('debug.toolbar')) {
- $loader = new XmlFileLoader($container, __DIR__.'/../Resources/config');
- $loader->load('toolbar.xml');
- }
- } elseif ($container->hasDefinition('debug.toolbar')) {
- $container->getDefinition('debug.toolbar')->clearTags();
- }
- }
-
if (isset($config['validation']['enabled'])) {
$this->registerValidationConfiguration($config, $container);
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Profiler.php b/src/Symfony/Bundle/FrameworkBundle/Profiler.php
index e6cbe7e482..2d9f564d6a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Profiler.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Profiler.php
@@ -4,7 +4,7 @@ namespace Symfony\Bundle\FrameworkBundle;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Profiler\Profiler as BaseProfiler;
-use Symfony\Component\HttpKernel\Profiler\ProfilerStorage;
+use Symfony\Component\HttpKernel\Profiler\ProfilerStorageInterface;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
/*
@@ -23,34 +23,12 @@ use Symfony\Component\HttpKernel\Log\LoggerInterface;
*/
class Profiler extends BaseProfiler
{
- protected $container;
-
- public function __construct(ContainerInterface $container, ProfilerStorage $profilerStorage, LoggerInterface $logger = null)
+ public function __construct(ContainerInterface $container, ProfilerStorageInterface $storage, LoggerInterface $logger = null)
{
- parent::__construct($profilerStorage, $logger);
+ parent::__construct($storage, $logger);
- $this->container = $container;
- $this->initCollectors();
- $this->loadCollectorData();
- }
-
- protected function initCollectors()
- {
- $config = $this->container->findTaggedServiceIds('data_collector');
- $ids = array();
- $coreCollectors = array();
- $userCollectors = array();
- foreach ($config as $id => $attributes) {
- $collector = $this->container->get($id);
- $collector->setProfiler($this);
-
- if (isset($attributes[0]['core']) && $attributes[0]['core']) {
- $coreCollectors[$collector->getName()] = $collector;
- } else {
- $userCollectors[$collector->getName()] = $collector;
- }
+ foreach ($container->findTaggedServiceIds('data_collector') as $id => $attributes) {
+ $this->addCollector($container->get($id));
}
-
- $this->setCollectors(array_merge($coreCollectors, $userCollectors));
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml
index 8772a76254..dddfd1ff10 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml
@@ -6,29 +6,48 @@
Symfony\Bundle\FrameworkBundle\DataCollector\ConfigDataCollector
- Symfony\Bundle\FrameworkBundle\DataCollector\AppDataCollector
+ Symfony\Bundle\FrameworkBundle\DataCollector\RequestDataCollector
Symfony\Bundle\FrameworkBundle\DataCollector\TimerDataCollector
- Symfony\Component\HttpKernel\Profiler\DataCollector\MemoryDataCollector
+ Symfony\Component\HttpKernel\DataCollector\MemoryDataCollector
+ Symfony\Component\HttpKernel\DataCollector\LoggerDataCollector
+ Symfony\Component\HttpKernel\DataCollector\ExceptionDataCollector
+ Symfony\Component\HttpKernel\DataCollector\EventDataCollector
-
-
+
+
+
-
-
-
+
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/profiling.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/profiling.xml
index 04d193e5ed..c6bd63b390 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/profiling.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/profiling.xml
@@ -6,7 +6,7 @@
Symfony\Bundle\FrameworkBundle\Profiler
- Symfony\Component\HttpKernel\Profiler\ProfilerStorage
+ Symfony\Component\HttpKernel\Profiler\SQLiteProfilerStorage
%kernel.cache_dir%/profiler.db
86400
Symfony\Component\HttpKernel\Profiler\ProfilerListener
@@ -21,7 +21,6 @@
%profiler.storage.file%
- null
%profiler.storage.lifetime%
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/toolbar.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/toolbar.xml
deleted file mode 100644
index 29027edeff..0000000000
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/toolbar.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
- Symfony\Component\HttpKernel\Profiler\WebDebugToolbarListener
-
-
-
-
-
-
-
-
-
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/WebExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/WebExtensionTest.php
index ea6d2d1874..8e283cb7b8 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/WebExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/WebExtensionTest.php
@@ -31,10 +31,6 @@ class WebExtensionTest extends TestCase
$loader->configLoad(array('profiler' => true), $container);
$this->assertEquals('Symfony\\Bundle\\FrameworkBundle\\Profiler', $container->getParameter('profiler.class'), '->configLoad() loads the collectors.xml file if not already loaded');
- $this->assertFalse($container->getParameterBag()->has('debug.toolbar.class'), '->configLoad() does not load the toolbar.xml file');
-
- $loader->configLoad(array('toolbar' => true), $container);
- $this->assertEquals('Symfony\\Component\\HttpKernel\\Profiler\\WebDebugToolbarListener', $container->getParameter('debug.toolbar.class'), '->configLoad() loads the collectors.xml file if the toolbar option is given');
}
public function testTemplatingLoad()
diff --git a/src/Symfony/Bundle/ZendBundle/Logger/Logger.php b/src/Symfony/Bundle/ZendBundle/Logger/Logger.php
index f842addb1d..e6ac3242f7 100644
--- a/src/Symfony/Bundle/ZendBundle/Logger/Logger.php
+++ b/src/Symfony/Bundle/ZendBundle/Logger/Logger.php
@@ -4,6 +4,7 @@ namespace Symfony\Bundle\ZendBundle\Logger;
use Zend\Log\Logger as BaseLogger;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
/*
* This file is part of the Symfony framework.
@@ -21,6 +22,22 @@ use Symfony\Component\HttpKernel\Log\LoggerInterface;
*/
class Logger extends BaseLogger implements LoggerInterface
{
+ /**
+ * Returns a DebugLoggerInterface instance if one is registered with this logger.
+ *
+ * @return DebugLoggerInterface A DebugLoggerInterface instance or null if none is registered
+ */
+ public function getDebugLogger()
+ {
+ foreach ($this->_writers as $writer) {
+ if ($writer instanceof DebugLoggerInterface) {
+ return $writer;
+ }
+ }
+
+ return null;
+ }
+
public function emerg($message)
{
return parent::log($message, 0);
diff --git a/src/Symfony/Component/HttpKernel/Profiler/DataCollector/DataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php
similarity index 54%
rename from src/Symfony/Component/HttpKernel/Profiler/DataCollector/DataCollector.php
rename to src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php
index 808c07862a..b80533fb1f 100644
--- a/src/Symfony/Component/HttpKernel/Profiler/DataCollector/DataCollector.php
+++ b/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php
@@ -1,6 +1,6 @@
*/
-abstract class DataCollector implements DataCollectorInterface
+abstract class DataCollector implements DataCollectorInterface, \Serializable
{
- protected $profiler;
protected $data;
- public function getData()
+ public function serialize()
{
- return $this->data;
+ return serialize($this->data);
}
- public function setData($data)
+ public function unserialize($data)
{
- $this->data = $data;
- }
-
- public function setProfiler(Profiler $profiler)
- {
- $this->profiler = $profiler;
+ $this->data = unserialize($data);
}
}
diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DataCollectorInterface.php b/src/Symfony/Component/HttpKernel/DataCollector/DataCollectorInterface.php
new file mode 100644
index 0000000000..1888067dd5
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/DataCollector/DataCollectorInterface.php
@@ -0,0 +1,40 @@
+
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+/**
+ * DataCollectorInterface.
+ *
+ * @author Fabien Potencier
+ */
+interface DataCollectorInterface
+{
+ /**
+ * Collects data for the given Request and Response.
+ *
+ * @param Request $request A Request instance
+ * @param Response $response A Response instance
+ * @param \Exception $exception An Exception instance
+ */
+ function collect(Request $request, Response $response, \Exception $exception = null);
+
+ /**
+ * Returns the name of the collector.
+ *
+ * @return string The collector name
+ */
+ function getName();
+}
diff --git a/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php
new file mode 100644
index 0000000000..978131c94d
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php
@@ -0,0 +1,77 @@
+
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+/**
+ * EventDataCollector.
+ *
+ * @author Fabien Potencier
+ */
+class EventDataCollector extends DataCollector
+{
+ protected $dispatcher;
+
+ public function setEventDispatcher(EventDispatcher $dispatcher)
+ {
+ if ($dispatcher instanceof EventDispatcherTraceableInterface) {
+ $this->dispatcher = $dispatcher;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
+ {
+ $this->data = array(
+ 'called_events' => null !== $this->dispatcher ? $this->dispatcher->getCalledEvents() : array(),
+ 'not_called_events' => null !== $this->dispatcher ? $this->dispatcher->getNotCalledEvents() : array(),
+ );
+ }
+
+ /**
+ * Gets the called events.
+ *
+ * @return array An array of called events
+ *
+ * @see EventDispatcherTraceableInterface
+ */
+ public function getCalledEvents()
+ {
+ return $this->data['called_events'];
+ }
+
+ /**
+ * Gets the not called events.
+ *
+ * @return array An array of not called events
+ *
+ * @see EventDispatcherTraceableInterface
+ */
+ public function getNotCalledEvents()
+ {
+ return $this->data['not_called_events'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'events';
+ }
+}
diff --git a/src/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php
new file mode 100644
index 0000000000..446d7c6679
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php
@@ -0,0 +1,93 @@
+
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+/**
+ * ExceptionDataCollector.
+ *
+ * @author Fabien Potencier
+ */
+class ExceptionDataCollector extends DataCollector
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
+ {
+ if (null !== $exception) {
+ $this->data = array(
+ 'exception' => $exception,
+ );
+ }
+ }
+
+ /**
+ * Checks if the exception is not null.
+ *
+ * @return Boolean true if the exception is not null, false otherwise
+ */
+ public function hasException()
+ {
+ return isset($this->data['exception']);
+ }
+
+ /**
+ * Gets the exception.
+ *
+ * @return \Exception The exception
+ */
+ public function getException()
+ {
+ return $this->data['exception'];
+ }
+
+ /**
+ * Gets the exception message.
+ *
+ * @return string The exception message
+ */
+ public function getMessage()
+ {
+ return $this->data['exception']->getMessage();
+ }
+
+ /**
+ * Gets the exception code.
+ *
+ * @return integer The exception code
+ */
+ public function getCode()
+ {
+ return $this->data['exception']->getCode();
+ }
+
+ /**
+ * Gets the exception trace.
+ *
+ * @return array The exception trace
+ */
+ public function getTrace()
+ {
+ return $this->data['exception']->getTrace();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'exception';
+ }
+}
diff --git a/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php
new file mode 100644
index 0000000000..aed0b356d5
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php
@@ -0,0 +1,76 @@
+
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+/**
+ * LogDataCollector.
+ *
+ * @author Fabien Potencier
+ */
+class LoggerDataCollector extends DataCollector
+{
+ protected $logger;
+
+ public function __construct($logger = null)
+ {
+ if (null !== $logger) {
+ $this->logger = $logger->getDebugLogger();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
+ {
+ if (null !== $this->logger) {
+ $this->data = array(
+ 'error_count' => $this->logger->countErrors(),
+ 'logs' => $this->logger->getLogs(),
+ );
+ }
+ }
+
+ /**
+ * Gets the called events.
+ *
+ * @return array An array of called events
+ *
+ * @see EventDispatcherTraceableInterface
+ */
+ public function countErrors()
+ {
+ return isset($this->data['error_count']) ? $this->data['error_count'] : 0;
+ }
+
+ /**
+ * Gets the logs.
+ *
+ * @return array An array of logs
+ */
+ public function getLogs()
+ {
+ return isset($this->data['logs']) ? $this->data['logs'] : array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'logger';
+ }
+}
diff --git a/src/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php
new file mode 100644
index 0000000000..e8bfa81a05
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php
@@ -0,0 +1,51 @@
+
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+/**
+ * MemoryDataCollector.
+ *
+ * @author Fabien Potencier
+ */
+class MemoryDataCollector extends DataCollector
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
+ {
+ $this->data = array(
+ 'memory' => memory_get_peak_usage(true),
+ );
+ }
+
+ /**
+ * Gets the memory.
+ *
+ * @return integer The memory
+ */
+ public function getMemory()
+ {
+ return $this->data['memory'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'memory';
+ }
+}
diff --git a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php
new file mode 100644
index 0000000000..2d93970e4d
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php
@@ -0,0 +1,102 @@
+
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+/**
+ * RequestDataCollector.
+ *
+ * @author Fabien Potencier
+ */
+class RequestDataCollector extends DataCollector
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
+ {
+ $this->data = array(
+ 'format' => $request->getRequestFormat(),
+ 'content_type' => $response->headers->get('Content-Type') ? $response->headers->get('Content-Type') : 'text/html',
+ 'status_code' => $response->getStatusCode(),
+ 'request_query' => $request->query->all(),
+ 'request_request' => $request->request->all(),
+ 'request_headers' => $request->headers->all(),
+ 'request_server' => $request->server->all(),
+ 'request_cookies' => $request->cookies->all(),
+ 'response_headers' => $response->headers->all(),
+ 'session_attributes' => $request->getSession()->getAttributes(),
+ );
+ }
+
+ public function getRequestRequest()
+ {
+ return new ParameterBag($this->data['request_request']);
+ }
+
+ public function getRequestQuery()
+ {
+ return new ParameterBag($this->data['request_query']);
+ }
+
+ public function getRequestHeaders()
+ {
+ return new HeaderBag($this->data['request_headers']);
+ }
+
+ public function getRequestServer()
+ {
+ return new ParameterBag($this->data['request_server']);
+ }
+
+ public function getRequestCookies()
+ {
+ return new ParameterBag($this->data['request_cookies']);
+ }
+
+ public function getResponseHeaders()
+ {
+ return new HeaderBag($this->data['response_headers']);
+ }
+
+ public function getSessionAttributes()
+ {
+ return new HeaderBag($this->data['session_attributes']);
+ }
+
+ public function getContentType()
+ {
+ return $this->data['content_type'];
+ }
+
+ public function getStatusCode()
+ {
+ return $this->data['status_code'];
+ }
+
+ public function getFormat()
+ {
+ return $this->data['format'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'request';
+ }
+}
diff --git a/src/Symfony/Component/HttpKernel/Profiler/DataCollector/DataCollectorInterface.php b/src/Symfony/Component/HttpKernel/Profiler/DataCollector/DataCollectorInterface.php
deleted file mode 100644
index 8a0b91785f..0000000000
--- a/src/Symfony/Component/HttpKernel/Profiler/DataCollector/DataCollectorInterface.php
+++ /dev/null
@@ -1,34 +0,0 @@
-
- *
- * This source file is subject to the MIT license that is bundled
- * with this source code in the file LICENSE.
- */
-
-/**
- * DataCollectorInterface.
- *
- * @author Fabien Potencier
- */
-interface DataCollectorInterface
-{
- function getData();
-
- function setData($data);
-
- function getName();
-
- function collect();
-
- function setProfiler(Profiler $profiler);
-
- function getSummary();
-}
diff --git a/src/Symfony/Component/HttpKernel/Profiler/DataCollector/MemoryDataCollector.php b/src/Symfony/Component/HttpKernel/Profiler/DataCollector/MemoryDataCollector.php
deleted file mode 100644
index b11ccf0226..0000000000
--- a/src/Symfony/Component/HttpKernel/Profiler/DataCollector/MemoryDataCollector.php
+++ /dev/null
@@ -1,44 +0,0 @@
-
- *
- * This source file is subject to the MIT license that is bundled
- * with this source code in the file LICENSE.
- */
-
-/**
- * MemoryDataCollector.
- *
- * @author Fabien Potencier
- */
-class MemoryDataCollector extends DataCollector
-{
- public function collect()
- {
- $this->data = array(
- 'memory' => memory_get_peak_usage(true),
- );
- }
-
- public function getMemory()
- {
- return $this->data['memory'];
- }
-
- public function getSummary()
- {
- return sprintf('
- %.0f KB
- ', $this->data['memory'] / 1024);
- }
-
- public function getName()
- {
- return 'memory';
- }
-}
diff --git a/src/Symfony/Component/HttpKernel/Profiler/Profiler.php b/src/Symfony/Component/HttpKernel/Profiler/Profiler.php
index 9e4f98e52d..35b950af6f 100644
--- a/src/Symfony/Component/HttpKernel/Profiler/Profiler.php
+++ b/src/Symfony/Component/HttpKernel/Profiler/Profiler.php
@@ -2,9 +2,10 @@
namespace Symfony\Component\HttpKernel\Profiler;
+use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\HttpKernel\Profiler\ProfilerStorage;
-use Symfony\Component\HttpKernel\Profiler\DataCollector\DataCollectorInterface;
+use Symfony\Component\HttpKernel\Profiler\ProfilerStorageInterface;
+use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
/*
@@ -21,134 +22,195 @@ use Symfony\Component\HttpKernel\Log\LoggerInterface;
*
* @author Fabien Potencier
*/
-class Profiler implements \ArrayAccess
+class Profiler
{
- protected $profilerStorage;
+ protected $storage;
protected $collectors;
- protected $response;
protected $logger;
protected $enabled;
+ protected $token;
+ protected $data;
+ protected $ip;
+ protected $url;
+ protected $time;
+ protected $empty;
- public function __construct(ProfilerStorage $profilerStorage, LoggerInterface $logger = null)
+ /**
+ * Constructor.
+ *
+ * @param ProfilerStorageInterface $storage A ProfilerStorageInterface instance
+ * @param LoggerInterface $logger A LoggerInterface instance
+ */
+ public function __construct(ProfilerStorageInterface $storage, LoggerInterface $logger = null)
{
- $this->profilerStorage = $profilerStorage;
+ $this->storage = $storage;
$this->logger = $logger;
$this->collectors = array();
$this->enabled = true;
+ $this->empty = true;
}
/**
- * Clones the Profiler instance.
+ * Disables the profiler.
*/
- public function __clone()
- {
- $this->profilerStorage = clone $this->profilerStorage;
- }
-
- /**
- * Returns a new Profiler for the given Response.
- *
- * @param Response $response A Response instance
- *
- * @return Profiler A new Profiler instance
- */
- public function load(Response $response)
- {
- if (!$token = $response->headers->get('X-Debug-Token')) {
- return null;
- }
-
- return $this->getProfilerForToken($token);
- }
-
- /**
- * Returns a new Profiler for the given token.
- *
- * @param string $token A token
- *
- * @return Profiler A new Profiler instance
- */
- public function getProfilerForToken($token)
- {
- $profiler = clone $this;
- $profiler->profilerStorage->setToken($token);
- $profiler->loadCollectorData();
-
- return $profiler;
- }
-
public function disable()
{
$this->enabled = false;
}
/**
- * Collects data for the given Response.
+ * Loads a Profiler for the given Response.
*
* @param Response $response A Response instance
+ *
+ * @return Profiler A new Profiler instance
*/
- public function collect(Response $response)
+ public function loadFromResponse(Response $response)
+ {
+ if (!$token = $response->headers->get('X-Debug-Token')) {
+ return null;
+ }
+
+ return $this->loadFromToken($token);
+ }
+
+ /**
+ * Loads a Profiler for the given token.
+ *
+ * @param string $token A token
+ *
+ * @return Profiler A new Profiler instance
+ */
+ public function loadFromToken($token)
+ {
+ $profiler = new self($this->storage, $this->logger);
+ $profiler->setToken($token);
+
+ return $profiler;
+ }
+
+ /**
+ * Sets the token.
+ *
+ * @param string $token The token
+ */
+ public function setToken($token)
+ {
+ $this->token = $token;
+
+ if (false !== $items = $this->storage->read($token)) {
+ list($collectors, $this->ip, $this->url, $this->time) = $items;
+ $this->setCollectors($collectors);
+
+ $this->empty = false;
+ } else {
+ $this->empty = true;
+ }
+ }
+
+ /**
+ * Gets the token.
+ *
+ * @return string The token
+ */
+ public function getToken()
+ {
+ if (null === $this->token) {
+ $this->token = uniqid();
+ }
+
+ return $this->token;
+ }
+
+ /**
+ * Checks if the profiler is empty.
+ *
+ * @return Boolean Whether the profiler is empty or not
+ */
+ public function isEmpty()
+ {
+ return $this->empty;
+ }
+
+ /**
+ * Returns the IP.
+ *
+ * @return string The IP
+ */
+ public function getIp()
+ {
+ return $this->ip;
+ }
+
+ /**
+ * Returns the URL.
+ *
+ * @return string The URL
+ */
+ public function getUrl()
+ {
+ return $this->url;
+ }
+
+ /**
+ * Returns the time.
+ *
+ * @return string The time
+ */
+ public function getTime()
+ {
+ return $this->time;
+ }
+
+ /**
+ * Finds profiler tokens for the given criteria.
+ *
+ * @param string $ip The IP
+ * @param string $url The URL
+ * @param string $limit The maximum number of tokens to return
+ *
+ * @return array An array of tokens
+ */
+ public function find($ip, $url, $limit)
+ {
+ return $this->storage->find($ip, $url, $limit);
+ }
+
+ /**
+ * Collects data for the given Response.
+ *
+ * @param Request $request A Request instance
+ * @param Response $response A Response instance
+ * @param \Exception $exception An exception instance if the request threw one
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
{
if (false === $this->enabled) {
return;
}
- $this->response = $response;
- $this->response->headers->set('X-Debug-Token', $this->profilerStorage->getToken());
+ $response = $response;
+ $response->headers->set('X-Debug-Token', $this->getToken());
- $data = array();
- foreach ($this->collectors as $name => $collector) {
- $collector->collect();
-
- $data[$name] = $collector->getData();
+ foreach ($this->collectors as $collector) {
+ $collector->collect($request, $response, $exception);
}
+ $this->ip = $request->server->get('REMOTE_ADDR');
+ $this->url = $request->getUri();
+ $this->time = time();
+
try {
- $this->profilerStorage->write($data);
- $this->profilerStorage->purge();
+ $this->storage->write($this->token, $this->collectors, $this->ip, $this->url, $this->time);
+
+ $this->empty = false;
} catch (\Exception $e) {
if (null !== $this->logger) {
- $this->logger->err('Unable to store the profiler information.');
+ $this->logger->err(sprintf('Unable to store the profiler information (%s).', $e->getMessage()));
}
}
}
- /**
- * Loads the data stored in the storage for all collectors.
- */
- public function loadCollectorData()
- {
- try {
- foreach ($this->collectors as $name => $collector) {
- $collector->setData($this->profilerStorage->getData($name));
- }
- } catch (\Exception $e) {
- if (null !== $this->logger) {
- $this->logger->err('Unable to read the profiler information.');
- }
- }
- }
-
- /**
- * Gets the profiler storage.
- *
- * @return ProfilerStorage A ProfilerStorage instance
- */
- public function getProfilerStorage()
- {
- return $this->profilerStorage;
- }
-
- /**
- * Gets the Response.
- *
- * @return Response A Response instance
- */
- public function getResponse()
- {
- return $this->response;
- }
-
/**
* Gets the Collectors associated with this profiler.
*
@@ -209,53 +271,4 @@ class Profiler implements \ArrayAccess
return $this->collectors[$name];
}
-
- /**
- * Returns true if the named collector exists.
- *
- * @param string $name The collector name
- *
- * @return Boolean true if the collector exists, false otherwise
- */
- public function offsetExists($name)
- {
- return $this->hasCollector($name);
- }
-
- /**
- * Gets a collector.
- *
- * @param string $name The collector name
- *
- * @throws \InvalidArgumentException if the collector does not exist
- */
- public function offsetGet($name)
- {
- return $this->getCollector($name);
- }
-
- /**
- * Unimplemented.
- *
- * @param string $name The collector name
- * @param string|array $value The collector
- *
- * @throws \LogicException
- */
- public function offsetSet($name, $value)
- {
- throw new \LogicException('A Collector cannot be set.');
- }
-
- /**
- * Unimplemented.
- *
- * @param string $name The collector name
- *
- * @throws \LogicException
- */
- public function offsetUnset($name)
- {
- throw new \LogicException('A Collector cannot be removed.');
- }
}
diff --git a/src/Symfony/Component/HttpKernel/Profiler/ProfilerListener.php b/src/Symfony/Component/HttpKernel/Profiler/ProfilerListener.php
index 850d0563ca..6f61e215ee 100644
--- a/src/Symfony/Component/HttpKernel/Profiler/ProfilerListener.php
+++ b/src/Symfony/Component/HttpKernel/Profiler/ProfilerListener.php
@@ -24,30 +24,61 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
class ProfilerListener
{
protected $profiler;
+ protected $exception;
+ /**
+ * Constructor.
+ *
+ * @param Profiler $profiler A Profiler instance
+ */
public function __construct(Profiler $profiler)
{
$this->profiler = $profiler;
}
/**
- * Registers a core.response listener.
+ * Registers a core.response and core.exception listeners.
*
* @param EventDispatcher $dispatcher An EventDispatcher instance
* @param integer $priority The priority
*/
public function register(EventDispatcher $dispatcher, $priority = 0)
{
- $dispatcher->connect('core.response', array($this, 'handle'), $priority);
+ $dispatcher->connect('core.exception', array($this, 'handleException'), $priority);
+ $dispatcher->connect('core.response', array($this, 'handleResponse'), $priority);
}
- public function handle(Event $event, Response $response)
+ /**
+ * Handles the core.exception event.
+ *
+ * @param Event $event An Event instance
+ */
+ public function handleException(Event $event)
+ {
+ if (HttpKernelInterface::MASTER_REQUEST !== $event->getParameter('request_type')) {
+ return false;
+ }
+
+ $this->exception = $event->getParameter('exception');
+
+ return false;
+ }
+
+ /**
+ * Handles the core.response event.
+ *
+ * @param Event $event An Event instance
+ *
+ * @return Response $response A Response instance
+ */
+ public function handleResponse(Event $event, Response $response)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getParameter('request_type')) {
return $response;
}
- $this->profiler->collect($response);
+ $this->profiler->collect($event->getParameter('request'), $response, $this->exception);
+ $this->exception = null;
return $response;
}
diff --git a/src/Symfony/Component/HttpKernel/Profiler/ProfilerStorageInterface.php b/src/Symfony/Component/HttpKernel/Profiler/ProfilerStorageInterface.php
new file mode 100644
index 0000000000..ea08094297
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/Profiler/ProfilerStorageInterface.php
@@ -0,0 +1,55 @@
+
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+/**
+ * ProfilerStorageInterface.
+ *
+ * @author Fabien Potencier
+ */
+interface ProfilerStorageInterface
+{
+ /**
+ * Finds profiler tokens for the given criteria.
+ *
+ * @param string $ip The IP
+ * @param string $url The URL
+ * @param string $limit The maximum number of tokens to return
+ *
+ * @return array An array of tokens
+ */
+ function find($ip, $url, $limit);
+
+ /**
+ * Reads data associated with the given token.
+ *
+ * The method returns false if the token does not exists in the storage.
+ *
+ * @param string $token A token
+ *
+ * @return DataCollectorInterface[] An array of DataCollectorInterface instance
+ */
+ function read($token);
+
+ /**
+ * Reads data associated with the given token.
+ *
+ * @param string $token A token
+ * @param DataCollectorInterface[] $collectors An array of DataCollectorInterface instances
+ * @param string $ip An IP
+ * @param string $url An URL
+ * @param integer $time The time of the data
+ */
+ function write($token, $collectors, $ip, $url, $time);
+}
diff --git a/src/Symfony/Component/HttpKernel/Profiler/ProfilerStorage.php b/src/Symfony/Component/HttpKernel/Profiler/SQLiteProfilerStorage.php
similarity index 58%
rename from src/Symfony/Component/HttpKernel/Profiler/ProfilerStorage.php
rename to src/Symfony/Component/HttpKernel/Profiler/SQLiteProfilerStorage.php
index 943f254cf9..e9871fe384 100644
--- a/src/Symfony/Component/HttpKernel/Profiler/ProfilerStorage.php
+++ b/src/Symfony/Component/HttpKernel/Profiler/SQLiteProfilerStorage.php
@@ -2,6 +2,8 @@
namespace Symfony\Component\HttpKernel\Profiler;
+use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface;
+
/*
* This file is part of the Symfony framework.
*
@@ -12,77 +14,99 @@ namespace Symfony\Component\HttpKernel\Profiler;
*/
/**
- * ProfilerStorage.
+ * SQLiteProfilerStorage stores profiling information in a SQLite database.
*
* @author Fabien Potencier
*/
-class ProfilerStorage
+class SQLiteProfilerStorage implements ProfilerStorageInterface
{
- protected $token;
- protected $data;
protected $store;
protected $lifetime;
- public function __construct($store, $token = null, $lifetime = 86400)
+ /**
+ * Constructor.
+ *
+ * @param string $store The path to the SQLite DB
+ * @param integer $lifetime The lifetime to use for the purge
+ */
+ public function __construct($store, $lifetime = 86400)
{
$this->store = $store;
- $this->token = null === $token ? uniqid() : $token;
- $this->data = null;
$this->lifetime = (int) $lifetime;
}
- public function hasData()
+ /**
+ * {@inheritdoc}
+ */
+ public function find($ip, $url, $limit)
{
- return null !== $this->data;
- }
+ $criteria = array();
- public function getData($name = null)
- {
- if (null === $this->data) {
- $this->data = $this->read();
+ if ($ip = preg_replace('/[^\d\.]/', '', $ip)) {
+ $criteria[] = ' ip LIKE "%'.$ip.'%"';
}
- if (null === $name) {
- return $this->data;
+ if ($url) {
+ $criteria[] = ' url LIKE "%'.$url.'%"';
}
- return isset($this->data[$name]) ? $this->data[$name] : array();
+ $criteria = $criteria ? 'WHERE '.implode(' AND ', $criteria) : '';
+
+ $db = $this->initDb();
+ $tokens = $this->fetch($db, 'SELECT token, ip, url, time FROM data '.$criteria.' ORDER BY time DESC LIMIT '.((integer) $limit));
+ $this->close($db);
+
+ return $tokens;
}
- public function setToken($token)
- {
- $this->token = $token;
- $this->data = null;
- }
-
- public function getToken()
- {
- return $this->token;
- }
-
- protected function read()
+ /**
+ * {@inheritdoc}
+ */
+ public function read($token)
{
$db = $this->initDb();
- $args = array(':token' => $this->token);
- $data = $this->fetch($db, 'SELECT data FROM data WHERE token = :token ORDER BY created_at DESC LIMIT 1', $args);
+ $args = array(':token' => $token);
+ $data = $this->fetch($db, 'SELECT data, ip, url, time FROM data WHERE token = :token ORDER BY time DESC LIMIT 1', $args);
$this->close($db);
if (isset($data[0]['data'])) {
- return unserialize(pack('H*', $data[0]['data']));
+ return array(unserialize(pack('H*', $data[0]['data'])), $data[0]['ip'], $data[0]['url'], $data[0]['time']);
+ } else {
+ return false;
}
}
- public function write($data)
+ /**
+ * {@inheritdoc}
+ */
+ public function write($token, $collectors, $ip, $url, $time)
{
- $unpack = unpack('H*', serialize($data));
+ $unpack = unpack('H*', serialize($collectors));
$data = $unpack[1];
$db = $this->initDb();
$args = array(
- ':token' => $this->token,
- ':data' => (string) $data,
- ':time' => time()
+ ':token' => $token,
+ ':data' => $data,
+ ':ip' => $ip,
+ ':url' => $url,
+ ':time' => $time,
);
- $this->exec($db, 'INSERT INTO data (token, data, created_at) VALUES (:token, :data, :time)', $args);
+ $this->exec($db, 'INSERT INTO data (token, data, ip, url, time) VALUES (:token, :data, :ip, :url, :time)', $args);
+ $this->purge();
+ $this->close($db);
+ }
+
+ public function purge($all = false)
+ {
+ $db = $this->initDb();
+
+ if (true === $all) {
+ $this->exec($db, 'DELETE FROM data');
+ } else {
+ $args = array(':time' => time() - $this->lifetime);
+ $this->exec($db, 'DELETE FROM data WHERE time < :time', $args);
+ }
+
$this->close($db);
}
@@ -99,8 +123,8 @@ class ProfilerStorage
throw new \RuntimeException('You need to enable either the SQLite or PDO_SQLite extension for the profiler to run properly.');
}
- $db->exec('CREATE TABLE IF NOT EXISTS data (token STRING, data STRING, created_at INTEGER)');
- $db->exec('CREATE INDEX IF NOT EXISTS data_data ON data (created_at)');
+ $db->exec('CREATE TABLE IF NOT EXISTS data (token STRING, data STRING, ip STRING, url STRING, time INTEGER)');
+ $db->exec('CREATE INDEX IF NOT EXISTS data_data ON data (time)');
return $db;
}
@@ -155,12 +179,4 @@ class ProfilerStorage
$db->close();
}
}
-
- public function purge()
- {
- $db = $this->initDb();
- $args = array(':time' => time() - $this->lifetime);
- $this->exec($db, 'DELETE FROM data WHERE created_at < :time', $args);
- $this->close($db);
- }
}
diff --git a/src/Symfony/Component/HttpKernel/Profiler/WebDebugToolbarListener.php b/src/Symfony/Component/HttpKernel/Profiler/WebDebugToolbarListener.php
deleted file mode 100644
index a94e008735..0000000000
--- a/src/Symfony/Component/HttpKernel/Profiler/WebDebugToolbarListener.php
+++ /dev/null
@@ -1,102 +0,0 @@
-
- *
- * This source file is subject to the MIT license that is bundled
- * with this source code in the file LICENSE.
- */
-
-/**
- * WebDebugToolbarListener injects the Web Debug Toolbar.
- *
- * @author Fabien Potencier
- */
-class WebDebugToolbarListener
-{
- protected $profiler;
-
- public function __construct(Profiler $profiler)
- {
- $this->profiler = $profiler;
- }
-
- /**
- * Registers a core.response listener.
- *
- * @param EventDispatcher $dispatcher An EventDispatcher instance
- * @param integer $priority The priority
- */
- public function register(EventDispatcher $dispatcher, $priority = 0)
- {
- $dispatcher->connect('core.response', array($this, 'handle'), $priority);
- }
-
- public function handle(Event $event, Response $response)
- {
- if (HttpKernelInterface::MASTER_REQUEST !== $event->getParameter('request_type')) {
- return $response;
- }
-
- $request = $event->getParameter('request');
- if (!$response->headers->has('X-Debug-Token')
- || '3' === substr($response->getStatusCode(), 0, 1)
- || ($response->headers->has('Content-Type') && false === strpos($response->headers->get('Content-Type'), 'html'))
- || 'html' !== $request->getRequestFormat()
- || $request->isXmlHttpRequest()
- ) {
- return $response;
- }
-
- $response->setContent($this->injectToolbar($request, $response));
-
- return $response;
- }
-
- /**
- * Injects the web debug toolbar into a given HTML string.
- *
- * @param string $content The HTML content
- *
- * @return Response A Response instance
- */
- protected function injectToolbar(Request $request, Response $response)
- {
- $data = '';
- foreach ($this->profiler->getCollectors() as $name => $collector) {
- $data .= $collector->getSummary();
- }
-
- $position = false === strpos($request->headers->get('user-agent'), 'Mobile') ? 'fixed' : 'absolute';
-
- $toolbar = <<
-
-
- $data
-
-
-
-EOF;
-
- $toolbar = "\n".str_replace("\n", '', $toolbar)."\n";
- $count = 0;
- $content = str_ireplace('