Skip to content

Commit da4893b

Browse files
committed
feature #5592 Updated the article about data collectors (javiereguiluz)
This PR was merged into the 2.3 branch. Discussion ---------- Updated the article about data collectors | Q | A | ------------- | --- | Doc fix? | yes | New docs? | yes | Applies to | all | Fixed tickets | - First, the existing contents have been updated with the usual "modern Symfony treatment" (AppBundle, short services names, etc.) Second, some explanations have been expanded and some features are newly explained, like the data collector priority. If this PR is accepted, I'll submit a new one for 2.8 with all the new things to consider for the redesigned toolbar. Commits ------- 69bd677 Fixed some issues 93bd994 Tweaks and fixes e3a80a4 Implemented all suggestions f1de079 Updated the article about data collectors
2 parents 21ec4fd + 69bd677 commit da4893b

File tree

1 file changed

+172
-71
lines changed

1 file changed

+172
-71
lines changed

cookbook/profiler/data_collector.rst

Lines changed: 172 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
How to Create a custom Data Collector
55
=====================================
66

7-
:doc:`The Symfony Profiler </cookbook/profiler/index>` delegates data collecting to
8-
data collectors. Symfony comes bundled with a few of them, but you can easily
9-
create your own.
7+
:doc:`The Symfony Profiler </cookbook/profiler/index>` delegates data collection
8+
to some special classes called data collectors. Symfony comes bundled with a few
9+
of them, but you can easily create your own.
1010

1111
Creating a custom Data Collector
1212
--------------------------------
@@ -33,12 +33,12 @@ Creating a custom data collector is as simple as implementing the
3333
function getName();
3434
}
3535

36-
The ``getName()`` method must return a unique name. This is used to access the
37-
information later on (see :doc:`/cookbook/testing/profiling` for
38-
instance).
36+
The value returned by ``getName()`` must be unique in the application. This value
37+
is also used to access the information later on (see :doc:`/cookbook/testing/profiling`
38+
for instance).
3939

40-
The ``collect()`` method is responsible for storing the data it wants to give
41-
access to in local properties.
40+
The ``collect()`` method is responsible for storing the collected data in local
41+
properties.
4242

4343
.. caution::
4444

@@ -51,101 +51,169 @@ Most of the time, it is convenient to extend
5151
populate the ``$this->data`` property (it takes care of serializing the
5252
``$this->data`` property)::
5353

54-
class MemoryDataCollector extends DataCollector
54+
// src/AppBundle/DataCollector/MyCollector.php
55+
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
56+
57+
class MyCollector extends DataCollector
5558
{
5659
public function collect(Request $request, Response $response, \Exception $exception = null)
5760
{
5861
$this->data = array(
59-
'memory' => memory_get_peak_usage(true),
62+
'variable' => 'value',
6063
);
6164
}
6265

63-
public function getMemory()
66+
public function getVariable()
6467
{
65-
return $this->data['memory'];
68+
return $this->data['variable'];
6669
}
6770

6871
public function getName()
6972
{
70-
return 'memory';
73+
return 'app.my_collector';
7174
}
7275
}
7376

7477
.. _data_collector_tag:
7578

76-
Enabling custom Data Collectors
79+
Enabling Custom Data Collectors
7780
-------------------------------
7881

79-
To enable a data collector, add it as a regular service in one of your
80-
configuration, and tag it with ``data_collector``:
82+
To enable a data collector, define it as a regular service and tag it with
83+
``data_collector``:
8184

8285
.. configuration-block::
8386

8487
.. code-block:: yaml
8588
89+
# app/config/services.yml
8690
services:
87-
data_collector.your_collector_name:
88-
class: Fully\Qualified\Collector\Class\Name
91+
app.my_collector:
92+
class: AppBundle\DataCollector\MyCollector
93+
public: false
8994
tags:
9095
- { name: data_collector }
9196
9297
.. code-block:: xml
9398
94-
<service id="data_collector.your_collector_name" class="Fully\Qualified\Collector\Class\Name">
95-
<tag name="data_collector" />
96-
</service>
99+
<!-- app/config/services.xml -->
100+
<?xml version="1.0" encoding="UTF-8" ?>
101+
<container xmlns="http://symfony.com/schema/dic/services"
102+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
103+
xsi:schemaLocation="http://symfony.com/schema/dic/services
104+
http://symfony.com/schema/dic/services/services-1.0.xsd"
105+
>
106+
<services>
107+
<service id="app.my_collector" class="AppBundle\DataCollector\MyCollector"
108+
public="false">
109+
<tag name="data_collector" />
110+
</service>
111+
</services>
112+
</container>
97113
98114
.. code-block:: php
99115
116+
// app/config/services.php
100117
$container
101-
->register('data_collector.your_collector_name', 'Fully\Qualified\Collector\Class\Name')
118+
->register('app.my_collector', 'AppBundle\DataCollector\MyCollector')
119+
->setPublic(false)
102120
->addTag('data_collector')
103121
;
104122
105123
Adding Web Profiler Templates
106124
-----------------------------
107125

108-
When you want to display the data collected by your data collector in the web
109-
debug toolbar or the web profiler, you will need to create a Twig template. The
110-
following example can help you get started:
126+
The information collected by your data collector can be displayed both in the
127+
web debug toolbar and in the web profiler. To do so, you need to create a Twig
128+
template that includes some specific blocks.
129+
130+
In the simplest case, you just want to display the information in the toolbar
131+
without providing a profiler panel. This requires to define the ``toolbar``
132+
block and set the value of two variables called ``icon`` and ``text``:
111133

112-
.. code-block:: jinja
134+
.. code-block:: html+jinja
113135

114136
{% extends 'WebProfilerBundle:Profiler:layout.html.twig' %}
115137

116138
{% block toolbar %}
117-
{# This toolbar item may appear along the top or bottom of the screen.#}
118139
{% set icon %}
119-
<span class="icon"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAcCAQAAADVGmdYAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQffAxkBCDStonIVAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAHpJREFUOMtj3PWfgXRAuqZd/5nIsIdhVBPFmgqIjCuYOrJsYtz1fxuUOYER2TQID8afwIiQ8YIkI4TzCv5D2AgaWSuExJKMIDbA7EEVhQEWXJ6FKUY4D48m7HYU/EcWZ8JlE6qfMELPDcUJuEMPxvYazYTDWRMjOcUyAEswO+VjeQQaAAAAAElFTkSuQmCC" alt=""/></span>
120-
<span class="sf-toolbar-status">Example</span>
140+
{# this is the content displayed as a panel in the toolbar #}
141+
<span class="icon"><img src="..." alt=""/></span>
142+
<span class="sf-toolbar-status">Information</span>
121143
{% endset %}
122144

123145
{% set text %}
124-
<div class="sf-toolbar-info-piece">
125-
<b>Quick piece of data</b>
126-
<span>100 units</span>
127-
</div>
128-
<div class="sf-toolbar-info-piece">
129-
<b>Another quick thing</b>
130-
<span>300 units</span>
131-
</div>
146+
{# this is the content displayed when hovering the mouse over
147+
the toolbar panel #}
148+
<div class="sf-toolbar-info-piece">
149+
<b>Quick piece of data</b>
150+
<span>100 units</span>
151+
</div>
152+
<div class="sf-toolbar-info-piece">
153+
<b>Another piece of data</b>
154+
<span>300 units</span>
155+
</div>
132156
{% endset %}
133157

134-
{# Set the "link" value to false if you do not have a big "panel"
135-
section that you want to direct the user to. #}
136-
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { 'link': true }) }}
158+
{# the 'link' value set to 'false' means that this panel doesn't
159+
show a section in the web profiler. #}
160+
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: false }) }}
161+
{% endblock %}
162+
163+
.. tip::
164+
165+
Built-in collector templates define all their images as embedded base64-encoded
166+
images. This makes them work everywhere without having to mess with web assets
167+
links:
168+
169+
.. code-block:: html
170+
171+
<img src="data:image/png;base64,..." />
172+
173+
Another solution is to define the images as SVG files. In addition to being
174+
resolution-independent, these images can be easily embedded in the Twig
175+
template or included from an external file to reuse them in several templates:
137176

177+
.. code-block:: jinja
178+
179+
{{ include('@App/data_collector/icon.svg') }}
180+
181+
You are encouraged to use the latter technique for your own toolbar panels.
182+
183+
If the toolbar panel includes extended web profiler information, the Twig template
184+
must also define additional blocks:
185+
186+
.. code-block:: html+jinja
187+
188+
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
189+
190+
{% block toolbar %}
191+
{% set icon %}
192+
<span class="icon"><img src="..." alt=""/></span>
193+
<span class="sf-toolbar-status">Information</span>
194+
{% endset %}
195+
196+
{% set text %}
197+
<div class="sf-toolbar-info-piece">
198+
{# ... #}
199+
</div>
200+
{% endset %}
201+
202+
{# the 'link' value is now set to 'true', which allows the user to click
203+
on it to access the web profiler panel. Since 'true' is the default
204+
value, you can omit the 'link' parameter entirely #}
205+
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: true }) }}
138206
{% endblock %}
139207

140208
{% block head %}
141-
{# Optional, if you need your own JS or CSS files. #}
142-
{{ parent() }} {# Use parent() to keep the default styles #}
209+
{# Optional, you can here link to or define your own CSS and JS contents #}
210+
{# {{ parent() }} to keep the default styles #}
143211
{% endblock %}
144212

145213
{% block menu %}
146214
{# This left-hand menu appears when using the full-screen profiler. #}
147215
<span class="label">
148-
<span class="icon"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAcCAQAAADVGmdYAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQffAxkBCDStonIVAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAHpJREFUOMtj3PWfgXRAuqZd/5nIsIdhVBPFmgqIjCuYOrJsYtz1fxuUOYER2TQID8afwIiQ8YIkI4TzCv5D2AgaWSuExJKMIDbA7EEVhQEWXJ6FKUY4D48m7HYU/EcWZ8JlE6qfMELPDcUJuEMPxvYazYTDWRMjOcUyAEswO+VjeQQaAAAAAElFTkSuQmCC" alt=""/></span>
216+
<span class="icon"><img src="..." alt=""/></span>
149217
<strong>Example Collector</strong>
150218
</span>
151219
{% endblock %}
@@ -158,57 +226,90 @@ following example can help you get started:
158226
</p>
159227
{% endblock %}
160228

161-
Each block is optional. The ``toolbar`` block is used for the web debug
162-
toolbar and ``menu`` and ``panel`` are used to add a panel to the web
163-
profiler.
164-
229+
The ``menu`` and ``panel`` blocks are the only required blocks to define the
230+
contents displayed in the web profiler panel associated with this data collector.
165231
All blocks have access to the ``collector`` object.
166232

167-
.. tip::
233+
Finally, to enable the data collector template, add a ``template`` attribute to
234+
the ``data_collector`` tag in your service configuration:
168235

169-
Built-in templates use a base64 encoded image for the toolbar:
236+
.. configuration-block::
170237

171-
.. code-block:: html
238+
.. code-block:: yaml
172239
173-
<img src="data:image/png;base64,..." />
240+
# app/config/services.yml
241+
services:
242+
app.my_collector:
243+
class: AppBundle\DataCollector\MyCollector
244+
tags:
245+
-
246+
name: data_collector
247+
template: 'data_collector/template.html.twig'
248+
id: 'app.my_collector'
249+
public: false
174250
175-
You can easily calculate the base64 value for an image with this
176-
little script::
251+
.. code-block:: xml
177252
178-
#!/usr/bin/env php
179-
<?php
180-
echo base64_encode(file_get_contents($_SERVER['argv'][1]));
253+
<!-- app/config/services.xml -->
254+
<?xml version="1.0" encoding="UTF-8" ?>
255+
<container xmlns="http://symfony.com/schema/dic/services"
256+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
257+
xsi:schemaLocation="http://symfony.com/schema/dic/services
258+
http://symfony.com/schema/dic/services/services-1.0.xsd"
259+
>
260+
<services>
261+
<service id="app.my_collector" class="AppBundle\DataCollector\MyCollector" public="false">
262+
<tag name="data_collector" template="data_collector/template.html.twig" id="app.my_collector" />
263+
</service>
264+
</services>
265+
</container>
181266
182-
To enable the template, add a ``template`` attribute to the ``data_collector``
183-
tag in your configuration. For example, assuming your template is in AppBundle:
267+
.. code-block:: php
268+
269+
// app/config/services.php
270+
$container
271+
->register('app.my_collector', 'AppBundle\DataCollector\MyCollector')
272+
->setPublic(false)
273+
->addTag('data_collector', array(
274+
'template' => 'data_collector/template.html.twig',
275+
'id' => 'app.my_collector',
276+
))
277+
;
278+
279+
.. caution::
280+
281+
The ``id`` attribute must match the value returned by the ``getName()`` method.
282+
283+
The position of each panel in the toolbar is determined by the priority defined
284+
by each collector. Most built-in collectors use ``255`` as their priority. If you
285+
want your collector to be displayed before them, use a higher value:
184286

185287
.. configuration-block::
186288

187289
.. code-block:: yaml
188290
291+
# app/config/services.yml
189292
services:
190-
data_collector.your_collector_name:
191-
class: AppBundle\Collector\Class\Name
293+
app.my_collector:
294+
class: AppBundle\DataCollector\MyCollector
192295
tags:
193-
- { name: data_collector, template: "AppBundle:Collector:templatename", id: "your_collector_name" }
296+
- { name: data_collector, template: '...', id: '...', priority: 300 }
194297
195298
.. code-block:: xml
196299
197-
<service id="data_collector.your_collector_name" class="AppBundle\Collector\Class\Name">
198-
<tag name="data_collector" template="AppBundle:Collector:templatename" id="your_collector_name" />
300+
<!-- app/config/services.xml -->
301+
<service id="app.my_collector" class="AppBundle\DataCollector\MyCollector">
302+
<tag name="data_collector" template="..." id="..." priority="300" />
199303
</service>
200304
201305
.. code-block:: php
202306
307+
// app/config/services.php
203308
$container
204-
->register('data_collector.your_collector_name', 'AppBundle\Collector\Class\Name')
309+
->register('app.my_collector', 'AppBundle\DataCollector\MyCollector')
205310
->addTag('data_collector', array(
206-
'template' => 'AppBundle:Collector:templatename',
207-
'id' => 'your_collector_name',
311+
'template' => '...',
312+
'id' => '...',
313+
'priority' => 300,
208314
))
209315
;
210-
211-
.. caution::
212-
213-
Make sure the ``id`` attribute is the same string you used for the
214-
``getName()`` method.

0 commit comments

Comments
 (0)