Як завантажувати конфігурацію сервісу всередині пакета
Дата оновлення перекладу 2025-01-10
Як завантажувати конфігурацію сервісу всередині пакета
Сервіси, створені пакетами, не визначаються в основному файлі
config/services.yaml
, який використовується додатком, а визначаються
у самих пакетах. Ця стаття пояснює, як створювати та завантажувати файли
сервісу, використовуючи структуру каталогів пакета.
Існує два різних способи зробити це:
- Завантажити ваші сервіси в основний клас пакету : рекомендовано для нових пакетів та для пакетів, що слідують рекомендованій структурі каталогу ;
- Створити клас розширення для завантаження файлів конфігурації сервісу : це був традиційний спосіб, але наразі він рекомендований лише для пакетів, що слідують успадкованій структурі каталогів .
Завантаження сервісів напряму у ваш клас пакета
У пакетах, що розширюють клас AbstractBundle, ви можете визначити метод loadExtension() для завантаження визначень сервісів з файлів конфігурації:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// ...
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
class AcmeHelloBundle extends AbstractBundle
{
public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
{
// завантажити файл XML, PHP або YAML
$container->import('../config/services.xml');
// ви також можете додати або замінити параметри та сервіси
$container->parameters()
->set('acme_hello.phrase', $config['phrase'])
;
if ($config['scream']) {
$container->services()
->get('acme_hello.printer')
->class(ScreamingPrinter::class)
;
}
}
}
Цей метод працює схоже на метод Extension::load()
, описаний нижче, але він
використовує новий простіший API для визначення та імпортування конфігурації сервісу.
Note
На відміну від параметра $configs
у Extension::load()
, параметр $config
вже об'єднано та оброблено AbstractBundle
.
Note
loadExtension()
викликається лише під час компіляції.
Створення класу розширення
Це традиційний спосіб завантаження визначень сервісів у пакетах. Для нових пакетів рекомендується завантажувати ваші сервіси в основний клас пакету , але традиційний спосіб створення класу розширення все ще працює.
Розширення впровадження залежності визначається як клас, який відповідає таким умовностям (пізніше ви дізнаєтеся, як їх можна пропустити, якщо це необхідно):
- Воно має жити у просторі імен
DependencyInjection
пакета; - Воно має реалізовувати ExtensionInterface, що зазвичай досягається шляхом розширення класу Extension ;
- Імʼя дорівнює імені пакета з суфіксом
Bundle
, зміненим наExtension
(наприклад клас розширення AcmeBundle буде називатисяAcmeExtension
, а для AcmeHelloBundle -AcmeHelloExtension
).
Ось як має виглядати розширення AcmeHelloBundle:
1 2 3 4 5 6 7 8 9 10 11 12 13
// src/DependencyInjection/AcmeHelloExtension.php
namespace Acme\HelloBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
class AcmeHelloExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container): void
{
// ... пізніше ви будете завантажувати тут файли
}
}
Реєстрація класу розширення вручну
Якщо не слідувати угодам, вам потрібно буде вручну реєструвати ваше розширення. Щоб зробити це, вам потрібно перевизначити метод Bundle::getContainerExtension(), щоб він повертав екземпляр розширення:
1 2 3 4 5 6 7 8 9 10 11
// ...
use Acme\HelloBundle\DependencyInjection\UnconventionalExtensionClass;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
class AcmeHelloBundle extends Bundle
{
public function getContainerExtension(): ?ExtensionInterface
{
return new UnconventionalExtensionClass();
}
}
Окрім того, якщо нове імʼя класу розширення не слідую угодам про іменування, вам також
потрібно перевизначити метод
Extension::getAlias()
щоб він повертав правильне додаткове імʼя ВЗ. Додаткове імʼя ВЗ - це імʼя, що
використовується для посилання на пакет у контейнері (наприклад, у файлах config/packages/
).
За замовчуванням, це робиться шляхом видалення суфікса Extension
та перетворення імені
класу на нижні підкреслення (наприклад, додаткове імʼя ВЗ AcmeHelloExtension
- це acme_hello
).
Використання методу load()
У методі load()
, всі сервіси та параметри відносяться до завантажуваного розширення.
Цей метод отримує не справжній екземпляр контейнера, а копію. Контейнер має лише
параметри зі справжнього контейнера. Після завантаження сервісів та параметрів, копія
буде зʼєднана зі справжнім контейнером, щоб переконатися, що всі сервіси та параметри
також додані у нього.
У методі load()
, ви можете використати PHP-код для реєстрації визначень сервісу,
але частіше ви будете розміщувати ці визначення у файл конфігурації (використовуючи
формати YAML, XML або PHP).
Наприклад, припустіть, що у вас є файл під назвою services.xml
у каталозі
Resources/config/
вашого пакета, ваш метод load()
виглядає так:
1 2 3 4 5 6 7 8 9 10 11 12
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
// ...
public function load(array $configs, ContainerBuilder $container): void
{
$loader = new XmlFileLoader(
$container,
new FileLocator(__DIR__.'/../../config')
);
$loader->load('services.xml');
}
Інші доступні завантажувачі - YamlFileLoader
та PhpFileLoader
.
Використання конфігурації для зміни сервісів
Розширення такаож є класом, який займається конфігурацією для цього конкретного
пакета (наприклад, конфігурація у config/packages/<bundle_alias>.yaml
). Щоб
прочитати більше про це, див. статтю "Як створити дружню конфігурацію для пакета".
Додавання класів для компіляції
Пакети можуть натякати Symfony про те, які з їх класів містять анотації, щоб
вони були скомпільовані при генеруванні кешу додатка для покращення загальної
ефективності. Визначте список класів з анотаціями для компіляції у методі
addAnnotatedClassesToCompile()
:
1 2 3 4 5 6 7 8 9 10 11 12 13
public function load(array $configs, ContainerBuilder $container): void
{
// ...
$this->addAnnotatedClassesToCompile([
// ви можете визначити повністю кваліфіковані імена класів...
'Acme\\BlogBundle\\Controller\\AuthorController',
// ... але також підтримуються глобальні патерни:
'Acme\\BlogBundle\\Form\\**',
// ...
]);
}
Note
Якщо якийсь клас розширюється з інших класів, всі його батьки автоматично додаються у список класів для компіляції.
Патерни трансформуються у справжні простори імен класів, викоирстовуючи карту класів,
згенеровану Composer. Отже, до використання цих схем, ви маєте згенерувати повну
карту класів, що виконує команду Composer dump-autoload
.
Caution
Ця техніка не може бути використана, коли класи для компіляції використовують
константи __DIR__
або __FILE__
, так як їх значення будуть змінюватися
при завантаженні цих класів з файлу classes.php
.