How to Create a custom Data Collector
Edit this pageWarning: You are browsing the documentation for Symfony 2.6, which is no longer maintained.
Read the updated version of this page for Symfony 6.3 (the current stable version).
How to Create a custom Data Collector
The Symfony Profiler delegates data collecting to data collectors. Symfony comes bundled with a few of them, but you can easily create your own.
Creating a custom Data Collector
Creating a custom data collector is as simple as implementing the DataCollectorInterface:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
interface DataCollectorInterface
{
/**
* Collects data for the given Request and Response.
*
* @param Request $request A Request instance
* @param Response $response A Response instance
* @param \Exception $exception An Exception instance
*/
function collect(Request $request, Response $response, \Exception $exception = null);
/**
* Returns the name of the collector.
*
* @return string The collector name
*/
function getName();
}
The getName()
method must return a unique name. This is used to access the
information later on (see How to Use the Profiler in a Functional Test for
instance).
The collect()
method is responsible for storing the data it wants to give
access to in local properties.
Caution
As the profiler serializes data collector instances, you should not
store objects that cannot be serialized (like PDO objects), or you need
to provide your own serialize()
method.
Most of the time, it is convenient to extend
DataCollector and
populate the $this->data
property (it takes care of serializing the
$this->data
property):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
class MemoryDataCollector extends DataCollector
{
public function collect(Request $request, Response $response, \Exception $exception = null)
{
$this->data = array(
'memory' => memory_get_peak_usage(true),
);
}
public function getMemory()
{
return $this->data['memory'];
}
public function getName()
{
return 'memory';
}
}
Enabling custom Data Collectors
To enable a data collector, add it as a regular service in one of your
configuration, and tag it with data_collector
:
1 2 3 4 5
services:
data_collector.your_collector_name:
class: Fully\Qualified\Collector\Class\Name
tags:
- { name: data_collector }
1 2 3
<service id="data_collector.your_collector_name" class="Fully\Qualified\Collector\Class\Name">
<tag name="data_collector" />
</service>
1 2 3 4
$container
->register('data_collector.your_collector_name', 'Fully\Qualified\Collector\Class\Name')
->addTag('data_collector')
;
Adding Web Profiler Templates
When you want to display the data collected by your data collector in the web debug toolbar or the web profiler, you will need to create a Twig template. The following example can help you get started:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
{% extends 'WebProfilerBundle:Profiler:layout.html.twig' %}
{% block toolbar %}
{# This toolbar item may appear along the top or bottom of the screen.#}
{% set icon %}
<span class="icon"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAcCAQAAADVGmdYAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQffAxkBCDStonIVAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAHpJREFUOMtj3PWfgXRAuqZd/5nIsIdhVBPFmgqIjCuYOrJsYtz1fxuUOYER2TQID8afwIiQ8YIkI4TzCv5D2AgaWSuExJKMIDbA7EEVhQEWXJ6FKUY4D48m7HYU/EcWZ8JlE6qfMELPDcUJuEMPxvYazYTDWRMjOcUyAEswO+VjeQQaAAAAAElFTkSuQmCC" alt=""/></span>
<span class="sf-toolbar-status">Example</span>
{% endset %}
{% set text %}
<div class="sf-toolbar-info-piece">
<b>Quick piece of data</b>
<span>100 units</span>
</div>
<div class="sf-toolbar-info-piece">
<b>Another quick thing</b>
<span>300 units</span>
</div>
{% endset %}
{# Set the "link" value to false if you do not have a big "panel"
section that you want to direct the user to. #}
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { 'link': true }) }}
{% endblock %}
{% block head %}
{# Optional, if you need your own JS or CSS files. #}
{{ parent() }} {# Use parent() to keep the default styles #}
{% endblock %}
{% block menu %}
{# This left-hand menu appears when using the full-screen profiler. #}
<span class="label">
<span class="icon"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAcCAQAAADVGmdYAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQffAxkBCDStonIVAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAHpJREFUOMtj3PWfgXRAuqZd/5nIsIdhVBPFmgqIjCuYOrJsYtz1fxuUOYER2TQID8afwIiQ8YIkI4TzCv5D2AgaWSuExJKMIDbA7EEVhQEWXJ6FKUY4D48m7HYU/EcWZ8JlE6qfMELPDcUJuEMPxvYazYTDWRMjOcUyAEswO+VjeQQaAAAAAElFTkSuQmCC" alt=""/></span>
<strong>Example Collector</strong>
</span>
{% endblock %}
{% block panel %}
{# Optional, for showing the most details. #}
<h2>Example</h2>
<p>
<em>Major information goes here</em>
</p>
{% endblock %}
Each block is optional. The toolbar
block is used for the web debug
toolbar and menu
and panel
are used to add a panel to the web
profiler.
All blocks have access to the collector
object.
Tip
Built-in templates use a base64 encoded image for the toolbar:
1
<img src="data:image/png;base64,..." />
You can easily calculate the base64 value for an image with this little script:
1 2 3
#!/usr/bin/env php
<?php
echo base64_encode(file_get_contents($_SERVER['argv'][1]));
To enable the template, add a template
attribute to the data_collector
tag in your configuration. For example, assuming your template is in some
AcmeDebugBundle:
1 2 3 4 5
services:
data_collector.your_collector_name:
class: Acme\DebugBundle\Collector\Class\Name
tags:
- { name: data_collector, template: "AcmeDebugBundle:Collector:templatename", id: "your_collector_name" }
1 2 3
<service id="data_collector.your_collector_name" class="Acme\DebugBundle\Collector\Class\Name">
<tag name="data_collector" template="AcmeDebugBundle:Collector:templatename" id="your_collector_name" />
</service>
1 2 3 4 5 6 7
$container
->register('data_collector.your_collector_name', 'Acme\DebugBundle\Collector\Class\Name')
->addTag('data_collector', array(
'template' => 'AcmeDebugBundle:Collector:templatename',
'id' => 'your_collector_name',
))
;
Caution
Make sure the id
attribute is the same string you used for the
getName()
method.