Урок 2. Компоненты Symfony

Урок 2. Компоненты Symfony

Рассмотрим все компоненты симфони, которые вошли в ядро, а также разберемся для чего они нужны и за что отвечают.

Содержание

Компоненты Symfony

BrowserKit

Симулирует[1] поведение веб браузера, позволяет делать запросы, кликать на ссылки и сабмитать формы программно.

ClassLoader

Компонент[2], позволяющий производить автозагрузку классов и кэшировать их для улучшения производительности. Symfony предоставляет три автозагрузчика (PSR - PHP Standart Recommendations[3]):

  • PSR-0 Class Loader[4] — загружает классы, которые следуют PSR-0 стандарту автозагрузки.
  • PSR-4 Class Loader[5] — загружает классы, которые следуют PSR-4 стандарту автозагрузки.
  • MapClassLoader[6] — загружает классы, используя статический мапинг имени класса с его путем.

Пример использования PSR-0 Class Loader

1
2
3
4
5
6
7
8
9
// Регистрация автозагрузчика.
use Composer\Autoload\ClassLoader;
$class = 'Not\\A\\Class';
$loader = new ClassLoader();
$loader->addClassMap(array($class => __FILE__));
$loader->register();
// Выполнение каких-либо действий ...
// Отмена дополнительного автозагрузчика.
$loader->unregister();

Пример с PSR-4 Class Loader

1
2
3
4
use Symfony\Component\ClassLoader\Psr4ClassLoader;
$loader = new Psr4ClassLoader();
$loader->addPrefix('Symfony\\Component\\Serializer\\', 'path/to/symfony/serializer');
$loader->register();

Пример с MapClassLoader

1
2
3
4
5
6
use Symfony\Component\ClassLoader\MapClassLoader;
$map = array(
  'Example' => '/path/to/Example',
);
$loader = new MapClassLoader($map);
$loader->register();

Console

Позволяет создавать команды командной строки[7]. Консольные команды могут использованы для выполнения каких либо повторяющихся задач, например, крон тасков, импортов или других batch операций.
Пример использования

1
2
3
4
5
use Symfony\Component\Console\Application;
$app = new Application();
// Регистрация некой команды.
$app->add(new SimpleCommand());
$app->run();

CssSelector

Конвертирует CSS селекторы в Xpath выражения[8]. Xpath выражения невероятно гибкие. Практически во всех случаях Xpath сможет найти то, что вам требуется. Но в то же время они довольно сложны в построении. Даже на первый взгляд простой поиск (найти элементы по определенному классу) может потребовать длинного и сложного выражения. Существуют ограничения: не все css селекторы могут быть сконвертированы в Xpath (псевдоклассы; псевдоэлементы; селекторы, основанные на действиях пользователя и т.д.). Полный перечень того, что не может быть сконвертировано вы найдете в документации по ссылке[8].
Пример использования.

1
2
3
use Symfony\Component\CssSelector\CssSelectorConverter;
$convert = new CssSelectorConverter();
$output = $convert->toXPath('form div span');

Получаем результат

1
descendant-or-self::form/descendant-or-self::*/div/descendant-or-self::*/span

Debug

Позволяет упростить отладку кода PHP[9]. Предоставляет три класса ErrorHandler, ExceptionHandler и Debug.

  • ErrorHandler — ловит PHP ошибки и конвертирует их в исключения.
  • ExceptionHandler — ловит неперехваченные исключения PHP и выводит их в красивом виде.
  • Debug — регистрирует все инструменты дебага.

Пример

1
2
3
4
5
6
7
8
9
10
11
12
13
use Symfony\Component\Debug\ErrorHandler;
use Symfony\Component\Debug\ExceptionHandler;
ErrorHandler::register();
 
try {
  trigger_error('Here is some error');
}
catch (\Exception $e) {
  ExceptionHandler::register();
  $handler = new ExceptionHandler();
  $handler->handle($e);
  return $e->getMessage();
}

Вывод
debug вывод ошибок
или такой пример

1
2
3
4
5
6
use Symfony\Component\Debug\ErrorHandler;
use Symfony\Component\Debug\ExceptionHandler;
 
ErrorHandler::register();
ExceptionHandler::register();
function_not_exists();

Предыдущий пример через Debug можно было бы записать так

1
2
3
use Symfony\Component\Debug\Debug;
Debug::enable();
function_not_exist();

Результат
debug вывод ошибки 2

DependencyInjection

DependencyInjection (service container, dependency injection container или контейнер зависимостей) — компонент, который позволяет стандартизировать и централизовать пути к объектам, определенным в приложении[10]. Сервис контейнер — это PHP объект, который управляет инстанциированием сервисов (т.е. объектами).
Конфигурация сервисов в Drupal 8 находится в формате YAML, в файлах MODULE.services.yml.
Пример конфигурации Ban модуля, ban.services.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
services:
 ban.ip_manager:
   class: Drupal\ban\BanIpManager
   arguments: ['@database']
   tags:
     - { name: backend_overridable }
 ban.middleware:
   class: Drupal\ban\BanMiddleware
   arguments: ['@ban.ip_manager']
   tags:
     # Ensure to come before page caching, so you don't serve cached pages to
     # banned users.
     - { name: http_middleware, priority: 250 }

В данном конфиге объявлено два сервиса, каждый из которых имеет свой класс, описывающий логику работы. Когда вы обращаетесь за нужный сервисом, контейнер создает объект и его возвращает. Это еще одно существенное преимущество сервис контейнера. Если сервис не вызывается, то он и не создается, не тратя память впустую и ухудшая производительность.

DomCrawler

Облегчает DOM навигацию для HTML и XML документов[11]. Если вы знакомы с jQuery, то DomCrawler — это PHP эквивалент. Позволяет искать элементы с помощью методов filter() и filterXpath(). Первый принимает селектор в формате CSS, второй - в формате Xpath выражения.
Пример использования.

1
2
3
4
5
use Symfony\Component\DomCrawler\Crawler;
$html = '<html><title>HTML TITLE</title><body>HTML BODY</body></html>';
$crawler = new Crawler();
$crawler->addContent($html);
print $crawler->filter('body')->text();

выведет

1
HTML BODY

Тот же пример с использованием filterXpath().

1
2
3
4
5
use Symfony\Component\DomCrawler\Crawler;
$html = '<html><title>HTML TITLE</title><body>HTML BODY</body></html>';
$crawler = new Crawler();
$crawler->addContent($html);
print $crawler->filterXPath('descendant-or-self::body')->text();

EventDispatcher

Компонент, предоставляющий инструменты, которые в свою очередь, позволяют компонентам вашего приложения коммуницировать друг с другом, отправляя события и прослушивая их[12]. Реализует паттерн посредник (Mediator).

Посредник (англ. Mediator) — поведенческий шаблон проектирования, обеспечивающий взаимодействие множества объектов, формируя при этом слабую связанность и избавляя объекты от необходимости явно ссылаться друг на друга[13].

Dispatcher — центральный объект во всей event dispatcher системе. После его инстанцирования, к нему подключается множество слушателей. Когда событие проходит через dispatcher, он оповещает всех слушателей, подписанных на это событие.
Пример. Создание экземпляра dispatcher

1
2
use Symfony\Component\EventDispatcher\EventDispatcher;
$dispatcher = new EventDispatcher();

Подключение слушателя

1
2
$listener = new ExampleListener();
$dispatcher->addListener('example.action', array($listener, 'onFooAction'));

Метод addListener() принимает три аргумента:

  • имя события, должно быть строкой
  • callable метод класса слушателя
  • необязательный аргумент - число, которое определяет приоритет вызова слушателя. По умолчанию 0.

В свою очередь ExampleListener класс имеет такое содержимое

1
2
3
4
5
6
7
8
use Symfony\Component\EventDispatcher\Event;
 
class ExampleListener {
    // ...
    public function onFooAction(Event $event) {
        // ... какие-то действия
    }
}

HttpFoundation

Компонент, определяющий объектно-ориентированный слой для HTTP спецификации[14]. В PHP запрос представлен некоторыми глобальными переменными ($_GET, $_POST, $_FILES, $_COOKIE, и т.д.), а ответ генерируется некоторыми функциями (echo, header() и т.д.)
Данный компонент призван заменить эти глобальные переменные и функциями одним объектно-ориентированный объектом. Содержит классы запроса (Request) и ответа (Response). Более подробно тема запросов и ответов будет рассмотрена в следующем уроке.

HttpKernel

Как уже упоминалось в первом, ознакомительном уроке, данный компонент необходим для стандартизации процесса конвертации запроса в ответ с помощью EventDispatcher компонента[15].
HttpKernel предоставляет интерфейс, который формализует процесс создания запроса и ответа. Компонент описывает "правила" данного процесса, оставляя реализацию за системой, фреймворком, в котором он используется.

Symfony Polyfill

Symfony Polyfill[16] — это проект, цель которого обеспечить портируемость и совместимость некоторых фич, найденных в последних версиях PHP. Список расширений, используемых в Drupal 8:

  • Symfony Polyfill/APCu[17] — предоставляет apcu_* функции, а также APCUIterator класс. APCu - это APC (Alternative PHP Cache) без кеширования опкода.
  • Symfony Polyfill/Iconv[18] — предоставляет нативные iconv функции PHP. Позволяет менять кодировку строки на иную из доступного списка.
  • Symfony Polyfill/Mbstring[19] — предоставляет реализацию Mbstring расширения.
  • Symfony Polyfill/Php54[20] — компонент, который предоставляет функции недоступные в релизе PHP 5.4, а именно: trait_exists, class_uses, hex2bin, session_register_shutdown.
  • Symfony Polyfill/Php55[21] — позволяет пользоваться функциями, недоступными для релиза PHP версии 5.5, а именно: boolval, json_last_error_msg, array_column, hash_pbkdf2, password_* functions.

Process

Компонент, выполняющий команды в sub-процессах[22].
Пример:

1
2
3
4
use Symfony\Component\Process\Process;
$process = new Process('cd /tmp/; ls -al');
$process->run();
print_r($process->getOutput());

С помощью команд ‘cd /tmp/; ls -al’ — переходим в tmp папку корневой директории сервера и выводим ее содержимое. Результат приведен ниже
d8_process_component.png

PSR-7 Bridge

PSR-7 Bridge[23] преобразует HttpFoundation объекты в объекты, реализующие стандарт PSR-7 и наоборот, объекты определенные по PSR-7 в HttpFoundation объекты.

Routing

Преобразовывает HTTP запрос в вызов определенной функции, подобно hook_menu()[24]. Мапит HTTP запрос на перечень конфигурационных переменных.

Serializer

Предназначен для конвертации объектов в специальный формат (XML, JSON, т.д.) и обратно[25]. Упрощенная схема, по которой работает компонент Serializer приведена ниже
d8 serializer компонент
Кодировщики (Encoders) конвертируют массивы в специальные форматы и обратно. В свою очередь нормализаторы (Normalizers) работают с преобразованием объектов в массивы и наоборот.

Translation

Компонент содержит инструменты для интернационализации приложения[26]. Ключевым классом является Translator. Может подгружать переводы с различных источников: массивов, json, yml файлов, csv, php, xml и т.д. Переводы хранятся в каталогах сообщений внутри класса Translator.
Пример использования

1
2
3
4
5
6
7
use Symfony\Component\Translation\Loader\ArrayLoader;
use Symfony\Component\Translation\Translator;
$translator = new Translator('ru_RU');
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', array(
 'user' => 'пользователь',
), 'ru_RU');

Перевод слова user

1
echo $translator->trans('user');

Validator

Валидация — это довольно общая задача. Например, для полей с датами нужно проверять корректность ввода даты, для полей, которые хранят числовые значения - проверять что в них записаны именно числа, для строковых - строки и т.д. Validator[27] — компонент, который предоставляет инструменты для того, чтобы сделать данную процедуру простой и прозрачной. Важным компонентом является так называемые Constraints — классы, наследуемые от абстрактного класса Constraint. Каждый такой класс отвечает за проверку определенного формата данных и не только. Из коробки доступно большое количество constraints: базовые (NotBlank, Blank, IsTrue, IsNull и т.д.), строковые, числовые, файловые и т.д.
Для примера проверим корректность даты

1
2
3
4
5
6
use Symfony\Component\Validator\Constraints\Date;
use Symfony\Component\Validator\Validation;
$validator  = Validation::createValidator();
$constraint = new Date();
$errors = $validator->validate('2016-99-99', $constraint);
return !empty($errors->count()) ? t('Date is invalid') : t('Date is valid');

Получаем

1
Date is invalid

Yaml

Yaml[28] — загружает и парсит файлы в формате yml. Причины по которым в качестве хранилища конфигов, а также файлов экспорта/импорта был выбран yml формат:

  • Быстрая скорость обработки данных
  • Надежный анализатор разбирающий большое множество Yaml спецификаций
  • Удобен для чтения и внесения изменений.
  • Содержит понятные сообщения об ошибках
  • Поддержка типов: поддерживает большинство Yaml встроенных типов данных - даты, числа, булевские значения и т.д.
  • Имеет полную поддержку ссылок & и алиасов (*)

Пример использования. Предположим у нас есть некий файлик в формате YAML - example.yml.
Содержимое example.yml

1
2
example.content:
 path: '/example'

Мы можем его распарсить следующим образом

1
2
use Symfony\Component\Yaml\Yaml;
$content = Yaml::parse(file_get_contents('path_to_file_example.yml'));

В результате в переменной $content будет массив данных из этого файла
d8 yml компонент
С помощью данного компонента можно также записывать данные в формат YAML.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use Symfony\Component\Yaml\Yaml;
$example = array(
 'one' => array(
   'one.one' => 11,
   'one.two' => 12,
 ),
 'two' => array(
   'two.one' => array(
     'two.one.one' => 211,
   ),
 ),
 'three' => 3,
);
$yml = Yaml::dump($example);
file_put_contents('path_to_file_example.yml', $yml);

В результате содержимое файлы example.yml будет следующим

1
2
3
4
5
6
one:
   one.one: 11
   one.two: 12
two:
   two.one: { two.one.one: 211 }
three: 3

Домашнее задание

Необходимо установить/развернуть Drupal 8 на локальном сервере, т.к. в последующих уроках приступим к написанию собственного модуля. Разворачивать можно по аналогии с 7-ой версией по статьям Установка и настройка VirtualBox и Установка Drupal на VirtualBox. Версию ubuntu лучше ставить от 14 и выше, версию PHP не ниже 5.6.

Дополнительная информация по статье

  1. http://symfony.com/doc/current/components/browser_kit.html - о BrowserKit из документации Symfony.
  2. https://symfony.com/doc/current/components/class_loader.html - о ClassLoader из документации Symfony.
  3. http://www.php-fig.org/psr - о PHP стандартах PSR.
  4. http://www.php-fig.org/psr/psr-0/ - о PSR-0.
  5. http://www.php-fig.org/psr/psr-4 - о PSR-4.
  6. https://symfony.com/doc/current/components/class_loader/map_class_loader.html - о MapClassLoader из документации Symfony.
  7. https://symfony.com/doc/current/components/console.html - о Console из документации Symfony.
  8. https://symfony.com/doc/current/components/css_selector.html - о CssSelector из документации Symfony.
  9. http://symfony.com/doc/current/components/debug.html - о Debug из документации Symfony.
  10. https://symfony.com/doc/current/components/dependency_injection/index.html - DependencyInjection из документации Symfony.
  11. http://symfony.com/doc/current/components/dom_crawler.html - о DomCrawler из документации Symfony.
  12. https://symfony.com/doc/current/components/event_dispatcher/index.html - о EventDispatcher из документации Symfony.
  13. https://ru.wikipedia.org/wiki/Посредник_(шаблон_проектирования) - паттерн Посредник на wiki
  14. http://symfony.com/doc/current/components/http_foundation.html - о HttpFoundation из документации Symfony.
  15. http://symfony.com/doc/current/components/http_kernel.html - о HttpKernel из документации Symfony.
  16. https://github.com/symfony/polyfill - Symfony Polyfill на гитхабе.
  17. https://github.com/symfony/polyfill/blob/master/src/Apcu/README.md - о Symfony Polyfill / APCu.
  18. https://github.com/symfony/polyfill/blob/master/src/Iconv/README.md - о Symfony Polyfill / Iconv.
  19. https://github.com/symfony/polyfill-mbstring - о Symfony Polyfill / Mbstring.
  20. https://github.com/symfony/polyfill-php54 - о Symfony Polyfill / Php54.
  21. https://github.com/symfony/polyfill-php55 - о Symfony Polyfill / Php55.
  22. https://symfony.com/doc/current/components/process.html - о Process из документации Symfony.
  23. http://symfony.com/doc/current/request/psr7.html - о PSR-7 Bridge из документации Symfony.
  24. https://symfony.com/doc/current/components/routing/index.html - о Routing из документации Symfony.
  25. https://symfony.com/doc/current/components/serializer.html - о Serializer из документации Symfony.
  26. https://symfony.com/doc/current/components/translation/index.html - о Translation из документации Symfony.
  27. https://symfony.com/doc/current/book/validation.html - о Validator из документации Symfony.
  28. https://symfony.com/doc/current/components/yaml/index.html - о YAML из документации Symfony.
  29. Версии программных продуктов, используемых в статье: Drupal 8.2.4