1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Doctrine\Bundle\DoctrineBundle\Controller; |
4
|
|
|
|
5
|
|
|
use Doctrine\DBAL\Connection; |
6
|
|
|
use Doctrine\DBAL\Platforms\SqlitePlatform; |
7
|
|
|
use Doctrine\DBAL\Platforms\SQLServerPlatform; |
8
|
|
|
use Exception; |
9
|
|
|
use PDO; |
10
|
|
|
use Symfony\Component\DependencyInjection\ContainerAwareInterface; |
11
|
|
|
use Symfony\Component\DependencyInjection\ContainerInterface; |
12
|
|
|
use Symfony\Component\HttpFoundation\Response; |
13
|
|
|
use Symfony\Component\HttpKernel\Profiler\Profiler; |
14
|
|
|
use Symfony\Component\VarDumper\Cloner\Data; |
15
|
|
|
|
16
|
|
|
class ProfilerController implements ContainerAwareInterface |
17
|
|
|
{ |
18
|
|
|
/** @var ContainerInterface */ |
19
|
|
|
private $container; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* {@inheritDoc} |
23
|
|
|
*/ |
24
|
|
|
public function setContainer(ContainerInterface $container = null) |
25
|
|
|
{ |
26
|
|
|
$this->container = $container; |
27
|
|
|
} |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Renders the profiler panel for the given token. |
31
|
|
|
* |
32
|
|
|
* @param string $token The profiler token |
33
|
|
|
* @param string $connectionName |
34
|
|
|
* @param int $query |
35
|
|
|
* |
36
|
|
|
* @return Response A Response instance |
37
|
|
|
*/ |
38
|
|
|
public function explainAction($token, $connectionName, $query) |
39
|
|
|
{ |
40
|
|
|
/** @var Profiler $profiler */ |
41
|
|
|
$profiler = $this->container->get('profiler'); |
42
|
|
|
$profiler->disable(); |
43
|
|
|
|
44
|
|
|
$profile = $profiler->loadProfile($token); |
45
|
|
|
$queries = $profile->getCollector('db')->getQueries(); |
46
|
|
|
|
47
|
|
|
if (! isset($queries[$connectionName][$query])) { |
48
|
|
|
return new Response('This query does not exist.'); |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
$query = $queries[$connectionName][$query]; |
52
|
|
|
if (! $query['explainable']) { |
53
|
|
|
return new Response('This query cannot be explained.'); |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
/** @var Connection $connection */ |
57
|
|
|
$connection = $this->container->get('doctrine')->getConnection($connectionName); |
58
|
|
|
try { |
59
|
|
|
$platform = $connection->getDatabasePlatform(); |
60
|
|
|
if ($platform instanceof SqlitePlatform) { |
61
|
|
|
$results = $this->explainSQLitePlatform($connection, $query); |
62
|
|
|
} elseif ($platform instanceof SQLServerPlatform) { |
63
|
|
|
$results = $this->explainSQLServerPlatform($connection, $query); |
64
|
|
|
} else { |
65
|
|
|
$results = $this->explainOtherPlatform($connection, $query); |
66
|
|
|
} |
67
|
|
|
} catch (Exception $e) { |
68
|
|
|
return new Response('This query cannot be explained.'); |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
return new Response($this->container->get('twig')->render('@Doctrine/Collector/explain.html.twig', [ |
72
|
|
|
'data' => $results, |
73
|
|
|
'query' => $query, |
74
|
|
|
])); |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* @param mixed[] $query |
79
|
|
|
*/ |
80
|
|
View Code Duplication |
private function explainSQLitePlatform(Connection $connection, array $query) |
81
|
|
|
{ |
82
|
|
|
$params = $query['params']; |
83
|
|
|
|
84
|
|
|
if ($params instanceof Data) { |
85
|
|
|
$params = $params->getValue(true); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
return $connection->executeQuery('EXPLAIN QUERY PLAN ' . $query['sql'], $params, $query['types']) |
|
|
|
|
89
|
|
|
->fetchAll(PDO::FETCH_ASSOC); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
private function explainSQLServerPlatform(Connection $connection, $query) |
93
|
|
|
{ |
94
|
|
|
if (stripos($query['sql'], 'SELECT') === 0) { |
95
|
|
|
$sql = 'SET STATISTICS PROFILE ON; ' . $query['sql'] . '; SET STATISTICS PROFILE OFF;'; |
96
|
|
|
} else { |
97
|
|
|
$sql = 'SET SHOWPLAN_TEXT ON; GO; SET NOEXEC ON; ' . $query['sql'] . '; SET NOEXEC OFF; GO; SET SHOWPLAN_TEXT OFF;'; |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
$params = $query['params']; |
101
|
|
|
|
102
|
|
|
if ($params instanceof Data) { |
103
|
|
|
$params = $params->getValue(true); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
$stmt = $connection->executeQuery($sql, $params, $query['types']); |
107
|
|
|
$stmt->nextRowset(); |
108
|
|
|
|
109
|
|
|
return $stmt->fetchAll(PDO::FETCH_ASSOC); |
|
|
|
|
110
|
|
|
} |
111
|
|
|
|
112
|
|
View Code Duplication |
private function explainOtherPlatform(Connection $connection, $query) |
113
|
|
|
{ |
114
|
|
|
$params = $query['params']; |
115
|
|
|
|
116
|
|
|
if ($params instanceof Data) { |
117
|
|
|
$params = $params->getValue(true); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
return $connection->executeQuery('EXPLAIN ' . $query['sql'], $params, $query['types']) |
|
|
|
|
121
|
|
|
->fetchAll(PDO::FETCH_ASSOC); |
122
|
|
|
} |
123
|
|
|
} |
124
|
|
|
|
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.