Сервіси в Symfony: коротко, просто та зрозуміло

Сервіси в Symfony: коротко, просто та зрозуміло

Досить просто і доступно про те, що таке сервіси і як вони працюють в Symfony 4 (за матеріалами symfonycasts).

OS: Ubuntu 18.04, Framework: Symfony 4.2.5

Отже, що таке сервіс? Насправді, цей термін позначає досить просту ідею: сервіс - це будь-який об'єкт, який виконує якусь роботу. Наприклад, відправляє повідомлення, зберігає дані в базу, парсить RSS і т.д.

Як використовувати сервіси? Просто всередині контролера допишіть в метод додатковий аргумент і дайте йому підказку типу, наприклад, LoggerInterface і назвіть його як хочете, наприклад $logger:

public function index(LoggerInterface $logger)
{
    // do something
    $logger->info('Some message');
}

 

Як це працює? Перед тим, як запустити контролер, Symfony перевіряє кожен аргумент, дивиться на підказку типу і розуміє, що нам потрібен той чи інший об'єкт. І, до речі, порядок аргументів зовсім не важливий.

Symfony поставляється з величезною кількістю сервісів. Як дізнатися, які сервіси є доступними? Увійдіть в кореневу директорію проекту і виконайте команду:

bin/console debug:autowiring

 

Можна також виконати пошук за ключовим словом:

bin/console debug:autowiring [<keyword>]

 

Ок, а що таке autowiring? Це автоматичне підключення, яке дозволяє керувати сервісами з мінімумом конфігурації. Мова про це вже була вище - Symfony читає підказку типу і передає потрібний об'єкт. Як щодо користувацького коду? Відкрийте файл config/services.yaml і зверніть увагу на наступні рядки:

services:
    # default configuration for services in *this* file
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.

 

Це означає, що будь-який клас (докладніше нижче) автоматично зареєстрований як сервіс і автоматично підключений. Іншими словами, створені класи можна відразу ж використовувати як сервіси, взагалі не замислюючись про конфігурацію.

Стоп! Невже взагалі будь-який клас зареєстрований як сервіс? Взагалі то ні. Знову звернемося до файлу config/services.yaml:

services:
    ...
    # makes classes in src/ available to be used as services
    # this creates a service per class whose id is the fully-qualified class name
    App\:
        resource: '../src/*'
        exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'

 

Тобто всі класи в директорії src, крім тих, які знаходяться в піддиректоріях перерахованих в exclude, будуть доступні як сервіси.

Звідки беруться об'єкти сервісів? Кожен сервіс, зберігається всередині іншого об'єкта, який називається контейнером (також відомим як сервіс-контейнер або контейнер ін'єкції залежностей). Важливий момент: об'єкт сервісу створюється тільки тоді, коли Ви його запитуєте. Якщо цього не відбувається то і сервіс не буде створено, що сприяє економії пам'яті і швидкості. Крім того сервіс створюється тільки один раз, тобто кожного разу Symfony повертатиме один і той же екземпляр сервісу.

Але як сервіси потрапляють в контейнер, хто їх туди кладе? Відповідь: бандли. Бандли подібні плагінам в іншому програмному забезпеченні. Ключова відмінність в тому, що в Symfony все є бандлами, включаючи як ядро фреймворку, так і код, написаний для Вашого додатку.

І наостанок: Symfony - це не що інше, як набір сервісів. А бандли - це те, що фактично готує сервіси і додає їх в контейнер.

Сподіваюся, після цієї статті картина стала більш зрозумілою. При цьому як зазвичай, рекомендую ретельно вивчити офіційну документацію, оскільки деякі важливі теми не були розглянуті в даній статті (явна конфігурація сервісів і параметрів, прив'язка аргументів за ім'ям або типом, публічні і приватні сервіси і т.д.)

Успіхів!