[DoctrineBridge] Refactored the query sanitization in the collector
The original parameters are kept whenever possible to allow using them again to explain the query.
This commit is contained in:
parent
3b260d268b
commit
e37783f4f9
@ -13,6 +13,7 @@ namespace Symfony\Bridge\Doctrine\DataCollector;
|
|||||||
|
|
||||||
use Doctrine\Common\Persistence\ManagerRegistry;
|
use Doctrine\Common\Persistence\ManagerRegistry;
|
||||||
use Doctrine\DBAL\Logging\DebugStack;
|
use Doctrine\DBAL\Logging\DebugStack;
|
||||||
|
use Doctrine\DBAL\Types\Type;
|
||||||
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
|
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
@ -54,7 +55,7 @@ class DoctrineDataCollector extends DataCollector
|
|||||||
{
|
{
|
||||||
$queries = array();
|
$queries = array();
|
||||||
foreach ($this->loggers as $name => $logger) {
|
foreach ($this->loggers as $name => $logger) {
|
||||||
$queries[$name] = $this->sanitizeQueries($logger->queries);
|
$queries[$name] = $this->sanitizeQueries($name, $logger->queries);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->data = array(
|
$this->data = array(
|
||||||
@ -104,48 +105,73 @@ class DoctrineDataCollector extends DataCollector
|
|||||||
return 'db';
|
return 'db';
|
||||||
}
|
}
|
||||||
|
|
||||||
private function sanitizeQueries($queries)
|
private function sanitizeQueries($connectionName, $queries)
|
||||||
{
|
{
|
||||||
foreach ($queries as $i => $query) {
|
foreach ($queries as $i => $query) {
|
||||||
foreach ((array) $query['params'] as $j => $param) {
|
$queries[$i] = $this->sanitizeQuery($connectionName, $query);
|
||||||
$queries[$i]['params'][$j] = $this->varToString($param);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $queries;
|
return $queries;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function varToString($var)
|
private function sanitizeQuery($connectionName, $query)
|
||||||
|
{
|
||||||
|
$query['explainable'] = true;
|
||||||
|
$query['params'] = (array) $query['params'];
|
||||||
|
foreach ($query['params'] as $j => &$param) {
|
||||||
|
if (isset($query['types'][$j])) {
|
||||||
|
// Transform the param according to the type
|
||||||
|
$type = $query['types'][$j];
|
||||||
|
if (is_string($type)) {
|
||||||
|
$type = Type::getType($type);
|
||||||
|
}
|
||||||
|
if ($type instanceof Type) {
|
||||||
|
$query['types'][$j] = $type->getBindingType();
|
||||||
|
$param = $type->convertToDatabaseValue($param, $this->registry->getConnection($connectionName)->getDatabasePlatform());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list($param, $explainable) = $this->sanitizeParam($param);
|
||||||
|
if (!$explainable) {
|
||||||
|
$query['explainable'] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitizes a param.
|
||||||
|
*
|
||||||
|
* The return value is an array with the sanitized value and a boolean
|
||||||
|
* indicating if the original value was kept (allowing to use the sanitized
|
||||||
|
* value to explain the query).
|
||||||
|
*
|
||||||
|
* @param mixed $var
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function sanitizeParam($var)
|
||||||
{
|
{
|
||||||
if (is_object($var)) {
|
if (is_object($var)) {
|
||||||
return sprintf('Object(%s)', get_class($var));
|
return array(sprintf('Object(%s)', get_class($var)), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($var)) {
|
if (is_array($var)) {
|
||||||
$a = array();
|
$a = array();
|
||||||
|
$original = true;
|
||||||
foreach ($var as $k => $v) {
|
foreach ($var as $k => $v) {
|
||||||
$a[] = sprintf('%s => %s', $k, $this->varToString($v));
|
list($value, $orig) = $this->sanitizeParam($v);
|
||||||
|
$original = $original && $orig;
|
||||||
|
$a[$k] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sprintf("Array(%s)", implode(', ', $a));
|
return array($a, $original);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_resource($var)) {
|
if (is_resource($var)) {
|
||||||
return sprintf('Resource(%s)', get_resource_type($var));
|
return array(sprintf('Resource(%s)', get_resource_type($var)), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $var) {
|
return array($var, true);
|
||||||
return 'null';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false === $var) {
|
|
||||||
return 'false';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (true === $var) {
|
|
||||||
return 'true';
|
|
||||||
}
|
|
||||||
|
|
||||||
return (string) $var;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace Symfony\Tests\Bridge\Doctrine\DataCollector;
|
namespace Symfony\Tests\Bridge\Doctrine\DataCollector;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Platforms\MySqlPlatform;
|
||||||
use Symfony\Bridge\Doctrine\DataCollector\DoctrineDataCollector;
|
use Symfony\Bridge\Doctrine\DataCollector\DoctrineDataCollector;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
@ -70,25 +71,26 @@ class DoctrineDataCollectorTest extends \PHPUnit_Framework_TestCase
|
|||||||
/**
|
/**
|
||||||
* @dataProvider paramProvider
|
* @dataProvider paramProvider
|
||||||
*/
|
*/
|
||||||
public function testCollectQueries($param, $expected)
|
public function testCollectQueries($param, $types, $expected, $explainable)
|
||||||
{
|
{
|
||||||
$queries = array(
|
$queries = array(
|
||||||
array('sql' => "SELECT * FROM table1 WHERE field1 = ?1", 'params' => array($param), 'types' => array(), 'executionMS' => 1)
|
array('sql' => "SELECT * FROM table1 WHERE field1 = ?1", 'params' => array($param), 'types' => $types, 'executionMS' => 1)
|
||||||
);
|
);
|
||||||
$c = $this->createCollector($queries);
|
$c = $this->createCollector($queries);
|
||||||
$c->collect(new Request(), new Response());
|
$c->collect(new Request(), new Response());
|
||||||
|
|
||||||
$collected_queries = $c->getQueries();
|
$collected_queries = $c->getQueries();
|
||||||
$this->assertEquals($expected, $collected_queries['default'][0]['params'][0]);
|
$this->assertEquals($expected, $collected_queries['default'][0]['params'][0]);
|
||||||
|
$this->assertEquals($explainable, $collected_queries['default'][0]['explainable']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider paramProvider
|
* @dataProvider paramProvider
|
||||||
*/
|
*/
|
||||||
public function testSerialization($param, $expected)
|
public function testSerialization($param, $types, $expected, $explainable)
|
||||||
{
|
{
|
||||||
$queries = array(
|
$queries = array(
|
||||||
array('sql' => "SELECT * FROM table1 WHERE field1 = ?1", 'params' => array($param), 'types' => array(), 'executionMS' => 1)
|
array('sql' => "SELECT * FROM table1 WHERE field1 = ?1", 'params' => array($param), 'types' => $types, 'executionMS' => 1)
|
||||||
);
|
);
|
||||||
$c = $this->createCollector($queries);
|
$c = $this->createCollector($queries);
|
||||||
$c->collect(new Request(), new Response());
|
$c->collect(new Request(), new Response());
|
||||||
@ -96,23 +98,31 @@ class DoctrineDataCollectorTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$collected_queries = $c->getQueries();
|
$collected_queries = $c->getQueries();
|
||||||
$this->assertEquals($expected, $collected_queries['default'][0]['params'][0]);
|
$this->assertEquals($expected, $collected_queries['default'][0]['params'][0]);
|
||||||
|
$this->assertEquals($explainable, $collected_queries['default'][0]['explainable']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function paramProvider()
|
public function paramProvider()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array('some value', 'some value'),
|
array('some value', array(), 'some value', true),
|
||||||
array(1, '1'),
|
array(1, array(), 1, true),
|
||||||
array(true, 'true'),
|
array(true, array(), true, true),
|
||||||
array(null, 'null'),
|
array(null, array(), null, true),
|
||||||
array(new \stdClass(), 'Object(stdClass)'),
|
array(new \DateTime('2011-09-11'), array('date'), '2011-09-11', true),
|
||||||
array(fopen(__FILE__, 'r'), 'Resource(stream)'),
|
array(fopen(__FILE__, 'r'), array(), 'Resource(stream)', false),
|
||||||
array(new \SplFileInfo(__FILE__), 'Object(SplFileInfo)'),
|
array(new \SplFileInfo(__FILE__), array(), 'Object(SplFileInfo)', false),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createCollector($queries)
|
private function createCollector($queries)
|
||||||
{
|
{
|
||||||
|
$connection = $this->getMockBuilder('Doctrine\DBAL\Connection')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$connection->expects($this->any())
|
||||||
|
->method('getDatabasePlatform')
|
||||||
|
->will($this->returnValue(new MySqlPlatform()));
|
||||||
|
|
||||||
$registry = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry');
|
$registry = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry');
|
||||||
$registry
|
$registry
|
||||||
->expects($this->any())
|
->expects($this->any())
|
||||||
@ -122,6 +132,9 @@ class DoctrineDataCollectorTest extends \PHPUnit_Framework_TestCase
|
|||||||
->expects($this->any())
|
->expects($this->any())
|
||||||
->method('getManagerNames')
|
->method('getManagerNames')
|
||||||
->will($this->returnValue(array('default' => 'doctrine.orm.default_entity_manager')));
|
->will($this->returnValue(array('default' => 'doctrine.orm.default_entity_manager')));
|
||||||
|
$registry->expects($this->any())
|
||||||
|
->method('getConnection')
|
||||||
|
->will($this->returnValue($connection));
|
||||||
|
|
||||||
$logger = $this->getMock('Doctrine\DBAL\Logging\DebugStack');
|
$logger = $this->getMock('Doctrine\DBAL\Logging\DebugStack');
|
||||||
$logger->queries = $queries;
|
$logger->queries = $queries;
|
||||||
|
Reference in New Issue
Block a user