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

Open in your IDE?
  1. <?php
  2. namespace Doctrine\Bundle\DoctrineBundle\DataCollector;
  3. use Doctrine\ORM\Cache\CacheConfiguration;
  4. use Doctrine\ORM\Cache\Logging\CacheLoggerChain;
  5. use Doctrine\ORM\Cache\Logging\StatisticsCacheLogger;
  6. use Doctrine\ORM\Configuration;
  7. use Doctrine\ORM\EntityManagerInterface;
  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. use function assert;
  16. class DoctrineDataCollector extends BaseCollector
  17. {
  18.     /** @var ManagerRegistry */
  19.     private $registry;
  20.     /** @var int|null */
  21.     private $invalidEntityCount;
  22.     /** @var string[] */
  23.     private $groupedQueries;
  24.     /** @var bool */
  25.     private $shouldValidateSchema;
  26.     public function __construct(ManagerRegistry $registrybool $shouldValidateSchema true)
  27.     {
  28.         $this->registry             $registry;
  29.         $this->shouldValidateSchema $shouldValidateSchema;
  30.         parent::__construct($registry);
  31.     }
  32.     /**
  33.      * {@inheritdoc}
  34.      */
  35.     public function collect(Request $requestResponse $responseThrowable $exception null)
  36.     {
  37.         parent::collect($request$response$exception);
  38.         $errors   = [];
  39.         $entities = [];
  40.         $caches   = [
  41.             'enabled' => false,
  42.             'log_enabled' => false,
  43.             'counts' => [
  44.                 'puts' => 0,
  45.                 'hits' => 0,
  46.                 'misses' => 0,
  47.             ],
  48.             'regions' => [
  49.                 'puts' => [],
  50.                 'hits' => [],
  51.                 'misses' => [],
  52.             ],
  53.         ];
  54.         foreach ($this->registry->getManagers() as $name => $em) {
  55.             assert($em instanceof EntityManagerInterface);
  56.             if ($this->shouldValidateSchema) {
  57.                 $entities[$name] = [];
  58.                 $factory   $em->getMetadataFactory();
  59.                 $validator = new SchemaValidator($em);
  60.                 foreach ($factory->getLoadedMetadata() as $class) {
  61.                     assert($class instanceof ClassMetadataInfo);
  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.             $emConfig $em->getConfiguration();
  74.             assert($emConfig instanceof Configuration);
  75.             $slcEnabled $emConfig->isSecondLevelCacheEnabled();
  76.             if (! $slcEnabled) {
  77.                 continue;
  78.             }
  79.             $caches['enabled'] = true;
  80.             $cacheConfiguration $emConfig->getSecondLevelCacheConfiguration();
  81.             assert($cacheConfiguration instanceof CacheConfiguration);
  82.             $cacheLoggerChain $cacheConfiguration->getCacheLogger();
  83.             assert($cacheLoggerChain instanceof CacheLoggerChain || $cacheLoggerChain === null);
  84.             if (! $cacheLoggerChain || ! $cacheLoggerChain->getLogger('statistics')) {
  85.                 continue;
  86.             }
  87.             $cacheLoggerStats $cacheLoggerChain->getLogger('statistics');
  88.             assert($cacheLoggerStats instanceof StatisticsCacheLogger);
  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.     /**
  127.      * @return array<string, array<string, string>>
  128.      */
  129.     public function getEntities()
  130.     {
  131.         return $this->data['entities'];
  132.     }
  133.     /**
  134.      * @return array<string, array<string, list<string>>>
  135.      */
  136.     public function getMappingErrors()
  137.     {
  138.         return $this->data['errors'];
  139.     }
  140.     /**
  141.      * @return int
  142.      */
  143.     public function getCacheHitsCount()
  144.     {
  145.         return $this->data['caches']['counts']['hits'];
  146.     }
  147.     /**
  148.      * @return int
  149.      */
  150.     public function getCachePutsCount()
  151.     {
  152.         return $this->data['caches']['counts']['puts'];
  153.     }
  154.     /**
  155.      * @return int
  156.      */
  157.     public function getCacheMissesCount()
  158.     {
  159.         return $this->data['caches']['counts']['misses'];
  160.     }
  161.     /**
  162.      * @return bool
  163.      */
  164.     public function getCacheEnabled()
  165.     {
  166.         return $this->data['caches']['enabled'];
  167.     }
  168.     /**
  169.      * @return array<string, array<string, int>>
  170.      */
  171.     public function getCacheRegions()
  172.     {
  173.         return $this->data['caches']['regions'];
  174.     }
  175.     /**
  176.      * @return array<string, int>
  177.      */
  178.     public function getCacheCounts()
  179.     {
  180.         return $this->data['caches']['counts'];
  181.     }
  182.     /**
  183.      * @return int
  184.      */
  185.     public function getInvalidEntityCount()
  186.     {
  187.         if ($this->invalidEntityCount === null) {
  188.             $this->invalidEntityCount array_sum(array_map('count'$this->data['errors']));
  189.         }
  190.         return $this->invalidEntityCount;
  191.     }
  192.     /**
  193.      * @return string[]
  194.      */
  195.     public function getGroupedQueries()
  196.     {
  197.         if ($this->groupedQueries !== null) {
  198.             return $this->groupedQueries;
  199.         }
  200.         $this->groupedQueries = [];
  201.         $totalExecutionMS     0;
  202.         foreach ($this->data['queries'] as $connection => $queries) {
  203.             $connectionGroupedQueries = [];
  204.             foreach ($queries as $i => $query) {
  205.                 $key $query['sql'];
  206.                 if (! isset($connectionGroupedQueries[$key])) {
  207.                     $connectionGroupedQueries[$key]                = $query;
  208.                     $connectionGroupedQueries[$key]['executionMS'] = 0;
  209.                     $connectionGroupedQueries[$key]['count']       = 0;
  210.                     $connectionGroupedQueries[$key]['index']       = $i// "Explain query" relies on query index in 'queries'.
  211.                 }
  212.                 $connectionGroupedQueries[$key]['executionMS'] += $query['executionMS'];
  213.                 $connectionGroupedQueries[$key]['count']++;
  214.                 $totalExecutionMS += $query['executionMS'];
  215.             }
  216.             usort($connectionGroupedQueries, static function ($a$b) {
  217.                 if ($a['executionMS'] === $b['executionMS']) {
  218.                     return 0;
  219.                 }
  220.                 return $a['executionMS'] < $b['executionMS'] ? : -1;
  221.             });
  222.             $this->groupedQueries[$connection] = $connectionGroupedQueries;
  223.         }
  224.         foreach ($this->groupedQueries as $connection => $queries) {
  225.             foreach ($queries as $i => $query) {
  226.                 $this->groupedQueries[$connection][$i]['executionPercent'] =
  227.                     $this->executionTimePercentage($query['executionMS'], $totalExecutionMS);
  228.             }
  229.         }
  230.         return $this->groupedQueries;
  231.     }
  232.     private function executionTimePercentage(int $executionTimeMSint $totalExecutionTimeMS): float
  233.     {
  234.         if ($totalExecutionTimeMS === 0.0 || $totalExecutionTimeMS === 0) {
  235.             return 0;
  236.         }
  237.         return $executionTimeMS $totalExecutionTimeMS 100;
  238.     }
  239.     /**
  240.      * @return int
  241.      */
  242.     public function getGroupedQueryCount()
  243.     {
  244.         $count 0;
  245.         foreach ($this->getGroupedQueries() as $connectionGroupedQueries) {
  246.             $count += count($connectionGroupedQueries);
  247.         }
  248.         return $count;
  249.     }
  250. }