doctrine /
DoctrineBundle
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | namespace Doctrine\Bundle\DoctrineBundle\DataCollector; |
||
| 4 | |||
| 5 | use Doctrine\Common\Persistence\ManagerRegistry; |
||
| 6 | use Doctrine\ORM\Cache\Logging\CacheLoggerChain; |
||
| 7 | use Doctrine\ORM\Cache\Logging\StatisticsCacheLogger; |
||
| 8 | use Doctrine\ORM\Configuration; |
||
| 9 | use Doctrine\ORM\Mapping\ClassMetadataFactory; |
||
| 10 | use Doctrine\ORM\Tools\SchemaValidator; |
||
| 11 | use Doctrine\ORM\Version; |
||
| 12 | use Symfony\Bridge\Doctrine\DataCollector\DoctrineDataCollector as BaseCollector; |
||
| 13 | use Symfony\Component\HttpFoundation\Request; |
||
| 14 | use Symfony\Component\HttpFoundation\Response; |
||
| 15 | |||
| 16 | /** |
||
| 17 | * DoctrineDataCollector. |
||
| 18 | */ |
||
| 19 | class DoctrineDataCollector extends BaseCollector |
||
| 20 | { |
||
| 21 | /** @var ManagerRegistry */ |
||
| 22 | private $registry; |
||
| 23 | |||
| 24 | /** @var int|null */ |
||
| 25 | private $invalidEntityCount; |
||
| 26 | |||
| 27 | public function __construct(ManagerRegistry $registry) |
||
| 28 | { |
||
| 29 | $this->registry = $registry; |
||
| 30 | |||
| 31 | parent::__construct($registry); |
||
| 32 | } |
||
| 33 | |||
| 34 | /** |
||
| 35 | * {@inheritdoc} |
||
| 36 | */ |
||
| 37 | public function collect(Request $request, Response $response, \Exception $exception = null) |
||
| 38 | { |
||
| 39 | parent::collect($request, $response, $exception); |
||
| 40 | |||
| 41 | $errors = []; |
||
| 42 | $entities = []; |
||
| 43 | $caches = [ |
||
| 44 | 'enabled' => false, |
||
| 45 | 'log_enabled' => false, |
||
| 46 | 'counts' => [ |
||
| 47 | 'puts' => 0, |
||
| 48 | 'hits' => 0, |
||
| 49 | 'misses' => 0, |
||
| 50 | ], |
||
| 51 | 'regions' => [ |
||
| 52 | 'puts' => [], |
||
| 53 | 'hits' => [], |
||
| 54 | 'misses' => [], |
||
| 55 | ], |
||
| 56 | ]; |
||
| 57 | |||
| 58 | foreach ($this->registry->getManagers() as $name => $em) { |
||
| 59 | $entities[$name] = []; |
||
| 60 | /** @var ClassMetadataFactory $factory */ |
||
| 61 | $factory = $em->getMetadataFactory(); |
||
| 62 | $validator = new SchemaValidator($em); |
||
| 63 | |||
| 64 | /** @var $class \Doctrine\ORM\Mapping\ClassMetadataInfo */ |
||
| 65 | foreach ($factory->getLoadedMetadata() as $class) { |
||
| 66 | if (isset($entities[$name][$class->getName()])) { |
||
| 67 | continue; |
||
| 68 | } |
||
| 69 | |||
| 70 | $classErrors = $validator->validateClass($class); |
||
| 71 | $entities[$name][$class->getName()] = $class->getName(); |
||
| 72 | |||
| 73 | if (empty($classErrors)) { |
||
| 74 | continue; |
||
| 75 | } |
||
| 76 | |||
| 77 | $errors[$name][$class->getName()] = $classErrors; |
||
| 78 | } |
||
| 79 | |||
| 80 | if (version_compare(Version::VERSION, '2.5.0-DEV') < 0) { |
||
| 81 | continue; |
||
| 82 | } |
||
| 83 | |||
| 84 | /** @var Configuration $emConfig */ |
||
| 85 | $emConfig = $em->getConfiguration(); |
||
| 86 | $slcEnabled = $emConfig->isSecondLevelCacheEnabled(); |
||
| 87 | |||
| 88 | if (! $slcEnabled) { |
||
| 89 | continue; |
||
| 90 | } |
||
| 91 | |||
| 92 | $caches['enabled'] = true; |
||
| 93 | |||
| 94 | /** @var $cacheConfiguration \Doctrine\ORM\Cache\CacheConfiguration */ |
||
| 95 | /** @var CacheLoggerChain $cacheLoggerChain */ |
||
| 96 | $cacheConfiguration = $emConfig->getSecondLevelCacheConfiguration(); |
||
| 97 | $cacheLoggerChain = $cacheConfiguration->getCacheLogger(); |
||
| 98 | |||
| 99 | if (! $cacheLoggerChain || ! $cacheLoggerChain->getLogger('statistics')) { |
||
| 100 | continue; |
||
| 101 | } |
||
| 102 | |||
| 103 | /** @var StatisticsCacheLogger $cacheLoggerStats */ |
||
| 104 | $cacheLoggerStats = $cacheLoggerChain->getLogger('statistics'); |
||
| 105 | $caches['log_enabled'] = true; |
||
| 106 | |||
| 107 | $caches['counts']['puts'] += $cacheLoggerStats->getPutCount(); |
||
| 108 | $caches['counts']['hits'] += $cacheLoggerStats->getHitCount(); |
||
| 109 | $caches['counts']['misses'] += $cacheLoggerStats->getMissCount(); |
||
| 110 | |||
| 111 | View Code Duplication | foreach ($cacheLoggerStats->getRegionsPut() as $key => $value) { |
|
| 112 | if (! isset($caches['regions']['puts'][$key])) { |
||
| 113 | $caches['regions']['puts'][$key] = 0; |
||
| 114 | } |
||
| 115 | |||
| 116 | $caches['regions']['puts'][$key] += $value; |
||
| 117 | } |
||
| 118 | |||
| 119 | View Code Duplication | foreach ($cacheLoggerStats->getRegionsHit() as $key => $value) { |
|
| 120 | if (! isset($caches['regions']['hits'][$key])) { |
||
| 121 | $caches['regions']['hits'][$key] = 0; |
||
| 122 | } |
||
| 123 | |||
| 124 | $caches['regions']['hits'][$key] += $value; |
||
| 125 | } |
||
| 126 | |||
| 127 | View Code Duplication | foreach ($cacheLoggerStats->getRegionsMiss() as $key => $value) { |
|
|
0 ignored issues
–
show
|
|||
| 128 | if (! isset($caches['regions']['misses'][$key])) { |
||
| 129 | $caches['regions']['misses'][$key] = 0; |
||
| 130 | } |
||
| 131 | |||
| 132 | $caches['regions']['misses'][$key] += $value; |
||
| 133 | } |
||
| 134 | } |
||
| 135 | |||
| 136 | // HttpKernel < 3.2 compatibility layer |
||
| 137 | if (method_exists($this, 'cloneVar')) { |
||
| 138 | // Might be good idea to replicate this block in doctrine bridge so we can drop this from here after some time. |
||
| 139 | // This code is compatible with such change, because cloneVar is supposed to check if input is already cloned. |
||
| 140 | foreach ($this->data['queries'] as &$queries) { |
||
| 141 | foreach ($queries as &$query) { |
||
| 142 | $query['params'] = $this->cloneVar($query['params']); |
||
| 143 | } |
||
| 144 | } |
||
| 145 | } |
||
| 146 | |||
| 147 | $this->data['entities'] = $entities; |
||
| 148 | $this->data['errors'] = $errors; |
||
| 149 | $this->data['caches'] = $caches; |
||
| 150 | } |
||
| 151 | |||
| 152 | public function getEntities() |
||
| 153 | { |
||
| 154 | return $this->data['entities']; |
||
| 155 | } |
||
| 156 | |||
| 157 | public function getMappingErrors() |
||
| 158 | { |
||
| 159 | return $this->data['errors']; |
||
| 160 | } |
||
| 161 | |||
| 162 | public function getCacheHitsCount() |
||
| 163 | { |
||
| 164 | return $this->data['caches']['counts']['hits']; |
||
| 165 | } |
||
| 166 | |||
| 167 | public function getCachePutsCount() |
||
| 168 | { |
||
| 169 | return $this->data['caches']['counts']['puts']; |
||
| 170 | } |
||
| 171 | |||
| 172 | public function getCacheMissesCount() |
||
| 173 | { |
||
| 174 | return $this->data['caches']['counts']['misses']; |
||
| 175 | } |
||
| 176 | |||
| 177 | public function getCacheEnabled() |
||
| 178 | { |
||
| 179 | return $this->data['caches']['enabled']; |
||
| 180 | } |
||
| 181 | |||
| 182 | public function getCacheRegions() |
||
| 183 | { |
||
| 184 | return $this->data['caches']['regions']; |
||
| 185 | } |
||
| 186 | |||
| 187 | public function getCacheCounts() |
||
| 188 | { |
||
| 189 | return $this->data['caches']['counts']; |
||
| 190 | } |
||
| 191 | |||
| 192 | public function getInvalidEntityCount() |
||
| 193 | { |
||
| 194 | if ($this->invalidEntityCount === null) { |
||
| 195 | $this->invalidEntityCount = array_sum(array_map('count', $this->data['errors'])); |
||
| 196 | } |
||
| 197 | |||
| 198 | return $this->invalidEntityCount; |
||
| 199 | } |
||
| 200 | |||
| 201 | public function getGroupedQueries() |
||
| 202 | { |
||
| 203 | static $groupedQueries = null; |
||
| 204 | |||
| 205 | if ($groupedQueries !== null) { |
||
| 206 | return $groupedQueries; |
||
| 207 | } |
||
| 208 | |||
| 209 | $groupedQueries = []; |
||
| 210 | $totalExecutionMS = 0; |
||
| 211 | foreach ($this->data['queries'] as $connection => $queries) { |
||
| 212 | $connectionGroupedQueries = []; |
||
| 213 | foreach ($queries as $i => $query) { |
||
| 214 | $key = $query['sql']; |
||
| 215 | if (! isset($connectionGroupedQueries[$key])) { |
||
| 216 | $connectionGroupedQueries[$key] = $query; |
||
| 217 | $connectionGroupedQueries[$key]['executionMS'] = 0; |
||
| 218 | $connectionGroupedQueries[$key]['count'] = 0; |
||
| 219 | $connectionGroupedQueries[$key]['index'] = $i; // "Explain query" relies on query index in 'queries'. |
||
| 220 | } |
||
| 221 | $connectionGroupedQueries[$key]['executionMS'] += $query['executionMS']; |
||
| 222 | $connectionGroupedQueries[$key]['count']++; |
||
| 223 | $totalExecutionMS += $query['executionMS']; |
||
| 224 | } |
||
| 225 | usort($connectionGroupedQueries, function ($a, $b) { |
||
| 226 | if ($a['executionMS'] === $b['executionMS']) { |
||
| 227 | return 0; |
||
| 228 | } |
||
| 229 | return ($a['executionMS'] < $b['executionMS']) ? 1 : -1; |
||
| 230 | }); |
||
| 231 | $groupedQueries[$connection] = $connectionGroupedQueries; |
||
| 232 | } |
||
| 233 | |||
| 234 | foreach ($groupedQueries as $connection => $queries) { |
||
| 235 | foreach ($queries as $i => $query) { |
||
| 236 | $groupedQueries[$connection][$i]['executionPercent'] = |
||
| 237 | $this->executionTimePercentage($query['executionMS'], $totalExecutionMS); |
||
| 238 | } |
||
| 239 | } |
||
| 240 | |||
| 241 | return $groupedQueries; |
||
| 242 | } |
||
| 243 | |||
| 244 | private function executionTimePercentage($executionTimeMS, $totalExecutionTimeMS) |
||
| 245 | { |
||
| 246 | if ($totalExecutionTimeMS === 0.0 || $totalExecutionTimeMS === 0) { |
||
| 247 | return 0; |
||
| 248 | } |
||
| 249 | |||
| 250 | return $executionTimeMS / $totalExecutionTimeMS * 100; |
||
| 251 | } |
||
| 252 | |||
| 253 | public function getGroupedQueryCount() |
||
| 254 | { |
||
| 255 | $count = 0; |
||
| 256 | foreach ($this->getGroupedQueries() as $connectionGroupedQueries) { |
||
| 257 | $count += count($connectionGroupedQueries); |
||
| 258 | } |
||
| 259 | |||
| 260 | return $count; |
||
| 261 | } |
||
| 262 | } |
||
| 263 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.