refactored Profiler and DataCollector classes (the WDT has been removed and will be re-added in the upcoming WebProfilerBundle)
This commit is contained in:
parent
eb66e0dc00
commit
72db4c7342
@ -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,22 +23,22 @@ 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,
|
||||
'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('<img style="margin-left: 10px; vertical-align: middle" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAKlJREFUeNrsk0EOgyAQRT9KiLog7D0Ql+B4HsULeAHXQFwaiCGBCm1Nmi4a69a/IDNk5g+8ZEhKCcMwYFfCORGlFOgrSVJKNE0DxhgofV6HELBtG5xz8N6XuK7rUjOOYx5I3gbQWoNzDiEEuq5DjLE0LcsCYwystVjXFW3bou/74xkVLuqywfGFaZp+T6uqwmGe52+DPyB+GtwQb4h5q3aI6SREko+HAAMADJ+V5b1xqucAAAAASUVORK5CYII=" />
|
||||
<span style="color: %s">%d</span>
|
||||
', $queriesColor, $queries);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'db';
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
<service id="doctrine.data_collector" class="%doctrine.data_collector.class%">
|
||||
<tag name="data_collector" />
|
||||
<argument type="service" id="service_container" />
|
||||
<argument type="service" id="doctrine.dbal.logger" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
@ -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('<img style="margin-left: 10px; vertical-align: middle" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAeJJREFUeNqM009r1EAUAPD3kkm22bapthSlq/EPUg9FUMSLoCAVvPUm4smr4Ico+BW89SCe6tVDj2oVLwVRS6HqTcUqwe7W7SbZbGbmzTiTvei2ML6QDAwzP968l0GtNfwdS/eu1KMSBHEytbhf9HbLdrGFiPX8i9VP/6z3YCTKvITidwETyeTN5NbZNTzFHhVZGWc/MsjTfHT5QUBKCcFMOD97be6JRhgLj0fXxy9PrXi+h6jRDfCcQ3xx+iE0/ZbgAogrCE5Gd8JzzftaKjfgHw0uBUm0JCoOpAmUUqBIgwEe4LgfO4HwdLSoQoykJJBEYGuspQaMgwU227jhBHQDFwjMZmW+Wg0BPVyJR9hVJwAT3rQkCVJbxpzZ1M0ew9ZPVWrG3YVMDKTZSDYDZY+gzYuWAs2VdHfhW3/bFq/OoEYMYB8zUkd8dgMf8zWxV+XkKRA1YNL3EGhf9uSX/ksnQCl/X7zqPCZmAVkDyDzgH3qrtCe2nACGCMV6Z7n3pv2chT6wgEG1nW1UG91lDP7jT0TfA3NxurtPv96dfOu/Pp/Oves++36buPxl2zoabHSiGlTDS9Uv24PNbOXMheRE61hrpxE14LA4APjMr8eoOQY/03RTaLVTDkrggh8K/BFgAGj/AWtED/mBAAAAAElFTkSuQmCC" />
|
||||
<span style="color: %s">%d</span>
|
||||
', $color, $this->data['nb_queries']);
|
||||
return $this->data['nb_queries'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'mongodb';
|
||||
|
@ -1,64 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpKernel\Profiler\DataCollector\DataCollector;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* AppDataCollector.
|
||||
*
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
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') : '<span style="color: #a33">NONE</span>',
|
||||
'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('<img style="margin-left: 10px; vertical-align: middle" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAABKElEQVR42sSTPa6CQBSFv3lRrCRYACvQxMLCBhsTK5fAGtiAPaGfDbgGNmBCS0PFAqhsoSGSWE1yrTDvxd+E4t1qkrnn3HPPnFEiwpD6YWCNPjUcj0fquhYAz/MUQBRFzwniOH6cMBrJfD4HoKoq6UleKkiS5H7WWstut+N0OmHbNrZt92rURw+01rJerzmfzyyXSy6XC77vf2ei1lpWqxVN02CMwRhDEARUVcXHFfrJbdsyHo8BcByHsiwxxqjfBj4omE6nstlsuF6vWJaFZVl4nkdZlhwOB/U2B1mWSRiGFEWB67pMJhNc16Uoipfgpx6EYUie58xmM/I8fwsGUH2UsywTgMViAUCapnRdp9498x+COI5lu93eL/b7vfomyurfP9NggtsAfaVzbTWryOIAAAAASUVORK5CYII=" />
|
||||
%s<span style="margin: 0; padding: 0; color: #aaa">/</span>%s<span style="margin: 0; padding: 0; color: #aaa">/</span><span style="color: %s">%s</span><span style="margin: 0; padding: 0; color: #aaa">/</span>%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';
|
||||
}
|
||||
}
|
@ -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('<img style="vertical-align: middle" alt="Symfony" src="data:image/png;base64,R0lGODlhOwARAMQdAIZ1X9rVz0owD/Lx78K6r2JML3pnT+bj37asn6qej1Y+H+jk4JKDb0oxEJOEcId2YGJMMPTy8KufkLetoJ+RgNvW0M7Iv56Rf25aP8/JwG5aQP///z4jAP///wAAAAAAACH5BAEAAB0ALAAAAAA7ABEAAAX/YLc8WmmeaKqu7OosYsPNdG3fuCDgfM81C4dvyAsEiEgORZNMGjaI5rBEEzAugBmWBshiOICtAbu7QL+Ky8UwExQw6i8HTqPPqJzCYMMPCDYWNBYWBRsHfIaIgWYbWIiAHAF7iAkcZjSXd0wchwQYCBZ/gTODHAQbngEbARincBsYGAMDAK2NAKsGBodpG5i+mjMGewg7HJCki7AcT18YG1e+DBtZMweBjTO4r780eHmqAQXHoxylZs7Lz2q+6IIDxxczz6/GmRzfBQKnAxgWG+MiKUuXjh0zVDMKEYg3DxYueRwSAMO3SSKBfwMEPBtA4NDAOeoaZQp3alk2kBgEVJDk421TgX+AAu5SZClkwUwCEPA5wIYhSg4KYO5pieRZFClIrcELNkTAHgVJkUqEyOGBBCRdoiItUInGhAgQtIpNoqGD2Qxo06pdy7at27dvK5gNAQA7" />
|
||||
%s
|
||||
<img style="margin-left: 10px; vertical-align: middle" alt="PHP" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAARCAYAAAC8XK78AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABfdJREFUeNqMVWlsFGUYfubas+y2hZZlWxahFlBKQbSg/ECUhCgQIsqRcMQfgHJoJAgRMcQ/KP5CJHgkCMQoERLBCyGIUGsIQlIOW44etGV7sle7x8zszOzMrO+MBU1AwiTfzux3vO/zPu/zvh+Tz+fxoKcr3DeMYZgpkqROSibl8fGENDqZzAbSolIoy5o7m81BVjRFltVkRlIihq50cIzSxDJKA/LKpb17P4g8yD5zPwB1Zy55fT7PC3nwC/qT6qxIVArQQDKlIqebMM08fD4fWJZFKpWiE3ds5GHZM3SNhgQ9l4xp2WitnI0dzcqpE98dPZR+IICvDpzkCgu9yw2D3xhJaNW3IzLkrA7dMMFxDDlkyAeDggIB8eh5yFIGleNmIzGgwVoaNAnG/mZtQKapQZGjGOhvborevr4rnogeqK+v1+4BsOvj7ys8HvfulMjOifdr0HUGgiDYxigFdmSmadjvEcN5bN0yF8FgCKvX7iMWcjRv2MN2zQr2Gdzlhc6bOaQG2nD92vHTbTevvNnd3XvDWuOtn23vH3zc4/L+FEsaFZqmw+EQUOARkcmEYZgmWcjTnAvFRWXIKl7097dBU3UMKwmQ0SZYW/yFpZQePznXIIsd0HI6HTPpP4fColKwXAmNx1AzLTBLVff/Smy+RKm8yG/ctH+ow+k6lJaECkotbWLg8bhwpf4gjh37Fh63CzzPQhRllJQGsWbdDnRHe2HtbfirHu1tjVCyKpwuL5YuexvFwwL4fM8Ge93tckJRFQqAx7z5y1A1aQkyeR9mPLe2vK+v+zCxNIOrfmLuZqejcAnD8oO5Y+B0Mjh39jD6+vqwddtneKpmAcrKylH3+0moSowMM2houIK167bi2ZmvIhAI4Pz5OmLIS1qgs+f+wKJFqzB/wVuYUPU0Wpov03otpk9/nhgtgMPpREnJI8VXG8+YrGFyizlOuKvkvI3cRHt7CyoqKsELY5CRSlA9+UVixo1wuAPNzY1wu50YNfoZ6OYolA6vtM8O8RWhP9Frf4+pnIpUZiiGlkxFdfUUkHwgSSkKkqXqUBEYUYnQqInzqZLYEP4jGI6YSCV7aaQIwAQixEVo/ejpvgpZzmLcuPHo7OxEKDQGuRxPoBhiqtU+GwyOQrjzJoqK/CgtrYCLUuAQJGLrIgq8btJMCIah20GyHEe6GR7kYeYiNDHkTvRerwtdt27afGSzIiJ95+yoThz/Bn6/HzNnzkZt7RlUTayhSiENMzlEbrfbAEaOLEdzUxPt86Gj7U8SrIZffjyBnp4eLF+xhnRRRLtEu0KsihIziRiv58QfdF3ZJAhuW7Uc2YxFw7bBCxfqcPnyWWhaDmPHVmHh4g10KG6norx8LIUhEGNZpFNRWyNW7atqFtGojP37thNAncAU47XXN+PRsXNAXdQmm+cdiMfC6Aw3niR3uU/ETGRxYVEoZOXH0FVC3GZv3PLuHqJqKPUDnvqPhxihJuQrxpb3viZnbqTSadIChwWvbEXBEB+artcRWA3Ll6/D5CfnERiVUuBFVhUGneepoTlIDwZOn9obVRRxJ7v/y3e6c1p6aTrVEzOpoCk43LrVRHQG4S4YjZTopk7HUe0rBEAiYQHpjOXctA1ad8FAygFRctpaoO6MspET0D/goj1OxBI5KmHJpt3h8JBuVBz7eWe6teXCCmpqN+92wpWrPqrheM+n5SPLa6KRZhLSMLB8iKLQ8TCPIHCUgG4kElGMKJsE64qwwFiOraitd2e4AbW/7Wvo6rq2nvyevecuWLlqh4/q4A2fP7De4fQHwXB2J/tHoP9eOPd7rFmeHPG8QGlQwJB31io5Smk81obGhlPRS/Unv9D13G6ylXjgbbhy5YdBhmVe5gT3QoejYKogeN08iZRlLNWzg31+cNyp4HzeFrE1DEOBJEapejqUrq7Gi92dN47E47eP0JXd+VDX8V0gq7eTr/w46m7TSKDVLMtXspwQYhlq7GC8Fg6TLiCTapucypomxRR5oEsUE62ZTH9jOp24kJGkptaWVuP/fPwtwAAItQDxq4a1ggAAAABJRU5ErkJggg==" />
|
||||
%s<span style="margin: 0; padding: 0; color: #aaa">/</span><span style="color: %s">xdebug</span><span style="margin: 0; padding: 0; color: #aaa">/</span><span style="color: %s">accel</span>
|
||||
<img style="margin-left: 10px; vertical-align: middle" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAATtJREFUeNqcU0Gqg0AMjZ/eQbEH0IUewIV4BXEjeD9dCvYGUlB056IU3Rf0Ci6c/hc6g/rr7+cHwkySl8xLZkZL05QORKz22jtAkiR0OkigIAjofD7T4/GgsizFLlcV/JLJAKOi4zjsME1zs8KPOHDrw7RXCwLBv0qWZZyLHMmAuq4jIcRHBW4taga3241c1+U9+r5erwrk+76kzri1gIEAII5jdcorWZMKW8aAA17OgRkYhkHLsvza9zoO/OYWQHmeZwYdFZIxKPDrGWhVVTGdKIrY6Xke1XWtrgo26EPyPN+8BTVEy7LU6bquUxiGPxigCHB939P+IZFt2x+vUOL2t8DSNA2D7vc7FUWxSYQNP/bAvXsH2jiO4nK5qMC3za1M08T2MAys+79wOvpxbdt+/I0ckL39V54CDAChFuDJX64gowAAAABJRU5ErkJggg==" />
|
||||
%s<span style="margin: 0; padding: 0; color: #aaa">/</span>%s<span style="margin: 0; padding: 0; color: #aaa">/</span>%s<span style="margin: 0; padding: 0; color: #aaa">/</span><a style="color: #000" href="#%s">%s</a>
|
||||
', $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';
|
||||
|
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\DataCollector\RequestDataCollector as BaseRequestDataCollector;
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* RequestDataCollector.
|
||||
*
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
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'];
|
||||
}
|
||||
}
|
@ -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('<img style="margin-left: 10px; vertical-align: middle" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAABSElEQVR42pyTwZHCMAxFXxxKUAXuIA3gFnJxERxohAt9QAM5EhpwB6rAJdjJXmKThIWdWc1oJvbo/y8p383tdmMfMcYEtKurLCKHfZ33nsMOmAFjraXrunofQmhVdQYmEVkTvwhijPMaOI5jLXLO0XUdIQSjqrOINBuCGGMu4AL03leC+/1eiQBUNZdOzFJjCth7X8GXy6WSee8Zx7F0WHCYGGOy1la1aZpqrs/zPNcaa21ZNAZoi3rf9+ScawL1O6VE3/frLtrNEgFSSm+/9Hq9AnA+n/ktvhKcTqev5GWEHELAOccwDKSUPuYwDDjnCCEAZAAjIgdV3Sh9yhKqSnFmGWEKIRjnHI/HA4Dj8VgBz+ez+mBRnzY7EJFi1WqWvRMXSxf19m2JItKoalZVY62toDXw61sonSwzJlX98zUCNGuH/Sd+BgBGROvHb4RJ6gAAAABJRU5ErkJggg==" />
|
||||
%.0f ms
|
||||
', $this->data['time'] * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'timer';
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
foreach ($container->findTaggedServiceIds('data_collector') as $id => $attributes) {
|
||||
$this->addCollector($container->get($id));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
$this->setCollectors(array_merge($coreCollectors, $userCollectors));
|
||||
}
|
||||
}
|
||||
|
@ -6,29 +6,48 @@
|
||||
|
||||
<parameters>
|
||||
<parameter key="data_collector.config.class">Symfony\Bundle\FrameworkBundle\DataCollector\ConfigDataCollector</parameter>
|
||||
<parameter key="data_collector.app.class">Symfony\Bundle\FrameworkBundle\DataCollector\AppDataCollector</parameter>
|
||||
<parameter key="data_collector.request.class">Symfony\Bundle\FrameworkBundle\DataCollector\RequestDataCollector</parameter>
|
||||
<parameter key="data_collector.timer.class">Symfony\Bundle\FrameworkBundle\DataCollector\TimerDataCollector</parameter>
|
||||
<parameter key="data_collector.memory.class">Symfony\Component\HttpKernel\Profiler\DataCollector\MemoryDataCollector</parameter>
|
||||
<parameter key="data_collector.memory.class">Symfony\Component\HttpKernel\DataCollector\MemoryDataCollector</parameter>
|
||||
<parameter key="data_collector.logger.class">Symfony\Component\HttpKernel\DataCollector\LoggerDataCollector</parameter>
|
||||
<parameter key="data_collector.exception.class">Symfony\Component\HttpKernel\DataCollector\ExceptionDataCollector</parameter>
|
||||
<parameter key="data_collector.events.class">Symfony\Component\HttpKernel\DataCollector\EventDataCollector</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="data_collector.config" class="%data_collector.config.class%">
|
||||
<tag name="data_collector" core="true" />
|
||||
<argument type="service" id="service_container" />
|
||||
<tag name="data_collector" />
|
||||
<argument type="service" id="kernel" />
|
||||
<argument type="service" id="router" on-invalid="ignore" />
|
||||
</service>
|
||||
|
||||
<service id="data_collector.app" class="%data_collector.app.class%">
|
||||
<tag name="data_collector" core="true" />
|
||||
<argument type="service" id="service_container" />
|
||||
<service id="data_collector.request" class="%data_collector.request.class%">
|
||||
<tag name="data_collector" />
|
||||
</service>
|
||||
|
||||
<service id="data_collector.timer" class="%data_collector.timer.class%">
|
||||
<tag name="data_collector" core="true" />
|
||||
<argument type="service" id="service_container" />
|
||||
<tag name="data_collector" />
|
||||
<argument type="service" id="kernel" />
|
||||
</service>
|
||||
|
||||
<service id="data_collector.memory" class="%data_collector.memory.class%">
|
||||
<tag name="data_collector" core="true" />
|
||||
<tag name="data_collector" />
|
||||
</service>
|
||||
|
||||
<service id="data_collector.logger" class="%data_collector.logger.class%">
|
||||
<tag name="data_collector" />
|
||||
<argument type="service" id="logger" on-invalid="ignore" />
|
||||
</service>
|
||||
|
||||
<service id="data_collector.exception" class="%data_collector.exception.class%">
|
||||
<tag name="data_collector" />
|
||||
</service>
|
||||
|
||||
<service id="data_collector.events" class="%data_collector.events.class%">
|
||||
<tag name="data_collector" />
|
||||
<call method="setEventDispatcher">
|
||||
<argument type="service" id="event_dispatcher" />
|
||||
</call>
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
<parameters>
|
||||
<parameter key="profiler.class">Symfony\Bundle\FrameworkBundle\Profiler</parameter>
|
||||
<parameter key="profiler.storage.class">Symfony\Component\HttpKernel\Profiler\ProfilerStorage</parameter>
|
||||
<parameter key="profiler.storage.class">Symfony\Component\HttpKernel\Profiler\SQLiteProfilerStorage</parameter>
|
||||
<parameter key="profiler.storage.file">%kernel.cache_dir%/profiler.db</parameter>
|
||||
<parameter key="profiler.storage.lifetime">86400</parameter>
|
||||
<parameter key="profiler_listener.class">Symfony\Component\HttpKernel\Profiler\ProfilerListener</parameter>
|
||||
@ -21,7 +21,6 @@
|
||||
|
||||
<service id="profiler.storage" class="%profiler.storage.class%">
|
||||
<argument>%profiler.storage.file%</argument>
|
||||
<argument>null</argument>
|
||||
<argument>%profiler.storage.lifetime%</argument>
|
||||
</service>
|
||||
|
||||
|
@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
|
||||
<container xmlns="http://www.symfony-project.org/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http://www.symfony-project.org/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<parameters>
|
||||
<parameter key="debug.toolbar.class">Symfony\Component\HttpKernel\Profiler\WebDebugToolbarListener</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="debug.toolbar" class="%debug.toolbar.class%">
|
||||
<tag name="kernel.listener" />
|
||||
<argument type="service" id="profiler" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Profiler\DataCollector;
|
||||
namespace Symfony\Component\HttpKernel\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpKernel\Profiler\Profiler;
|
||||
|
||||
@ -16,25 +16,21 @@ use Symfony\Component\HttpKernel\Profiler\Profiler;
|
||||
/**
|
||||
* DataCollector.
|
||||
*
|
||||
* Children of this class must store the collected data in the data property.
|
||||
*
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpKernel\Profiler\Profiler;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DataCollectorInterface.
|
||||
*
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
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();
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DataCollector;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Framework\Debug\EventDispatcherTraceableInterface;
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* EventDataCollector.
|
||||
*
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
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';
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ExceptionDataCollector.
|
||||
*
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
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';
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DataCollector;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* LogDataCollector.
|
||||
*
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
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';
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* MemoryDataCollector.
|
||||
*
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
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';
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
use Symfony\Component\HttpFoundation\HeaderBag;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* RequestDataCollector.
|
||||
*
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
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';
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Profiler\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpKernel\Profiler\Profiler;
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DataCollectorInterface.
|
||||
*
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
interface DataCollectorInterface
|
||||
{
|
||||
function getData();
|
||||
|
||||
function setData($data);
|
||||
|
||||
function getName();
|
||||
|
||||
function collect();
|
||||
|
||||
function setProfiler(Profiler $profiler);
|
||||
|
||||
function getSummary();
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Profiler\DataCollector;
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* MemoryDataCollector.
|
||||
*
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
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('<img style="margin-left: 10px; vertical-align: middle" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAAmElEQVR42sSTuwoEIQxFr7JtOgf0n+z9Rhsr/0nB0jKiW00xs7Myj4VNFQj3cAKJGGPgSUk8rNfaeO8vqTjnxAYAAMuynAqXUj4NAKDWen8FKSWstadCIYRjg9YaUkrTsDHm2GAFtNamgP18A2BmKKWmAGaeG+ScpwCt9XdA7x299ylgP//dJQIAEYGI7gNijJcNxN+/8T0A1+E5NmcLfJkAAAAASUVORK5CYII=" />
|
||||
%.0f KB
|
||||
', $this->data['memory'] / 1024);
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'memory';
|
||||
}
|
||||
}
|
@ -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 <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
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.');
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Profiler;
|
||||
|
||||
use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface;
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ProfilerStorageInterface.
|
||||
*
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
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);
|
||||
}
|
@ -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 <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
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();
|
||||
|
||||
if ($ip = preg_replace('/[^\d\.]/', '', $ip)) {
|
||||
$criteria[] = ' ip LIKE "%'.$ip.'%"';
|
||||
}
|
||||
|
||||
public function getData($name = null)
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->data = $this->read();
|
||||
if ($url) {
|
||||
$criteria[] = ' url LIKE "%'.$url.'%"';
|
||||
}
|
||||
|
||||
if (null === $name) {
|
||||
return $this->data;
|
||||
$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;
|
||||
}
|
||||
|
||||
return isset($this->data[$name]) ? $this->data[$name] : array();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Profiler;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* 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 <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
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 = <<<EOF
|
||||
|
||||
<!-- START of Symfony 2 Web Debug Toolbar -->
|
||||
<div style="clear: both; height: 40px;"></div>
|
||||
<div style="position: $position; bottom: 0px; left:0; z-index: 6000000; width: 100%; background: #dde4eb; border-top: 1px solid #bbb; padding: 5px; margin: 0; font: 11px Verdana, Arial, sans-serif; color: #222;">
|
||||
$data
|
||||
</div>
|
||||
<!-- END of Symfony 2 Web Debug Toolbar -->
|
||||
|
||||
EOF;
|
||||
|
||||
$toolbar = "\n".str_replace("\n", '', $toolbar)."\n";
|
||||
$count = 0;
|
||||
$content = str_ireplace('</body>', $toolbar.'</body>', $response->getContent(), $count);
|
||||
if (!$count) {
|
||||
$content .= $toolbar;
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
@ -75,7 +75,7 @@ class Client extends BaseClient
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->container->getProfilerService()->load($this->response);
|
||||
return $this->container->getProfilerService()->loadFromResponse($this->response);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Tests\Component\HttpKernel\Profiler;
|
||||
|
||||
use Symfony\Component\HttpKernel\DataCollector\RequestDataCollector;
|
||||
use Symfony\Component\HttpKernel\Profiler\SQLiteProfilerStorage;
|
||||
use Symfony\Component\HttpKernel\Profiler\Profiler;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class ProfilerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testCollect()
|
||||
{
|
||||
$request = new Request();
|
||||
$request->query->set('foo', 'bar');
|
||||
$response = new Response();
|
||||
$collector = new RequestDataCollector();
|
||||
|
||||
$storage = new SQLiteProfilerStorage(sys_get_temp_dir().'/sf2_profiler.db');
|
||||
$storage->purge(true);
|
||||
|
||||
$profiler = new Profiler($storage);
|
||||
$profiler->addCollector($collector);
|
||||
$profiler->setToken('foobar');
|
||||
$profiler->collect($request, $response);
|
||||
|
||||
$profiler = new Profiler($storage);
|
||||
$profiler->setToken('foobar');
|
||||
$this->assertEquals(array('foo' => 'bar'), $profiler->getCollector('request')->getRequestQuery()->all());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user