Skip to content

Commit a8fd5ee

Browse files
committed
Merge branch '5.4' into 6.2
* 5.4: Minor: Removing code line Minor Consolidate profiler docs
2 parents bcb20fb + 993d960 commit a8fd5ee

File tree

7 files changed

+305
-311
lines changed

7 files changed

+305
-311
lines changed

_build/redirection_map

Lines changed: 2 additions & 1 deletion
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

mailer.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ the ``TemplatedEmail`` class:
740740

741741
.. code-block:: diff
742742
743-
+ use Symfony\Bridge\Twig\Mime\TemplatedEmail;
743+
+use Symfony\Bridge\Twig\Mime\TemplatedEmail;
744744
745745
$email = (new TemplatedEmail())
746746
// ...

profiler.rst

Lines changed: 297 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,11 +207,305 @@ event::
207207
$response = $event->getResponse();
208208
$response->headers->set('Symfony-Debug-Toolbar-Replace', 1);
209209
}
210+
.. index::
211+
single: Profiling; Data collector
210212

211-
.. toctree::
212-
:hidden:
213+
.. _profiler-data-collector:
213214

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

0 commit comments

Comments
 (0)