webprofiler-10.0.x-dev/src/DataCollector/EventsDataCollector.php

src/DataCollector/EventsDataCollector.php
<?php

declare(strict_types=1);

namespace Drupal\webprofiler\DataCollector;

use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\tracer\EventDispatcher\EventDispatcherTraceableInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;

/**
 * Collects events data.
 */
class EventsDataCollector extends DataCollector implements LateDataCollectorInterface, HasPanelInterface {

  use StringTranslationTrait, DataCollectorTrait, PanelTrait;

  /**
   * EventsDataCollector constructor.
   *
   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $eventDispatcher
   *   The event dispatcher.
   */
  public function __construct(
    private readonly EventDispatcherInterface $eventDispatcher,
  ) {
  }

  /**
   * {@inheritdoc}
   */
  public function getName() {
    return 'events';
  }

  /**
   * {@inheritdoc}
   */
  public function collect(Request $request, Response $response, ?\Throwable $exception = NULL): void {
    $this->data = [
      'called_listeners' => [],
      'called_listeners_count' => 0,
      'not_called_listeners' => [],
      'not_called_listeners_count' => 0,
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function lateCollect() {
    if ($this->eventDispatcher instanceof EventDispatcherTraceableInterface) {
      $count_called = 0;
      $called_listeners = $this->eventDispatcher->getCalledListeners();
      foreach ($called_listeners as &$called_events) {
        foreach ($called_events as &$priority) {
          foreach ($priority as &$listener) {
            $count_called++;
            $listener['clazz'] = $this->getMethodData($listener['class'], $listener['method']);
          }
        }
      }

      $this->data['called_listeners'] = $called_listeners;
      $this->data['called_listeners_count'] = $count_called;

      $count_not_called = 0;
      $not_called_listeners = $this->eventDispatcher->getNotCalledListeners();
      foreach ($not_called_listeners as $not_called_events) {
        foreach ($not_called_events as $not_priority) {
          $count_not_called += \count($not_priority);
        }
      }

      $this->data['not_called_listeners'] = $not_called_listeners;
      $this->data['not_called_listeners_count'] = $count_not_called;
    }
  }

  /**
   * Reset the collected data.
   */
  public function reset(): void {
    $this->data = [];
  }

  /**
   * Return an array of all the events that have been dispatched.
   *
   * @return array
   *   An array of all the events that have been dispatched.
   */
  public function getCalledListeners(): array {
    return $this->data['called_listeners'];
  }

  /**
   * Return an array of all the events that have not been dispatched.
   *
   * @return array
   *   An array of all the events that have not been dispatched.
   */
  public function getNotCalledListeners(): array {
    return $this->data['not_called_listeners'];
  }

  /**
   * Return the count of the events that have been dispatched.
   *
   * @return int
   *   The count of the events that have been dispatched.
   */
  public function getCalledListenersCount(): int {
    return $this->data['called_listeners_count'];
  }

  /**
   * Return the count of the events that have not been dispatched.
   *
   * @return int
   *   The count of the events that have not been dispatched.
   */
  public function getNotCalledListenersCount(): int {
    return $this->data['not_called_listeners_count'];
  }

  /**
   * {@inheritdoc}
   */
  public function getPanel(): array {
    $tabs = [
      [
        'label' => 'Called listeners',
        'content' => $this->renderListeners($this->getCalledListeners(), 'Called listeners', TRUE),
      ],
      [
        'label' => 'Not called listeners',
        'content' => $this->renderListeners($this->getNotCalledListeners(), 'Not called listeners', FALSE),
      ],
    ];

    return [
      '#theme' => 'webprofiler_dashboard_tabs',
      '#tabs' => $tabs,
    ];
  }

  /**
   * Render a list of listeners.
   *
   * @param array $listeners
   *   The list of listeners to render.
   * @param string $label
   *   The list's label.
   * @param bool $called
   *   TRUE if the table is for called listeners, FALSE otherwise.
   *
   * @return array
   *   The render array of the list of blocks.
   */
  private function renderListeners(array $listeners, string $label, bool $called): array {
    if (\count($listeners) == 0) {
      return [
        $label => [
          '#markup' => '<p>' . $this->t('No @label listeners collected',
              ['@label' => $label]) . '</p>',
        ],
      ];
    }

    $rows = [];
    foreach ($listeners as $name => $priorities) {
      foreach ($priorities as $priority => $subscribers) {
        foreach ($subscribers as $subscriber) {
          $rows[] = [
            $name,
            [
              'data' => [
                '#type' => 'inline_template',
                '#template' => '{{ data|raw }}',
                '#context' => [
                  'data' => $this->classLink($subscriber),
                ],
              ],
              'class' => 'webprofiler__value',
            ],
            $priority,
          ];
        }
      }
    }

    return [
      $label => [
        '#theme' => 'webprofiler_dashboard_section',
        '#data' => [
          '#type' => 'table',
          '#header' => [
            $this->t('Called listeners'),
            $called ? $this->t('Class') : $this->t('Service'),
            $this->t('Priority'),
          ],
          '#rows' => $rows,
          '#attributes' => [
            'class' => [
              'webprofiler__table',
            ],
          ],
          '#sticky' => TRUE,
        ],
      ],
    ];
  }

  /**
   * Render the link to a class.
   *
   * The class can be a regular class, a service or a closure.
   *
   * @param array $subscriber
   *   Event subscriber data.
   *
   * @return array
   *   A render array of the link to the class.
   */
  private function classLink(array $subscriber): array {
    if (isset($subscriber['class'])) {
      if ($subscriber['class'] == 'Closure') {
        return [
          '#markup' => $this->t('Closure'),
        ];
      }
      else {
        return $this->renderClassLinkFromMethodData($subscriber['clazz']);
      }
    }

    return [
      '#markup' => \sprintf('%s::%s', $subscriber['service'][0], $subscriber['service'][1]),
    ];
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc