44How 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
1111Creating 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
5151populate 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.
165231All 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