diff --git a/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php b/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php index 354cd0aea5..e6f7b52edb 100644 --- a/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php +++ b/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php @@ -13,6 +13,7 @@ namespace Symfony\Bridge\Doctrine\DataCollector; use Doctrine\Common\Persistence\ManagerRegistry; use Doctrine\DBAL\Logging\DebugStack; +use Doctrine\DBAL\Types\Type; use Symfony\Component\HttpKernel\DataCollector\DataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -54,7 +55,7 @@ class DoctrineDataCollector extends DataCollector { $queries = array(); foreach ($this->loggers as $name => $logger) { - $queries[$name] = $this->sanitizeQueries($logger->queries); + $queries[$name] = $this->sanitizeQueries($name, $logger->queries); } $this->data = array( @@ -104,48 +105,73 @@ class DoctrineDataCollector extends DataCollector return 'db'; } - private function sanitizeQueries($queries) + private function sanitizeQueries($connectionName, $queries) { foreach ($queries as $i => $query) { - foreach ((array) $query['params'] as $j => $param) { - $queries[$i]['params'][$j] = $this->varToString($param); - } + $queries[$i] = $this->sanitizeQuery($connectionName, $query); } 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)) { - return sprintf('Object(%s)', get_class($var)); + return array(sprintf('Object(%s)', get_class($var)), false); } if (is_array($var)) { $a = array(); + $original = true; 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)) { - return sprintf('Resource(%s)', get_resource_type($var)); + return array(sprintf('Resource(%s)', get_resource_type($var)), false); } - if (null === $var) { - return 'null'; - } - - if (false === $var) { - return 'false'; - } - - if (true === $var) { - return 'true'; - } - - return (string) $var; + return array($var, true); } } diff --git a/tests/Symfony/Tests/Bridge/Doctrine/DataCollector/DoctrineDataCollectorTest.php b/tests/Symfony/Tests/Bridge/Doctrine/DataCollector/DoctrineDataCollectorTest.php index 241943b3f6..fecf6191b0 100644 --- a/tests/Symfony/Tests/Bridge/Doctrine/DataCollector/DoctrineDataCollectorTest.php +++ b/tests/Symfony/Tests/Bridge/Doctrine/DataCollector/DoctrineDataCollectorTest.php @@ -11,6 +11,7 @@ namespace Symfony\Tests\Bridge\Doctrine\DataCollector; +use Doctrine\DBAL\Platforms\MySqlPlatform; use Symfony\Bridge\Doctrine\DataCollector\DoctrineDataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -70,25 +71,26 @@ class DoctrineDataCollectorTest extends \PHPUnit_Framework_TestCase /** * @dataProvider paramProvider */ - public function testCollectQueries($param, $expected) + public function testCollectQueries($param, $types, $expected, $explainable) { $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->collect(new Request(), new Response()); $collected_queries = $c->getQueries(); $this->assertEquals($expected, $collected_queries['default'][0]['params'][0]); + $this->assertEquals($explainable, $collected_queries['default'][0]['explainable']); } /** * @dataProvider paramProvider */ - public function testSerialization($param, $expected) + public function testSerialization($param, $types, $expected, $explainable) { $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->collect(new Request(), new Response()); @@ -96,23 +98,31 @@ class DoctrineDataCollectorTest extends \PHPUnit_Framework_TestCase $collected_queries = $c->getQueries(); $this->assertEquals($expected, $collected_queries['default'][0]['params'][0]); + $this->assertEquals($explainable, $collected_queries['default'][0]['explainable']); } public function paramProvider() { return array( - array('some value', 'some value'), - array(1, '1'), - array(true, 'true'), - array(null, 'null'), - array(new \stdClass(), 'Object(stdClass)'), - array(fopen(__FILE__, 'r'), 'Resource(stream)'), - array(new \SplFileInfo(__FILE__), 'Object(SplFileInfo)'), + array('some value', array(), 'some value', true), + array(1, array(), 1, true), + array(true, array(), true, true), + array(null, array(), null, true), + array(new \DateTime('2011-09-11'), array('date'), '2011-09-11', true), + array(fopen(__FILE__, 'r'), array(), 'Resource(stream)', false), + array(new \SplFileInfo(__FILE__), array(), 'Object(SplFileInfo)', false), ); } 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 ->expects($this->any()) @@ -122,6 +132,9 @@ class DoctrineDataCollectorTest extends \PHPUnit_Framework_TestCase ->expects($this->any()) ->method('getManagerNames') ->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->queries = $queries;