Как создать пользовательский сборщик данных

Дата обновления перевода 2023-07-05

Как создать пользовательский сборщик данных

Профилировщик Symfony получает информацию о профилировании и отладке, используя некоторые специальные классы под названием сборщики данных. Symfony поставляется с некоторыми из них, но вы можете также создать собственные.

Создание пользовательского сборщика данных

Сборщик данных - это PHP класс, который реализует DataCollectorInterface. Для удобства, ващи сборщики данных также могут расширяться из класса DataCollector, который реализует интерфейс и предоставляет некоторые утилиты и свойство $this->data для хранения собранной информации.

Следующий пример демонстрирует пользовательский сборщик, который хранит информацию о запросе:

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
// src/DataCollector/RequestCollector.php
namespace App\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 reset()
    {
        $this->data = array();
    }

    public function getName()
    {
        return 'app.request_collector';
    }

    // ...
}
Метод collect():

Хранит собранные данные в локальных свойствах ($this->data если вы расширяете из DataCollector). Если данные для сборки не могут быть получены через запрос или ответ, внедрите необходимые сервисы в сборщик данных.

Caution

Метод collect() вызывается только единожды. Он не используется для "сборки" данных, но существует для "подбора" данных, которые хранятся вашим сервисом.

Caution

Пока ваш профилировщик сериализирует экземпляры сборщиков данных, вам не стоит хранить объекты, которые не могут быть сериализированы (вроде PDO объектов) или вам нужно предоставить ваш собственный метод serialize().

Метод reset():
Вызывается между запросами, чтобы сбросить состояние профилировщика. Используйте его, чтобы удалить всю собранную методом collect() информацию.
Метод getName():
Возвращает идентификатор сборщика, который должен быть уникален для приложения. Это значение используется позже для доступа к информации сборщика (см. Как использовать профилировщик в функциональном тесте), так что рекомендуется возвращать короткую строку в нижнем регистре без пробелов.

Включение пользовательских сборщиков данных

Если вы используете конфигурацию services.yaml по умолчанию с autoconfigure, то Symfony автоматически заметит ваш новый сборщик данных! Ваш метод collect() должен быть вызван при последующем обновлении.

Если вы не используете autoconfigure, то вы также можете вручную смонтировать ваш сервис и тегировать его с помощью data_collector.

Добавление шаблонов веб-профилировщика

Информация, собранная вашим сборщиком данных, может быть отображена как в панели инструментов веб-отладки, так и в веб-профилировщике. Чтобы сделать это, вам понадобится создать шаблон Twig, включающий некоторые конкретные блоки.

Однако, вначале вам нужно добавить некоторые геттеры в класс сборщика данных, чтобы предоставить шаблону доступ к собранной информации:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// src/DataCollector/RequestCollector.php
namespace App\DataCollector;

use Symfony\Component\HttpKernel\DataCollector\DataCollector;

class RequestCollector extends DataCollector
{
    // ...

    public function getMethod()
    {
        return $this->data['method'];
    }

    public function getAcceptableContentTypes()
    {
        return $this->data['acceptable_content_types'];
    }
}

В наипростейшем случае, вам просто нужно отобразить информацию в панели инструментов, не предоставляя панели профилировщика. Это требует определения блока 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
{% extends '@WebProfiler/Profiler/layout.html.twig' %}

{% block toolbar %}
    {% set icon %}
        {# это содержимое, отображённое в виде панели в панели инструментов #}
        <svg xmlns="http://www.w3.org/2000/svg"> ... </svg>
        <span class="sf-toolbar-value">Request</span>
    {% endset %}

    {% set text %}
        {# это содержимое, отображённое при наведении мыши на панель инструментов #}
        <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 %}

    {# значение 'link' установленное, как 'false', означает, что эта панель не
       отображает раздел в веб-профилировщике #}
    {{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: false }) }}
{% endblock %}

Tip

Встроенные шаблоны сборщиков определяют все свои изображения, как встроенные SVG файлы. Это позволяет им работать везде без вмешательства в ссылки веб-ресуров:

1
2
3
4
{% set icon %}
    {{ include('data_collector/icon.svg') }}
    {# ... #}
{% endset %}

Если панель инструментов включает расширенную информауию веб-профилировщика, то шаблон Twig должен также определять дополнительные блоки:

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
{% extends '@WebProfiler/Profiler/layout.html.twig' %}

{% block toolbar %}
    {% set icon %}
        {# ... #}
    {% endset %}

    {% set text %}
        <div class="sf-toolbar-info-piece">
            {# ... #}
        </div>
    {% endset %}

    {{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { 'link': true }) }}
{% endblock %}

{% block head %}
    {# Необязательно. Тут вы можете дать ссылку или определить ваше собственное
       CSS и JS содержимое. #}
    {# Используйте {{ parent() }}, чтобы расширить стили по умолчанию, вместо того,
       чтобы переопределять их. #}
{% endblock %}

{% block menu %}
    {# Это левостороннее меню отображается при использовании полноэкранного
       профилировщика. #}
    <span class="label">
        <span class="icon"><img src="..." alt=""/></span>
        <strong>Request</strong>
    </span>
{% endblock %}

{% block panel %}
    {# Необязательно для отображения большинства деталей. #}
    <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 являются единственными обязательными блоками для определения содержимого, отбражённого в панели веб-профилировщика, связанного с этим сборщиком данных. Все блоки имеют доступ к объекту collector.

Наконец, чтобы включить шаблон сборщика данных, переопределите конфигурацию вашего сервиса, чтобы указать тег, содержащий шаблон:

1
2
3
4
5
6
7
8
9
10
11
12
# config/services.yaml
services:
    App\DataCollector\RequestCollector:
        tags:
            -
                name:     data_collector
                template: 'data_collector/template.html.twig'
                # must match the value returned by the getName() method
                id:       'app.request_collector'
                # optional priority
                # priority: 300
        public: false

Положение каждой панели в панели инструментов определяется приоритетом сборщика (чем выше приоритет, тем раньше отображается панель в нанели инструментов).