Skip to content

Commit d46ae15

Browse files
author
Jelte Steijaert
committed
Extract the profiler to a new component
1 parent 775129f commit d46ae15

File tree

167 files changed

+10216
-654
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

167 files changed

+10216
-654
lines changed

composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
"symfony/monolog-bridge": "self.version",
5656
"symfony/options-resolver": "self.version",
5757
"symfony/process": "self.version",
58+
"symfony/profiler": "self.version",
5859
"symfony/property-access": "self.version",
5960
"symfony/property-info": "self.version",
6061
"symfony/proxy-manager-bridge": "self.version",

src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
* DoctrineDataCollector.
2323
*
2424
* @author Fabien Potencier <fabien@symfony.com>
25+
*
26+
* @deprecated since 2.8, to be removed in 3.0. Use Symfony\Bridge\Doctrine\Profiler\DoctrineDataCollector instead.
2527
*/
2628
class DoctrineDataCollector extends DataCollector
2729
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Doctrine\Profiler;
13+
14+
use Doctrine\Common\Persistence\ManagerRegistry;
15+
use Doctrine\DBAL\Logging\DebugStack;
16+
use Doctrine\DBAL\Types\Type;
17+
use Symfony\Component\Profiler\DataCollector\DataCollectorInterface;
18+
19+
/**
20+
* DoctrineDataCollector.
21+
*
22+
* @author Fabien Potencier <fabien@symfony.com>
23+
*/
24+
class DoctrineDataCollector implements DataCollectorInterface
25+
{
26+
private $registry;
27+
private $loggers = array();
28+
29+
public function __construct(ManagerRegistry $registry)
30+
{
31+
$this->registry = $registry;
32+
}
33+
34+
/**
35+
* Adds the stack logger for a connection.
36+
*
37+
* @param string $name
38+
* @param DebugStack $logger
39+
*/
40+
public function addLogger($name, DebugStack $logger)
41+
{
42+
$this->loggers[$name] = $logger;
43+
}
44+
45+
/**
46+
* {@inheritdoc}
47+
*/
48+
public function getCollectedData()
49+
{
50+
$queries = array();
51+
foreach ($this->loggers as $name => $logger) {
52+
$queries[$name] = $this->sanitizeQueries($name, $logger->queries);
53+
}
54+
55+
return new DoctrineProfileData($queries, $this->registry);
56+
}
57+
58+
private function sanitizeQueries($connectionName, array $queries)
59+
{
60+
foreach ($queries as $i => $query) {
61+
$queries[$i] = $this->sanitizeQuery($connectionName, $query);
62+
}
63+
64+
return $queries;
65+
}
66+
67+
private function sanitizeQuery($connectionName, $query)
68+
{
69+
$query['explainable'] = true;
70+
if (!is_array($query['params'])) {
71+
$query['params'] = array($query['params']);
72+
}
73+
foreach ($query['params'] as $j => $param) {
74+
if (isset($query['types'][$j])) {
75+
// Transform the param according to the type
76+
$type = $query['types'][$j];
77+
if (is_string($type)) {
78+
$type = Type::getType($type);
79+
}
80+
if ($type instanceof Type) {
81+
$query['types'][$j] = $type->getBindingType();
82+
$param = $type->convertToDatabaseValue($param, $this->registry->getConnection($connectionName)->getDatabasePlatform());
83+
}
84+
}
85+
86+
list($query['params'][$j], $explainable) = $this->sanitizeParam($param);
87+
if (!$explainable) {
88+
$query['explainable'] = false;
89+
}
90+
}
91+
92+
return $query;
93+
}
94+
95+
/**
96+
* Sanitizes a param.
97+
*
98+
* The return value is an array with the sanitized value and a boolean
99+
* indicating if the original value was kept (allowing to use the sanitized
100+
* value to explain the query).
101+
*
102+
* @param mixed $var
103+
*
104+
* @return array
105+
*/
106+
private function sanitizeParam($var)
107+
{
108+
if (is_object($var)) {
109+
return array(sprintf('Object(%s)', get_class($var)), false);
110+
}
111+
112+
if (is_array($var)) {
113+
$a = array();
114+
$original = true;
115+
foreach ($var as $k => $v) {
116+
list($value, $orig) = $this->sanitizeParam($v);
117+
$original = $original && $orig;
118+
$a[$k] = $value;
119+
}
120+
121+
return array($a, $original);
122+
}
123+
124+
if (is_resource($var)) {
125+
return array(sprintf('Resource(%s)', get_resource_type($var)), false);
126+
}
127+
128+
return array($var, true);
129+
}
130+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
<?php
2+
3+
namespace Symfony\Bridge\Doctrine\Profiler;
4+
5+
use Doctrine\Common\Persistence\ManagerRegistry;
6+
use Doctrine\ORM\Tools\SchemaValidator;
7+
use Doctrine\ORM\Version;
8+
use Symfony\Component\Profiler\ProfileData\ProfileDataInterface;
9+
10+
class DoctrineProfileData implements ProfileDataInterface
11+
{
12+
private $queries;
13+
private $connections;
14+
private $managers;
15+
private $invalidEntityCount;
16+
private $cacheEnabled = false;
17+
private $cacheLogEnabled = false;
18+
private $cacheCounts = array('puts' => 0, 'hits' => 0, 'misses' => 0);
19+
private $cacheRegions = array('puts' => array(), 'hits' => array(), 'misses' => array());
20+
private $errors = array();
21+
private $entities = array();
22+
23+
public function __construct(array $queries, ManagerRegistry $registry)
24+
{
25+
$this->queries = $queries;
26+
$this->connections = $registry->getConnectionNames();
27+
$this->managers = $registry->getManagerNames();
28+
29+
/*
30+
* @var string
31+
* @var \Doctrine\ORM\EntityManager
32+
*/
33+
foreach ($registry->getManagers() as $name => $em) {
34+
$this->entities[$name] = array();
35+
/** @var $factory \Doctrine\ORM\Mapping\ClassMetadataFactory */
36+
$factory = $em->getMetadataFactory();
37+
$validator = new SchemaValidator($em);
38+
39+
/** @var $class \Doctrine\ORM\Mapping\ClassMetadataInfo */
40+
foreach ($factory->getLoadedMetadata() as $class) {
41+
if (!isset($entities[$name][$class->getName()])) {
42+
$classErrors = $validator->validateClass($class);
43+
$this->entities[$name][$class->getName()] = $class->getName();
44+
45+
if (!empty($classErrors)) {
46+
$this->errors[$name][$class->getName()] = $classErrors;
47+
}
48+
}
49+
}
50+
51+
if (version_compare(Version::VERSION, '2.5.0-DEV') < 0) {
52+
continue;
53+
}
54+
55+
/** @var $emConfig \Doctrine\ORM\Configuration */
56+
$emConfig = $em->getConfiguration();
57+
$slcEnabled = $emConfig->isSecondLevelCacheEnabled();
58+
59+
if (!$slcEnabled) {
60+
continue;
61+
}
62+
63+
$this->cacheEnabled = true;
64+
65+
/** @var $cacheConfiguration \Doctrine\ORM\Cache\CacheConfiguration */
66+
$cacheConfiguration = $emConfig->getSecondLevelCacheConfiguration();
67+
/** @var $cacheLoggerChain \Doctrine\ORM\Cache\Logging\CacheLoggerChain */
68+
$cacheLoggerChain = $cacheConfiguration->getCacheLogger();
69+
70+
if (!$cacheLoggerChain || !$cacheLoggerChain->getLogger('statistics')) {
71+
continue;
72+
}
73+
74+
/** @var $cacheLoggerStats \Doctrine\ORM\Cache\Logging\StatisticsCacheLogger */
75+
$cacheLoggerStats = $cacheLoggerChain->getLogger('statistics');
76+
$this->cacheLogEnabled = true;
77+
78+
$this->cacheCounts['puts'] += $cacheLoggerStats->getPutCount();
79+
$this->cacheCounts['hits'] += $cacheLoggerStats->getHitCount();
80+
$this->cacheCounts['misses'] += $cacheLoggerStats->getMissCount();
81+
82+
foreach ($cacheLoggerStats->getRegionsPut() as $key => $value) {
83+
if (!isset($this->cacheRegions['hits'][$key])) {
84+
$this->cacheRegions['hits'][$key] = 0;
85+
}
86+
87+
$this->cacheRegions['puts'][$key] += $value;
88+
}
89+
90+
foreach ($cacheLoggerStats->getRegionsHit() as $key => $value) {
91+
if (!isset($this->cacheRegions['hits'][$key])) {
92+
$this->cacheRegions['hits'][$key] = 0;
93+
}
94+
95+
$this->cacheRegions['hits'][$key] += $value;
96+
}
97+
98+
foreach ($cacheLoggerStats->getRegionsMiss() as $key => $value) {
99+
if (!isset($this->cacheRegions['misses'][$key])) {
100+
$this->cacheRegions['misses'][$key] = 0;
101+
}
102+
103+
$this->cacheRegions['misses'][$key] += $value;
104+
}
105+
}
106+
}
107+
108+
public function getManagers()
109+
{
110+
return $this->managers;
111+
}
112+
113+
public function getConnections()
114+
{
115+
return $this->connections;
116+
}
117+
118+
public function getQueryCount()
119+
{
120+
return array_sum(array_map('count', $this->queries));
121+
}
122+
123+
public function getQueries()
124+
{
125+
return $this->queries;
126+
}
127+
128+
public function getTime()
129+
{
130+
$time = 0;
131+
foreach ($this->queries as $queries) {
132+
foreach ($queries as $query) {
133+
$time += $query['executionMS'];
134+
}
135+
}
136+
137+
return $time;
138+
}
139+
140+
public function getEntities()
141+
{
142+
return $this->entities;
143+
}
144+
145+
public function getMappingErrors()
146+
{
147+
return $this->errors;
148+
}
149+
150+
public function getCacheHitsCount()
151+
{
152+
return $this->cacheCounts['hits'];
153+
}
154+
155+
public function getCachePutsCount()
156+
{
157+
return $this->cacheCounts['puts'];
158+
}
159+
160+
public function getCacheMissesCount()
161+
{
162+
return $this->cacheCounts['misses'];
163+
}
164+
165+
public function getCacheEnabled()
166+
{
167+
return $this->cacheEnabled;
168+
}
169+
170+
public function getCacheRegions()
171+
{
172+
return $this->cacheRegions;
173+
}
174+
175+
public function getCacheCounts()
176+
{
177+
return $this->cacheCounts;
178+
}
179+
180+
public function getInvalidEntityCount()
181+
{
182+
if (null === $this->invalidEntityCount) {
183+
$this->invalidEntityCount = array_sum(array_map('count', $this->errors));
184+
}
185+
186+
return $this->invalidEntityCount;
187+
}
188+
189+
/**
190+
* {@inheritdoc}
191+
*/
192+
public function serialize()
193+
{
194+
return serialize(array(
195+
'queries' => $this->queries,
196+
'connections' => $this->connections,
197+
'managers' => $this->managers,
198+
'invalidEntityCount' => $this->invalidEntityCount,
199+
'cacheEnabled' => $this->cacheEnabled,
200+
'cacheLogEnabled' => $this->cacheLogEnabled,
201+
'cacheCounts' => $this->cacheCounts,
202+
'cacheRegions' => $this->cacheRegions,
203+
'errors' => $this->errors,
204+
'entities' => $this->entities,
205+
));
206+
}
207+
208+
/**
209+
* {@inheritdoc}
210+
*/
211+
public function unserialize($serialized)
212+
{
213+
$unserialized = unserialize($serialized);
214+
$this->queries = $unserialized['queries'];
215+
$this->connections = $unserialized['connections'];
216+
$this->managers = $unserialized['managers'];
217+
$this->invalidEntityCount = $unserialized['invalidEntityCount'];
218+
$this->cacheEnabled = $unserialized['cacheEnabled'];
219+
$this->cacheLogEnabled = $unserialized['cacheLogEnabled'];
220+
$this->cacheCounts = $unserialized['cacheCounts'];
221+
$this->cacheRegions = $unserialized['cacheRegions'];
222+
$this->errors = $unserialized['errors'];
223+
$this->entities = $unserialized['entities'];
224+
}
225+
226+
/**
227+
* {@inheritdoc}
228+
*/
229+
public function getName()
230+
{
231+
return 'db';
232+
}
233+
}

0 commit comments

Comments
 (0)