支付宝扫一扫付款
微信扫一扫付款
(微信为保护隐私,不显示你的昵称)
Symfony Profiler(分析器)把数据收集(data collection)委托给了一些特殊的被称为data collector的类。Symfony对其中的一些打了包,但你可以轻松创建自己的收集器。
创建自定义的数据收集器简单到只需实现DataCollectorInterface
接口:
1 2 3 4 5 | interface DataCollectorInterface
{
function collect(Request $request, Response $response, \Exception $exception = null);
function getName();
} |
getName()
返回data collector的名字,此名称在程序中必须唯一。这个值在后面也用于访问信息 (参考 如何在功能测试中使用分析器 for instance)。
collect()
负责在本地属性中存储收集来的数据。
多数时候,继承 DataCollector
和装载 $this->data
属性 (它掌控 $this->data
属性的序列化) 是很方便的。假设你要创建一个全新的数据收集器,用于从请求中收集method和可接受的content types:
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 | // src/AppBundle/DataCollector/RequestCollector.php
namespace AppBundle\DataCollector;
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class RequestCollector extends DataCollector
{
public function collect(Request $request, Response $response, \Exception $exception = null)
{
$this->data = array(
'method' => $request->getMethod(),
'acceptable_content_types' => $request->getAcceptableContentTypes(),
);
}
public function getMethod()
{
return $this->data['method'];
}
public function getAcceptableContentTypes()
{
return $this->data['acceptable_content_types'];
}
public function getName()
{
return 'app.request_collector';
}
} |
添加getters是为了让模板访问到所收集的信息。
由于分析器对data collecotor实例进行了序列化,你不应该存储那些不能被序列化的对象(如,PDO objects) 否则你需要提供自己的 serialize()
方法。
要开启data collector,将其定义为常规服务并打上 data_collector
标签:
1 2 3 4 5 6 7 | # app/config/services.yml
services:
app.request_collector:
class: AppBundle\DataCollector\RequestCollector
public: false
tags:
- { name: data_collector } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <!-- app/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd"
>
<services>
<service id="app.request_collector"
class="AppBundle\DataCollector\RequestCollector"
public="false"
>
<tag name="data_collector" />
</service>
</services>
</container> |
1 2 3 4 5 6 7 8 | // app/config/services.php
use AppBundle\DataCollector\RequestCollector;
$container
->register('app.request_collector', RequestCollector::class)
->setPublic(false)
->addTag('data_collector')
; |
通过你的数据收集器所收集来的信息,可以被显示在web debug toolbar和web profiler中。要实现之,需要创建一个Twig模板,令其包容一些特定的block。
在最简单的例子中,你只需在工具条中显示信息,而不用再提供一个分析器面板。这需要定义 toolbar
块儿,并且设置其中的两个变量,分别是 icon
和 text
:
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 | {% extends 'WebProfilerBundle:Profiler:layout.html.twig' %}
{% block toolbar %}
{% set icon %}
{# this is the content displayed as a panel in the toolbar #}
{# 这是在工具条中作为面板来显示的内容 #}
<span class="icon"><img src="..." alt=""/></span>
<span class="sf-toolbar-status">Request</span>
{% endset %}
{% set text %}
{# this is the content displayed when hovering the mouse over
the toolbar panel #}
{# 这是当鼠标悬停在工具条面板上时所显示的内容 #}
<div class="sf-toolbar-info-piece">
<b>Method</b>
<span>{{ collector.method }}</span>
</div>
<div class="sf-toolbar-info-piece">
<b>Accepted content type</b>
<span>{{ collector.acceptableContentTypes|join(', ') }}</span>
</div>
{% endset %}
{# the 'link' value set to 'false' means that this panel doesn't
show a section in the web profiler #}
{# 'link' 值设为 'false',表示在此面板中,不显示web profiler部分 #}
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: false }) }}
{% endblock %} |
内置的collector模板,把所需之全部图片定义成基于base64加密的图片。这可令它们在任何地方工作,而不会和web资源的链接混为一谈:
1 | <img src="data:image/png;base64,..." /> |
另一个方案是把图片定义成SVG文件。除了分辨率是独立的之外,这些图片还可以轻易嵌入到Twig模板或从外部文件中包容,以实现在多个模板中的复用:
1 | {{ include('@App/data_collector/icon.svg') }} |
推荐在你自己的工具条面板中使用后一个技巧。
如果工具条面板继承了web profiler信息,Twig模板中必须同时定义附加blocks:
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 47 48 49 | {% extends '@WebProfiler/Profiler/layout.html.twig' %}
{% block toolbar %}
{% set icon %}
<span class="icon"><img src="..." alt=""/></span>
<span class="sf-toolbar-status">Request</span>
{% endset %}
{% set text %}
<div class="sf-toolbar-info-piece">
{# ... #}
</div>
{% endset %}
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { 'link': true }) }}
{% endblock %}
{% block head %}
{# Optional. Here you can link to or define your own CSS and JS contents. #}
{# 可选。此处你可以链入自己的 CSS 和 JS 内容。 #}
{# Use {{ parent() }} to extend the default styles instead of overriding them. #}
{# 使用 {{ parent() }} 来继承默认样式而不是全盘覆写。 #}
{% endblock %}
{% block menu %}
{# This left-hand menu appears when using the full-screen profiler. #}
{# 当使用全屏profiler时,这个左侧菜单就会显示 #}
<span class="label">
<span class="icon"><img src="..." alt=""/></span>
<strong>Request</strong>
</span>
{% endblock %}
{% block panel %}
{# Optional, for showing the most details. #}
{# 可选,用于显示更多细节。 #}
<h2>Acceptable Content Types</h2>
<table>
<tr>
<th>Content Type</th>
</tr>
{% for type in collector.acceptableContentTypes %}
<tr>
<td>{{ type }}</td>
</tr>
{% endfor %}
</table>
{% endblock %} |
menu
和 panel
块儿,是唯一需要定义内容以显示在“和这个data collector相关联”的分析器面板中的blocks。所有的block都可以访问到 collector
对象。
最后,要开启数据收集器模板,添加一个 template
属性到你的服务配置的 data_collector
标签中:
1 2 3 4 5 6 7 8 9 10 | # app/config/services.yml
services:
app.request_collector:
class: AppBundle\DataCollector\RequestCollector
tags:
-
name: data_collector
template: 'data_collector/template.html.twig'
id: 'app.request_collector'
public: false |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <!-- app/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd"
>
<services>
<service id="app.request_collector"
class="AppBundle\DataCollector\RequestCollector"
public="false"
>
<tag name="data_collector"
template="data_collector/template.html.twig"
id="app.request_collector"
/>
</service>
</services>
</container> |
1 2 3 4 5 6 7 8 9 10 11 | // app/config/services.php
use AppBundle\DataCollector\RequestCollector;
$container
->register('app.request_collector', RequestCollector::class)
->setPublic(false)
->addTag('data_collector', array(
'template' => 'data_collector/template.html.twig',
'id' => 'app.request_collector',
))
; |
id
属性必须匹配由 getName()
方法返回的值。
工具条中的每一个面板的位置,是由定义在每个collector中的优先级所决定的。多数内置的收集器使用 255
作为其优先级。如果你希望自己的收集器可以显示在它们的前面,使用更高的值:
1 2 3 4 5 6 | # app/config/services.yml
services:
app.request_collector:
class: AppBundle\DataCollector\RequestCollector
tags:
- { name: data_collector, template: '...', id: '...', priority: 300 } |
1 2 3 4 | <!-- app/config/services.xml -->
<service id="app.request_collector" class="AppBundle\DataCollector\RequestCollector">
<tag name="data_collector" template="..." id="..." priority="300" />
</service> |
1 2 3 4 5 6 7 8 9 10 11 | // app/config/services.php
use AppBundle\DataCollector\RequestCollector;
$container
->register('app.request_collector', RequestCollector::class)
->addTag('data_collector', array(
'template' => '...',
'id' => '...',
'priority' => 300,
))
; |
本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。