Skip to content

Commit 39a16e6

Browse files
committed
Merge branch '6.2' into 6.3
* 6.2: Minor: Removing code line Minor Consolidate profiler docs
2 parents 9caea11 + a8fd5ee commit 39a16e6

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
@@ -216,11 +216,305 @@ event::
216216
$response = $event->getResponse();
217217
$response->headers->set('Symfony-Debug-Toolbar-Replace', 1);
218218
}
219+
.. index::
220+
single: Profiling; Data collector
219221

220-
.. toctree::
221-
:hidden:
222+
.. _profiler-data-collector:
222223

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

0 commit comments

Comments
 (0)