Skip to content

Commit bf6c858

Browse files
committed
minor #17834 [Profiler] Consolidate profiler docs (fabpot)
This PR was merged into the 5.4 branch. Discussion ---------- [Profiler] Consolidate profiler docs <!-- If your pull request fixes a BUG, use the oldest maintained branch that contains the bug (see https://symfony.com/releases for the list of maintained branches). If your pull request documents a NEW FEATURE, use the same Symfony branch where the feature was introduced (and `6.x` for features of unreleased versions). --> Commits ------- f5d8216 Consolidate profiler docs
2 parents 9041533 + f5d8216 commit bf6c858

File tree

5 files changed

+306
-311
lines changed

5 files changed

+306
-311
lines changed

_build/redirection_map

+2-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,8 @@
190190
/cookbook/logging/monolog_console /logging/monolog_console
191191
/cookbook/logging/monolog_email /logging/monolog_email
192192
/cookbook/logging/monolog_regex_based_excludes /logging/monolog_regex_based_excludes
193-
/cookbook/profiler/data_collector /profiler/data_collector
193+
/cookbook/profiler/data_collector /profiler#profiler-data-collector
194+
/profiler/data_collector /profiler#profiler-data-collector
194195
/cookbook/profiler/index /profiler
195196
/cookbook/profiler/matchers /profiler/matchers
196197
/cookbook/profiler/profiling_data /profiler/profiling_data

profiler.rst

+301-3
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,309 @@ event::
211211
$response = $event->getResponse();
212212
$response->headers->set('Symfony-Debug-Toolbar-Replace', 1);
213213
}
214+
.. index::
215+
single: Profiling; Data collector
214216

215-
.. toctree::
216-
:hidden:
217+
.. _profiler-data-collector:
217218

218-
profiler/data_collector
219+
Creating a Data Collector
220+
=========================
221+
222+
The Symfony Profiler obtains its profiling and debug information using some
223+
special classes called data collectors. Symfony comes bundled with a few of
224+
them, but you can also create your own.
225+
226+
A data collector is a PHP class that implements the
227+
:class:`Symfony\\Component\\HttpKernel\\DataCollector\\DataCollectorInterface`.
228+
For convenience, your data collectors can also extend from the
229+
:class:`Symfony\\Bundle\\FrameworkBundle\\DataCollector\\AbstractDataCollector`
230+
class, which implements the interface and provides some utilities and the
231+
``$this->data`` property to store the collected information.
232+
233+
.. versionadded:: 5.2
234+
235+
The ``AbstractDataCollector`` class was introduced in Symfony 5.2.
236+
237+
The following example shows a custom collector that stores information about the
238+
request::
239+
240+
// src/DataCollector/RequestCollector.php
241+
namespace App\DataCollector;
242+
243+
use Symfony\Bundle\FrameworkBundle\DataCollector\AbstractDataCollector;
244+
use Symfony\Component\HttpFoundation\Request;
245+
use Symfony\Component\HttpFoundation\Response;
246+
247+
class RequestCollector extends AbstractDataCollector
248+
{
249+
public function collect(Request $request, Response $response, \Throwable $exception = null)
250+
{
251+
$this->data = [
252+
'method' => $request->getMethod(),
253+
'acceptable_content_types' => $request->getAcceptableContentTypes(),
254+
];
255+
}
256+
}
257+
258+
These are the method that you can define in the data collector class:
259+
260+
:method:`Symfony\\Component\\HttpKernel\\DataCollector\\DataCollectorInterface::collect` method:
261+
Stores the collected data in local properties (``$this->data`` if you extend
262+
from ``AbstractDataCollector``). If you need some services to collect the
263+
data, inject those services in the data collector constructor.
264+
265+
.. caution::
266+
267+
The ``collect()`` method is only called once. It is not used to "gather"
268+
data but is there to "pick up" the data that has been stored by your
269+
service.
270+
271+
.. caution::
272+
273+
As the profiler serializes data collector instances, you should not
274+
store objects that cannot be serialized (like PDO objects) or you need
275+
to provide your own ``serialize()`` method.
276+
277+
:method:`Symfony\\Component\\HttpKernel\\DataCollector\\DataCollectorInterface::reset` method:
278+
It's called between requests to reset the state of the profiler. By default
279+
it only empties the ``$this->data`` contents, but you can override this method
280+
to do additional cleaning.
281+
282+
:method:`Symfony\\Component\\HttpKernel\\DataCollector\\DataCollectorInterface::getName` method:
283+
Returns the collector identifier, which must be unique in the application.
284+
By default it returns the FQCN of the data collector class, but you can
285+
override this method to return a custom name (e.g. ``app.request_collector``).
286+
This value is used later to access the collector information (see
287+
:doc:`/testing/profiling`) so you may prefer using short strings instead of FQCN strings.
288+
289+
The ``collect()`` method is called during the :ref:`kernel.response <component-http-kernel-kernel-response>`
290+
event. If you need to collect data that is only available later, implement
291+
:class:`Symfony\\Component\\HttpKernel\\DataCollector\\LateDataCollectorInterface`
292+
and define the ``lateCollect()`` method, which is invoked right before the profiler
293+
data serialization (during :ref:`kernel.terminate <component-http-kernel-kernel-terminate>` event).
294+
295+
.. note::
296+
297+
If you're using the :ref:`default services.yaml configuration <service-container-services-load-example>`
298+
with ``autoconfigure``, then Symfony will start using your data collector after the
299+
next page refresh. Otherwise, :ref:`enable the data collector by hand <data_collector_tag>`.
300+
301+
Adding Web Profiler Templates
302+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
303+
304+
The information collected by your data collector can be displayed both in the
305+
web debug toolbar and in the web profiler. To do so, you need to create a Twig
306+
template that includes some specific blocks.
307+
308+
First, add the ``getTemplate()`` method in your data collector class to return
309+
the path of the Twig template to use. Then, add some *getters* to give the
310+
template access to the collected information::
311+
312+
// src/DataCollector/RequestCollector.php
313+
namespace App\DataCollector;
314+
315+
use Symfony\Bundle\FrameworkBundle\DataCollector\AbstractDataCollector;
316+
317+
class RequestCollector extends AbstractDataCollector
318+
{
319+
// ...
320+
321+
public static function getTemplate(): ?string
322+
{
323+
return 'data_collector/template.html.twig';
324+
}
325+
326+
public function getMethod()
327+
{
328+
return $this->data['method'];
329+
}
330+
331+
public function getAcceptableContentTypes()
332+
{
333+
return $this->data['acceptable_content_types'];
334+
}
335+
}
336+
337+
In the simplest case, you want to display the information in the toolbar
338+
without providing a profiler panel. This requires to define the ``toolbar``
339+
block and set the value of two variables called ``icon`` and ``text``:
340+
341+
.. code-block:: html+twig
342+
343+
{# templates/data_collector/template.html.twig #}
344+
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
345+
346+
{% block toolbar %}
347+
{% set icon %}
348+
{# this is the content displayed as a panel in the toolbar #}
349+
<svg xmlns="http://www.w3.org/2000/svg"> ... </svg>
350+
<span class="sf-toolbar-value">Request</span>
351+
{% endset %}
352+
353+
{% set text %}
354+
{# this is the content displayed when hovering the mouse over
355+
the toolbar panel #}
356+
<div class="sf-toolbar-info-piece">
357+
<b>Method</b>
358+
<span>{{ collector.method }}</span>
359+
</div>
360+
361+
<div class="sf-toolbar-info-piece">
362+
<b>Accepted content type</b>
363+
<span>{{ collector.acceptableContentTypes|join(', ') }}</span>
364+
</div>
365+
{% endset %}
366+
367+
{# the 'link' value set to 'false' means that this panel doesn't
368+
show a section in the web profiler #}
369+
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: false }) }}
370+
{% endblock %}
371+
372+
.. tip::
373+
374+
Built-in collector templates define all their images as embedded SVG files.
375+
This makes them work everywhere without having to mess with web assets links:
376+
377+
.. code-block:: twig
378+
379+
{% set icon %}
380+
{{ include('data_collector/icon.svg') }}
381+
{# ... #}
382+
{% endset %}
383+
384+
If the toolbar panel includes extended web profiler information, the Twig template
385+
must also define additional blocks:
386+
387+
.. code-block:: html+twig
388+
389+
{# templates/data_collector/template.html.twig #}
390+
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
391+
392+
{% block toolbar %}
393+
{% set icon %}
394+
{# ... #}
395+
{% endset %}
396+
397+
{% set text %}
398+
<div class="sf-toolbar-info-piece">
399+
{# ... #}
400+
</div>
401+
{% endset %}
402+
403+
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { 'link': true }) }}
404+
{% endblock %}
405+
406+
{% block head %}
407+
{# Optional. Here you can link to or define your own CSS and JS contents. #}
408+
{# Use {{ parent() }} to extend the default styles instead of overriding them. #}
409+
{% endblock %}
410+
411+
{% block menu %}
412+
{# This left-hand menu appears when using the full-screen profiler. #}
413+
<span class="label">
414+
<span class="icon"><img src="..." alt=""/></span>
415+
<strong>Request</strong>
416+
</span>
417+
{% endblock %}
418+
419+
{% block panel %}
420+
{# Optional, for showing the most details. #}
421+
<h2>Acceptable Content Types</h2>
422+
<table>
423+
<tr>
424+
<th>Content Type</th>
425+
</tr>
426+
427+
{% for type in collector.acceptableContentTypes %}
428+
<tr>
429+
<td>{{ type }}</td>
430+
</tr>
431+
{% endfor %}
432+
</table>
433+
{% endblock %}
434+
435+
The ``menu`` and ``panel`` blocks are the only required blocks to define the
436+
contents displayed in the web profiler panel associated with this data collector.
437+
All blocks have access to the ``collector`` object.
438+
439+
.. note::
440+
441+
The position of each panel in the toolbar is determined by the collector
442+
priority, which can only be defined when :ref:`configuring the data collector by hand <data_collector_tag>`.
443+
444+
.. note::
445+
446+
If you're using the :ref:`default services.yaml configuration <service-container-services-load-example>`
447+
with ``autoconfigure``, then Symfony will start displaying your collector data
448+
in the toolbar after the next page refresh. Otherwise, :ref:`enable the data collector by hand <data_collector_tag>`.
449+
450+
.. _data_collector_tag:
451+
452+
Enabling Custom Data Collectors
453+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
454+
455+
If you don't use Symfony's default configuration with
456+
:ref:`autowire and autoconfigure <service-container-services-load-example>`
457+
you'll need to configure the data collector explicitly:
458+
459+
.. configuration-block::
460+
461+
.. code-block:: yaml
462+
463+
# config/services.yaml
464+
services:
465+
App\DataCollector\RequestCollector:
466+
tags:
467+
-
468+
name: data_collector
469+
# must match the value returned by the getName() method
470+
id: 'App\DataCollector\RequestCollector'
471+
# optional template (it has more priority than the value returned by getTemplate())
472+
template: 'data_collector/template.html.twig'
473+
# optional priority (positive or negative integer; default = 0)
474+
# priority: 300
475+
476+
.. code-block:: xml
477+
478+
<!-- config/services.xml -->
479+
<?xml version="1.0" encoding="UTF-8" ?>
480+
<container xmlns="http://symfony.com/schema/dic/services"
481+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
482+
xsi:schemaLocation="http://symfony.com/schema/dic/services
483+
https://symfony.com/schema/dic/services/services-1.0.xsd">
484+
485+
<services>
486+
<service id="App\DataCollector\RequestCollector">
487+
<!-- the 'template' attribute has more priority than the value returned by getTemplate() -->
488+
<tag name="data_collector"
489+
id="App\DataCollector\RequestCollector"
490+
template="data_collector/template.html.twig"
491+
/>
492+
<!-- optional 'priority' attribute (positive or negative integer; default = 0) -->
493+
<!-- priority="300" -->
494+
</service>
495+
</services>
496+
</container>
497+
498+
.. code-block:: php
499+
500+
// config/services.php
501+
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
502+
503+
use App\DataCollector\RequestCollector;
504+
505+
return function(ContainerConfigurator $containerConfigurator) {
506+
$services = $containerConfigurator->services();
507+
508+
$services->set(RequestCollector::class)
509+
->tag('data_collector', [
510+
'id' => RequestCollector::class,
511+
// optional template (it has more priority than the value returned by getTemplate())
512+
'template' => 'data_collector/template.html.twig',
513+
// optional priority (positive or negative integer; default = 0)
514+
// 'priority' => 300,
515+
]);
516+
};
219517
220518
.. _`Single-page applications`: https://en.wikipedia.org/wiki/Single-page_application
221519
.. _`Blackfire`: https://blackfire.io/docs/introduction?utm_source=symfony&utm_medium=symfonycom_docs&utm_campaign=profiler

0 commit comments

Comments
 (0)