vendor/doctrine/doctrine-bundle/DataCollector/DoctrineDataCollector.php line 43

Open in your IDE?
  1. <?php
  2. namespace Doctrine\Bundle\DoctrineBundle\DataCollector;
  3. use Doctrine\ORM\Cache\Logging\CacheLoggerChain;
  4. use Doctrine\ORM\Cache\Logging\StatisticsCacheLogger;
  5. use Doctrine\ORM\Configuration;
  6. use Doctrine\ORM\EntityManager;
  7. use Doctrine\ORM\Mapping\ClassMetadataFactory;
  8. use Doctrine\ORM\Mapping\ClassMetadataInfo;
  9. use Doctrine\ORM\Tools\SchemaValidator;
  10. use Doctrine\Persistence\ManagerRegistry;
  11. use Symfony\Bridge\Doctrine\DataCollector\DoctrineDataCollector as BaseCollector;
  12. use Symfony\Component\HttpFoundation\Request;
  13. use Symfony\Component\HttpFoundation\Response;
  14. use Throwable;
  15. class DoctrineDataCollector extends BaseCollector
  16. {
  17.     /** @var ManagerRegistry */
  18.     private $registry;
  19.     /** @var int|null */
  20.     private $invalidEntityCount;
  21.     /** @var string[] */
  22.     private $groupedQueries;
  23.     /** @var bool */
  24.     private $shouldValidateSchema;
  25.     public function __construct(ManagerRegistry $registrybool $shouldValidateSchema true)
  26.     {
  27.         $this->registry             $registry;
  28.         $this->shouldValidateSchema $shouldValidateSchema;
  29.         parent::__construct($registry);
  30.     }
  31.     /**
  32.      * {@inheritdoc}
  33.      */
  34.     public function collect(Request $requestResponse $responseThrowable $exception null)
  35.     {
  36.         parent::collect($request$response$exception);
  37.         $errors   = [];
  38.         $entities = [];
  39.         $caches   = [
  40.             'enabled' => false,
  41.             'log_enabled' => false,
  42.             'counts' => [
  43.                 'puts' => 0,
  44.                 'hits' => 0,
  45.                 'misses' => 0,
  46.             ],
  47.             'regions' => [
  48.                 'puts' => [],
  49.                 'hits' => [],
  50.                 'misses' => [],
  51.             ],
  52.         ];
  53.         /** @var EntityManager $em */
  54.         foreach ($this->registry->getManagers() as $name => $em) {
  55.             if ($this->shouldValidateSchema) {
  56.                 $entities[$name] = [];
  57.                 /** @var ClassMetadataFactory $factory */
  58.                 $factory   $em->getMetadataFactory();
  59.                 $validator = new SchemaValidator($em);
  60.                 /** @var ClassMetadataInfo $class */
  61.                 foreach ($factory->getLoadedMetadata() as $class) {
  62.                     if (isset($entities[$name][$class->getName()])) {
  63.                         continue;
  64.                     }
  65.                     $classErrors                        $validator->validateClass($class);
  66.                     $entities[$name][$class->getName()] = $class->getName();
  67.                     if (empty($classErrors)) {
  68.                         continue;
  69.                     }
  70.                     $errors[$name][$class->getName()] = $classErrors;
  71.                 }
  72.             }
  73.             /** @var Configuration $emConfig */
  74.             $emConfig   $em->getConfiguration();
  75.             $slcEnabled $emConfig->isSecondLevelCacheEnabled();
  76.             if (! $slcEnabled) {
  77.                 continue;
  78.             }
  79.             $caches['enabled'] = true;
  80.             /** @var $cacheConfiguration \Doctrine\ORM\Cache\CacheConfiguration */
  81.             /** @var CacheLoggerChain $cacheLoggerChain */
  82.             $cacheConfiguration $emConfig->getSecondLevelCacheConfiguration();
  83.             $cacheLoggerChain   $cacheConfiguration->getCacheLogger();
  84.             if (! $cacheLoggerChain || ! $cacheLoggerChain->getLogger('statistics')) {
  85.                 continue;
  86.             }
  87.             /** @var StatisticsCacheLogger $cacheLoggerStats */
  88.             $cacheLoggerStats      $cacheLoggerChain->getLogger('statistics');
  89.             $caches['log_enabled'] = true;
  90.             $caches['counts']['puts']   += $cacheLoggerStats->getPutCount();
  91.             $caches['counts']['hits']   += $cacheLoggerStats->getHitCount();
  92.             $caches['counts']['misses'] += $cacheLoggerStats->getMissCount();
  93.             foreach ($cacheLoggerStats->getRegionsPut() as $key => $value) {
  94.                 if (! isset($caches['regions']['puts'][$key])) {
  95.                     $caches['regions']['puts'][$key] = 0;
  96.                 }
  97.                 $caches['regions']['puts'][$key] += $value;
  98.             }
  99.             foreach ($cacheLoggerStats->getRegionsHit() as $key => $value) {
  100.                 if (! isset($caches['regions']['hits'][$key])) {
  101.                     $caches['regions']['hits'][$key] = 0;
  102.                 }
  103.                 $caches['regions']['hits'][$key] += $value;
  104.             }
  105.             foreach ($cacheLoggerStats->getRegionsMiss() as $key => $value) {
  106.                 if (! isset($caches['regions']['misses'][$key])) {
  107.                     $caches['regions']['misses'][$key] = 0;
  108.                 }
  109.                 $caches['regions']['misses'][$key] += $value;
  110.             }
  111.         }
  112.         // Might be good idea to replicate this block in doctrine bridge so we can drop this from here after some time.
  113.         // This code is compatible with such change, because cloneVar is supposed to check if input is already cloned.
  114.         foreach ($this->data['queries'] as &$queries) {
  115.             foreach ($queries as &$query) {
  116.                 $query['params'] = $this->cloneVar($query['params']);
  117.                 // To be removed when the required minimum version of symfony/doctrine-bridge is >= 4.4
  118.                 $query['runnable'] = $query['runnable'] ?? true;
  119.             }
  120.         }
  121.         $this->data['entities'] = $entities;
  122.         $this->data['errors']   = $errors;
  123.         $this->data['caches']   = $caches;
  124.         $this->groupedQueries   null;
  125.     }
  126.     public function getEntities()
  127.     {
  128.         return $this->data['entities'];
  129.     }
  130.     public function getMappingErrors()
  131.     {
  132.         return $this->data['errors'];
  133.     }
  134.     public function getCacheHitsCount()
  135.     {
  136.         return $this->data['caches']['counts']['hits'];
  137.     }
  138.     public function getCachePutsCount()
  139.     {
  140.         return $this->data['caches']['counts']['puts'];
  141.     }
  142.     public function getCacheMissesCount()
  143.     {
  144.         return $this->data['caches']['counts']['misses'];
  145.     }
  146.     public function getCacheEnabled()
  147.     {
  148.         return $this->data['caches']['enabled'];
  149.     }
  150.     public function getCacheRegions()
  151.     {
  152.         return $this->data['caches']['regions'];
  153.     }
  154.     public function getCacheCounts()
  155.     {
  156.         return $this->data['caches']['counts'];
  157.     }
  158.     public function getInvalidEntityCount()
  159.     {
  160.         if ($this->invalidEntityCount === null) {
  161.             $this->invalidEntityCount array_sum(array_map('count'$this->data['errors']));
  162.         }
  163.         return $this->invalidEntityCount;
  164.     }
  165.     public function getGroupedQueries()
  166.     {
  167.         if ($this->groupedQueries !== null) {
  168.             return $this->groupedQueries;
  169.         }
  170.         $this->groupedQueries = [];
  171.         $totalExecutionMS     0;
  172.         foreach ($this->data['queries'] as $connection => $queries) {
  173.             $connectionGroupedQueries = [];
  174.             foreach ($queries as $i => $query) {
  175.                 $key $query['sql'];
  176.                 if (! isset($connectionGroupedQueries[$key])) {
  177.                     $connectionGroupedQueries[$key]                = $query;
  178.                     $connectionGroupedQueries[$key]['executionMS'] = 0;
  179.                     $connectionGroupedQueries[$key]['count']       = 0;
  180.                     $connectionGroupedQueries[$key]['index']       = $i// "Explain query" relies on query index in 'queries'.
  181.                 }
  182.                 $connectionGroupedQueries[$key]['executionMS'] += $query['executionMS'];
  183.                 $connectionGroupedQueries[$key]['count']++;
  184.                 $totalExecutionMS += $query['executionMS'];
  185.             }
  186.             usort($connectionGroupedQueries, static function ($a$b) {
  187.                 if ($a['executionMS'] === $b['executionMS']) {
  188.                     return 0;
  189.                 }
  190.                 return $a['executionMS'] < $b['executionMS'] ? : -1;
  191.             });
  192.             $this->groupedQueries[$connection] = $connectionGroupedQueries;
  193.         }
  194.         foreach ($this->groupedQueries as $connection => $queries) {
  195.             foreach ($queries as $i => $query) {
  196.                 $this->groupedQueries[$connection][$i]['executionPercent'] =
  197.                     $this->executionTimePercentage($query['executionMS'], $totalExecutionMS);
  198.             }
  199.         }
  200.         return $this->groupedQueries;
  201.     }
  202.     private function executionTimePercentage($executionTimeMS$totalExecutionTimeMS)
  203.     {
  204.         if ($totalExecutionTimeMS === 0.0 || $totalExecutionTimeMS === 0) {
  205.             return 0;
  206.         }
  207.         return $executionTimeMS $totalExecutionTimeMS 100;
  208.     }
  209.     public function getGroupedQueryCount()
  210.     {
  211.         $count 0;
  212.         foreach ($this->getGroupedQueries() as $connectionGroupedQueries) {
  213.             $count += count($connectionGroupedQueries);
  214.         }
  215.         return $count;
  216.     }
  217. }