Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[HttpKernel] Collect data from every event dispatcher #49151

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@

->set('data_collector.events', EventDataCollector::class)
->args([
service('debug.event_dispatcher')->ignoreOnInvalid(),
tagged_iterator('event_dispatcher.dispatcher', 'name'),
service('request_stack')->ignoreOnInvalid(),
])
->tag('data_collector', ['template' => '@WebProfiler/Collector/events.html.twig', 'id' => 'events', 'priority' => 290])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,76 +8,85 @@
{% endblock %}

{% block panel %}
<h2>Event Dispatcher</h2>
<h2>Dispatched Events</h2>

{% if collector.calledlisteners is empty %}
<div class="empty empty-panel">
<p>No events have been recorded. Check that debugging is enabled in the kernel.</p>
</div>
{% else %}
<div class="sf-tabs">
<div class="sf-tabs">
{% for dispatcherName, dispatcherData in collector.data %}
<div class="tab">
<h3 class="tab-title">Called Listeners <span class="badge">{{ collector.calledlisteners|length }}</span></h3>

<div class="tab-content">
{{ _self.render_table(collector.calledlisteners) }}
</div>
</div>

<div class="tab">
<h3 class="tab-title">Not Called Listeners <span class="badge">{{ collector.notcalledlisteners|length }}</span></h3>
<h3 class="tab-title">{{ dispatcherName }}</h3>
<div class="tab-content">
{% if collector.notcalledlisteners is empty %}
<div class="empty">
<p>
<strong>There are no uncalled listeners</strong>.
</p>
<p>
All listeners were called for this request or an error occurred
when trying to collect uncalled listeners (in which case check the
logs to get more information).
</p>
{% if dispatcherData['called_listeners'] is empty %}
<div class="empty empty-panel">
<p>No events have been recorded. Check that debugging is enabled in the kernel.</p>
</div>
{% else %}
{{ _self.render_table(collector.notcalledlisteners) }}
{% endif %}
</div>
</div>
<div class="sf-tabs">
<div class="tab">
<h3 class="tab-title">Called Listeners <span class="badge">{{ dispatcherData['called_listeners']|length }}</span></h3>

<div class="tab">
<h3 class="tab-title">Orphaned Events <span class="badge">{{ collector.orphanedEvents|length }}</span></h3>
<div class="tab-content">
{% if collector.orphanedEvents is empty %}
<div class="empty">
<p>
<strong>There are no orphaned events</strong>.
</p>
<p>
All dispatched events were handled or an error occurred
when trying to collect orphaned events (in which case check the
logs to get more information).
</p>
<div class="tab-content">
{{ _self.render_table(dispatcherData['called_listeners']) }}
</div>
</div>

<div class="tab">
<h3 class="tab-title">Not Called Listeners <span class="badge">{{ dispatcherData['not_called_listeners']|length }}</span></h3>
<div class="tab-content">
{% if dispatcherData['not_called_listeners'] is empty %}
<div class="empty">
<p>
<strong>There are no uncalled listeners</strong>.
</p>
<p>
All listeners were called for this request or an error occurred
when trying to collect uncalled listeners (in which case check the
logs to get more information).
</p>
</div>
{% else %}
{{ _self.render_table(dispatcherData['not_called_listeners']) }}
{% endif %}
</div>
</div>

<div class="tab">
<h3 class="tab-title">Orphaned Events <span class="badge">{{ dispatcherData['orphaned_events']|length }}</span></h3>
<div class="tab-content">
{% if dispatcherData['orphaned_events'] is empty %}
<div class="empty">
<p>
<strong>There are no orphaned events</strong>.
</p>
<p>
All dispatched events were handled or an error occurred
when trying to collect orphaned events (in which case check the
logs to get more information).
</p>
</div>
{% else %}
<table>
<thead>
<tr>
<th>Event</th>
</tr>
</thead>
<tbody>
{% for event in dispatcherData['orphaned_events'] %}
<tr>
<td class="font-normal">{{ event }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
</div>
</div>
{% else %}
<table>
<thead>
<tr>
<th>Event</th>
</tr>
</thead>
<tbody>
{% for event in collector.orphanedEvents %}
<tr>
<td class="font-normal">{{ event }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
</div>
</div>
{% endif %}
{% endfor %}
</div>
{% endblock %}

{% macro render_table(listeners) %}
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Bundle/WebProfilerBundle/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"php": ">=8.1",
"symfony/config": "^5.4|^6.0",
"symfony/framework-bundle": "^5.4|^6.0",
"symfony/http-kernel": "^6.1",
"symfony/http-kernel": "^6.3",
"symfony/routing": "^5.4|^6.0",
"symfony/twig-bundle": "^5.4|^6.0",
"twig/twig": "^2.13|^3.0.4"
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/HttpKernel/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ CHANGELOG
* Add `#[MapRequestPayload]` to map and validate request payload from `Request::getContent()` or `Request::$request->all()` to typed objects
* Add `#[MapQueryString]` to map and validate request query string from `Request::$query->all()` to typed objects
* Add `#[MapQueryParameter]` to map and validate individual query parameters to controller arguments
* Collect data from every event dispatcher

6.2
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,94 +28,110 @@
*/
class EventDataCollector extends DataCollector implements LateDataCollectorInterface
{
private ?EventDispatcherInterface $dispatcher;
private ?RequestStack $requestStack;
/** @var iterable<EventDispatcherInterface> */
private iterable $dispatchers;
private ?Request $currentRequest = null;

public function __construct(EventDispatcherInterface $dispatcher = null, RequestStack $requestStack = null)
{
$this->dispatcher = $dispatcher;
/**
* @param iterable<EventDispatcherInterface>|EventDispatcherInterface|null $dispatchers
*/
public function __construct(
iterable|EventDispatcherInterface $dispatchers = null,
private ?RequestStack $requestStack = null,
private string $defaultDispatcher = 'event_dispatcher',
) {
if ($dispatchers instanceof EventDispatcherInterface) {
$dispatchers = [$this->defaultDispatcher => $dispatchers];
}
$this->dispatchers = $dispatchers ?? [];
$this->requestStack = $requestStack;
}

public function collect(Request $request, Response $response, \Throwable $exception = null): void
{
$this->currentRequest = $this->requestStack && $this->requestStack->getMainRequest() !== $request ? $request : null;
$this->data = [
'called_listeners' => [],
'not_called_listeners' => [],
'orphaned_events' => [],
];
$this->data = [];
}

public function reset(): void
{
$this->data = [];

if ($this->dispatcher instanceof ResetInterface) {
$this->dispatcher->reset();
foreach ($this->dispatchers as $dispatcher) {
if ($dispatcher instanceof ResetInterface) {
$dispatcher->reset();
}
}
}

public function lateCollect(): void
{
if ($this->dispatcher instanceof TraceableEventDispatcher) {
$this->setCalledListeners($this->dispatcher->getCalledListeners($this->currentRequest));
$this->setNotCalledListeners($this->dispatcher->getNotCalledListeners($this->currentRequest));
$this->setOrphanedEvents($this->dispatcher->getOrphanedEvents($this->currentRequest));
foreach ($this->dispatchers as $name => $dispatcher) {
if (!$dispatcher instanceof TraceableEventDispatcher) {
continue;
}

$this->setCalledListeners($dispatcher->getCalledListeners($this->currentRequest), $name);
$this->setNotCalledListeners($dispatcher->getNotCalledListeners($this->currentRequest), $name);
$this->setOrphanedEvents($dispatcher->getOrphanedEvents($this->currentRequest), $name);
}

$this->data = $this->cloneVar($this->data);
}

public function getData(): array|Data
{
return $this->data;
}

/**
* @see TraceableEventDispatcher
*/
public function setCalledListeners(array $listeners): void
public function setCalledListeners(array $listeners, string $dispatcher = null): void
{
$this->data['called_listeners'] = $listeners;
$this->data[$dispatcher ?? $this->defaultDispatcher]['called_listeners'] = $listeners;
}

/**
* @see TraceableEventDispatcher
*/
public function getCalledListeners(): array|Data
public function getCalledListeners(string $dispatcher = null): array|Data
{
return $this->data['called_listeners'];
return $this->data[$dispatcher ?? $this->defaultDispatcher]['called_listeners'] ?? [];
}

/**
* @see TraceableEventDispatcher
*/
public function setNotCalledListeners(array $listeners): void
public function setNotCalledListeners(array $listeners, string $dispatcher = null): void
{
$this->data['not_called_listeners'] = $listeners;
$this->data[$dispatcher ?? $this->defaultDispatcher]['not_called_listeners'] = $listeners;
}

/**
* @see TraceableEventDispatcher
*/
public function getNotCalledListeners(): array|Data
public function getNotCalledListeners(string $dispatcher = null): array|Data
{
return $this->data['not_called_listeners'];
return $this->data[$dispatcher ?? $this->defaultDispatcher]['not_called_listeners'] ?? [];
}

/**
* @param array $events An array of orphaned events
*
* @see TraceableEventDispatcher
*/
public function setOrphanedEvents(array $events): void
public function setOrphanedEvents(array $events, string $dispatcher = null): void
{
$this->data['orphaned_events'] = $events;
$this->data[$dispatcher ?? $this->defaultDispatcher]['orphaned_events'] = $events;
}

/**
* @see TraceableEventDispatcher
*/
public function getOrphanedEvents(): array|Data
public function getOrphanedEvents(string $dispatcher = null): array|Data
{
return $this->data['orphaned_events'];
return $this->data[$dispatcher ?? $this->defaultDispatcher]['orphaned_events'] ?? [];
}

public function getName(): string
Expand Down