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

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