mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 09:02:12 +00:00
feature #10990 Template events system - data collector & profiler (pamil)
This PR was merged into the 1.7-dev branch. Discussion ---------- | Q | A | --------------- | ----- | Branch? | - | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Related tickets | related to #10924 | License | MIT Added data collector for template events & blocks: <img width="1068" alt="Screenshot 2019-12-27 at 20 12 40" src="https://user-images.githubusercontent.com/1897953/71530508-5f076580-28ea-11ea-90df-e6b5b04d452d.png"> <img width="1261" alt="Screenshot 2019-12-27 at 20 12 17" src="https://user-images.githubusercontent.com/1897953/71530509-5f076580-28ea-11ea-9b37-f194f4895945.png"> <img width="323" alt="Screenshot 2019-12-31 at 14 46 18" src="https://user-images.githubusercontent.com/1897953/71623372-607fa900-2bdc-11ea-95d5-3c237727fe6d.png"> All the added classes are internal and the code is a real MVP 🎉 TODO: - [x] Get our own icon for the debug toolbar, do not steal it from SonataBlock :D Commits -------d917f2d088Add template events data collectorf4c32cd8fdAdd a dedicated icon for template events data collector
This commit is contained in:
commit
c815e4c506
9 changed files with 374 additions and 0 deletions
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\UiBundle\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class TemplateBlockDataCollector extends DataCollector
|
||||
{
|
||||
/** @var TemplateBlockRenderingHistory */
|
||||
private $templateBlockRenderingHistory;
|
||||
|
||||
public function __construct(TemplateBlockRenderingHistory $templateBlockRenderingHistory)
|
||||
{
|
||||
$this->templateBlockRenderingHistory = $templateBlockRenderingHistory;
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
public function collect(Request $request, Response $response): void
|
||||
{
|
||||
$this->data['renderedEvents'] = $this->templateBlockRenderingHistory->getRenderedEvents();
|
||||
}
|
||||
|
||||
public function getRenderedEvents(): array
|
||||
{
|
||||
return $this->data['renderedEvents'];
|
||||
}
|
||||
|
||||
public function getNumberOfRenderedEvents(): int
|
||||
{
|
||||
return count($this->data['renderedEvents']);
|
||||
}
|
||||
|
||||
public function getNumberOfRenderedBlocks(): int
|
||||
{
|
||||
return array_reduce($this->data['renderedEvents'], static function (int $accumulator, array $event): int {
|
||||
return $accumulator + count($event['blocks']);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
public function getTotalDuration(): float
|
||||
{
|
||||
return array_reduce($this->data['renderedEvents'], static function (float $accumulator, array $event): float {
|
||||
return $accumulator + $event['time'];
|
||||
}, 0.0);
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'sylius_ui.template_block';
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
$this->data['renderedEvents'] = [];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\UiBundle\DataCollector;
|
||||
|
||||
use Sylius\Bundle\UiBundle\Registry\TemplateBlock;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class TemplateBlockRenderingHistory
|
||||
{
|
||||
/** @psalm-var list<array{name: string, start: float, stop: float, time: float, blocks: list<array{definition: TemplateBlock, start: float, stop: float, time: float}>}> */
|
||||
private $renderedEvents = [];
|
||||
|
||||
/** @psalm-var array{name: string, start: float, stop?: float, time?: float, blocks: list<array{definition: TemplateBlock, start: float, stop: float, time: float}>} */
|
||||
private $currentlyRenderedEvent = [];
|
||||
|
||||
/** @psalm-var array{definition: TemplateBlock, start: float, stop?: float, time?: float} */
|
||||
private $currentlyRenderedBlock = [];
|
||||
|
||||
public function startRenderingEvent(string $eventName, array $context): void
|
||||
{
|
||||
$this->currentlyRenderedEvent = ['name' => $eventName, 'start' => microtime(true), 'blocks' => []];
|
||||
}
|
||||
|
||||
public function startRenderingBlock(string $eventName, TemplateBlock $templateBlock, array $context): void
|
||||
{
|
||||
$this->currentlyRenderedBlock = ['definition' => $templateBlock, 'start' => microtime(true)];
|
||||
}
|
||||
|
||||
public function stopRenderingBlock(string $eventName, TemplateBlock $templateBlock, array $context): void
|
||||
{
|
||||
$this->currentlyRenderedBlock['stop'] = microtime(true);
|
||||
$this->currentlyRenderedBlock['time'] = $this->currentlyRenderedBlock['stop'] - $this->currentlyRenderedBlock['start'];
|
||||
$this->currentlyRenderedEvent['blocks'][] = $this->currentlyRenderedBlock;
|
||||
$this->currentlyRenderedBlock = [];
|
||||
}
|
||||
|
||||
public function stopRenderingEvent(string $eventName, array $context): void
|
||||
{
|
||||
$this->currentlyRenderedEvent['stop'] = microtime(true);
|
||||
$this->currentlyRenderedEvent['time'] = $this->currentlyRenderedEvent['stop'] - $this->currentlyRenderedEvent['start'];
|
||||
$this->renderedEvents[] = $this->currentlyRenderedEvent;
|
||||
$this->currentlyRenderedEvent = [];
|
||||
}
|
||||
|
||||
public function getRenderedEvents(): array
|
||||
{
|
||||
return $this->renderedEvents;
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
$this->renderedEvents = $this->currentlyRenderedEvent = $this->currentlyRenderedBlock = [];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\UiBundle\DataCollector;
|
||||
|
||||
use Sylius\Bundle\UiBundle\Registry\TemplateBlock;
|
||||
use Sylius\Bundle\UiBundle\Renderer\TemplateBlockRendererInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class TraceableTemplateBlockRenderer implements TemplateBlockRendererInterface
|
||||
{
|
||||
/** @var TemplateBlockRendererInterface */
|
||||
private $templateBlockRenderer;
|
||||
|
||||
/** @var TemplateBlockRenderingHistory */
|
||||
private $templateBlockRenderingHistory;
|
||||
|
||||
public function __construct(TemplateBlockRendererInterface $templateBlockRenderer, TemplateBlockRenderingHistory $templateBlockRenderingHistory)
|
||||
{
|
||||
$this->templateBlockRenderer = $templateBlockRenderer;
|
||||
$this->templateBlockRenderingHistory = $templateBlockRenderingHistory;
|
||||
}
|
||||
|
||||
public function render(string $eventName, TemplateBlock $templateBlock, array $context = []): string
|
||||
{
|
||||
$this->templateBlockRenderingHistory->startRenderingBlock($eventName, $templateBlock, $context);
|
||||
|
||||
$renderedBlock = $this->templateBlockRenderer->render($eventName, $templateBlock, $context);
|
||||
|
||||
$this->templateBlockRenderingHistory->stopRenderingBlock($eventName, $templateBlock, $context);
|
||||
|
||||
return $renderedBlock;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\UiBundle\DataCollector;
|
||||
|
||||
use Sylius\Bundle\UiBundle\Renderer\TemplateEventRendererInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class TraceableTemplateEventRenderer implements TemplateEventRendererInterface
|
||||
{
|
||||
/** @var TemplateEventRendererInterface */
|
||||
private $templateEventRenderer;
|
||||
|
||||
/** @var TemplateBlockRenderingHistory */
|
||||
private $templateBlockRenderingHistory;
|
||||
|
||||
public function __construct(TemplateEventRendererInterface $templateEventRenderer, TemplateBlockRenderingHistory $templateBlockRenderingHistory)
|
||||
{
|
||||
$this->templateEventRenderer = $templateEventRenderer;
|
||||
$this->templateBlockRenderingHistory = $templateBlockRenderingHistory;
|
||||
}
|
||||
|
||||
public function render(string $eventName, array $context = []): string
|
||||
{
|
||||
$this->templateBlockRenderingHistory->startRenderingEvent($eventName, $context);
|
||||
|
||||
$renderedEvent = $this->templateEventRenderer->render($eventName, $context);
|
||||
|
||||
$this->templateBlockRenderingHistory->stopRenderingEvent($eventName, $context);
|
||||
|
||||
return $renderedEvent;
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,10 @@ final class SyliusUiExtension extends Extension
|
|||
|
||||
$loader->load('services.xml');
|
||||
|
||||
if ($container->getParameter('kernel.debug')) {
|
||||
$loader->load('services/debug/template_event.xml');
|
||||
}
|
||||
|
||||
$this->loadEvents($config['events'], $container);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
|
||||
This file is part of the Sylius package.
|
||||
|
||||
(c) Paweł Jędrzejewski
|
||||
|
||||
For the full copyright and license information, please view the LICENSE
|
||||
file that was distributed with this source code.
|
||||
|
||||
-->
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
<services>
|
||||
<service id="Sylius\Bundle\UiBundle\DataCollector\TemplateBlockRenderingHistory" />
|
||||
|
||||
<service id="Sylius\Bundle\UiBundle\DataCollector\TemplateBlockDataCollector">
|
||||
<argument type="service" id="Sylius\Bundle\UiBundle\DataCollector\TemplateBlockRenderingHistory" />
|
||||
<tag name="data_collector" template="@SyliusUi/DataCollector/templateBlock.html.twig" id="sylius_ui.template_block" />
|
||||
</service>
|
||||
|
||||
<service id="Sylius\Bundle\UiBundle\DataCollector\TraceableTemplateBlockRenderer" decorates="Sylius\Bundle\UiBundle\Renderer\TemplateBlockRendererInterface">
|
||||
<argument type="service" id="Sylius\Bundle\UiBundle\DataCollector\TraceableTemplateBlockRenderer.inner" />
|
||||
<argument type="service" id="Sylius\Bundle\UiBundle\DataCollector\TemplateBlockRenderingHistory" />
|
||||
</service>
|
||||
|
||||
<service id="Sylius\Bundle\UiBundle\DataCollector\TraceableTemplateEventRenderer" decorates="Sylius\Bundle\UiBundle\Renderer\TemplateEventRendererInterface">
|
||||
<argument type="service" id="Sylius\Bundle\UiBundle\DataCollector\TraceableTemplateEventRenderer.inner" />
|
||||
<argument type="service" id="Sylius\Bundle\UiBundle\DataCollector\TemplateBlockRenderingHistory" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<!-- Icon by fontawesome.com, color modified to #AAAAAA, https://fontawesome.com/license -->
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="stream" class="svg-inline--fa fa-stream fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#AAAAAA" d="M16 128h416c8.84 0 16-7.16 16-16V48c0-8.84-7.16-16-16-16H16C7.16 32 0 39.16 0 48v64c0 8.84 7.16 16 16 16zm480 80H80c-8.84 0-16 7.16-16 16v64c0 8.84 7.16 16 16 16h416c8.84 0 16-7.16 16-16v-64c0-8.84-7.16-16-16-16zm-64 176H16c-8.84 0-16 7.16-16 16v64c0 8.84 7.16 16 16 16h416c8.84 0 16-7.16 16-16v-64c0-8.84-7.16-16-16-16z"></path></svg>
|
||||
|
After Width: | Height: | Size: 641 B |
|
|
@ -0,0 +1,101 @@
|
|||
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
|
||||
|
||||
{% block toolbar %}
|
||||
<div class="sf-toolbar-block">
|
||||
<a href="{{ path('_profiler', { 'token': token, 'panel': name }) }}">
|
||||
<div class="sf-toolbar-icon">
|
||||
{{ include('@SyliusUi/DataCollector/icon.svg') }}
|
||||
<span class="sf-toolbar-value">{{ collector.numberOfRenderedEvents }}</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<div class="sf-toolbar-info">
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>Rendered events</b>
|
||||
<span class="sf-toolbar-status">{{ collector.numberOfRenderedEvents }}</span>
|
||||
</div>
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>Rendered blocks</b>
|
||||
<span class="sf-toolbar-status">{{ collector.numberOfRenderedBlocks }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block menu %}
|
||||
<span class="label">
|
||||
<span class="icon">
|
||||
{{ include('@SyliusUi/DataCollector/icon.svg') }}
|
||||
</span>
|
||||
<strong>Template events</strong>
|
||||
<span class="count">
|
||||
<span>{{ collector.numberOfRenderedEvents }}</span>
|
||||
</span>
|
||||
</span>
|
||||
{% endblock %}
|
||||
|
||||
{% block panel %}
|
||||
<h2>Template events metrics</h2>
|
||||
|
||||
<div class="metrics">
|
||||
<div class="metric">
|
||||
<span class="value">{{ '%.0f'|format(collector.totalDuration * 1000) }} <span class="unit">ms</span></span>
|
||||
<span class="label">Total execution time</span>
|
||||
</div>
|
||||
|
||||
<div class="metric">
|
||||
<span class="value">{{ '%.0f'|format(collector.numberOfRenderedEvents) }}</span>
|
||||
<span class="label">Rendered events</span>
|
||||
</div>
|
||||
|
||||
<div class="metric">
|
||||
<span class="value">{{ '%.0f'|format(collector.numberOfRenderedBlocks) }}</span>
|
||||
<span class="label">Rendered blocks</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Rendered template events</h2>
|
||||
|
||||
{% if collector.renderedEvents|length > 0 %}
|
||||
<table>
|
||||
<tr>
|
||||
<th>Event</th>
|
||||
<th>Duration</th>
|
||||
<th>Blocks</th>
|
||||
</tr>
|
||||
|
||||
{% for event in collector.renderedEvents %}
|
||||
<tr>
|
||||
<td>{{ event.name }}</td>
|
||||
<td>{{ '%.0f'|format(event.time * 1000) }}ms</td>
|
||||
<td>
|
||||
{% if event.blocks|length > 0 %}
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Template</th>
|
||||
<th>Duration</th>
|
||||
<th>Priority</th>
|
||||
</tr>
|
||||
{% for block in event.blocks %}
|
||||
<tr>
|
||||
<td>{{ block.definition.name }}</td>
|
||||
<td>{{ block.definition.template }}</td>
|
||||
<td>{{ '%.0f'|format(block.time * 1000) }}ms</td>
|
||||
<td>{{ block.definition.priority }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<i>no blocks rendered</i>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="empty">
|
||||
No template events have been rendered.
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
@ -24,6 +24,8 @@ final class SyliusUiExtensionTest extends AbstractExtensionTestCase
|
|||
/** @test */
|
||||
public function it_configures_the_multiple_event_block_listener_service_with_events_and_blocks_data(): void
|
||||
{
|
||||
$this->container->setParameter('kernel.debug', true);
|
||||
|
||||
$this->load(['events' => [
|
||||
'first_event' => ['blocks' => [
|
||||
'first_block' => ['template' => 'first.html.twig', 'context' => [], 'enabled' => true, 'priority' => 0],
|
||||
|
|
@ -52,6 +54,8 @@ final class SyliusUiExtensionTest extends AbstractExtensionTestCase
|
|||
/** @test */
|
||||
public function it_sorts_blocks_by_their_priority_and_uses_fifo_ordering(): void
|
||||
{
|
||||
$this->container->setParameter('kernel.debug', true);
|
||||
|
||||
$this->load(['events' => [
|
||||
'event_name' => ['blocks' => [
|
||||
'fourth_block' => ['template' => 'fourth.html.twig', 'context' => [], 'enabled' => true, 'priority' => -5],
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue