Як завантажувати конфігурацію сервісу всередині пакета
Дата оновлення перекладу 2024-04-30
Як завантажувати конфігурацію сервісу всередині пакета
Сервіси, створені пакетами, не визначаються в основному файлі
config/services.yaml
, який використовується додатком, а визначаються
у самих пакетах. Ця стаття пояснює, як створювати та завантажувати файли
сервісу, використовуючи структуру каталогів пакета.
Створення класу розширення
Для того, щоб завантажувати конфігурацію сервісів, вам потрібно створити Розширення впровадження залежності (ВЗ) для вашого пакета. За замовчуванням, клас Розширення має слідувати таким угодам (але пізніше ви дізнаєтеся, як їх пропускати, якщо це необхідно):
- Воно має жити у просторі імен
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
). Щоб
прочитати більше про це, див. статтю "Як створити дружню конфігурацію для пакета".
Завантаження сервісів напряму у ваш клас Пакета
Як варіант, ви можете визначати та завантажувати конфігурацію сервісів напряму у
клас пакета замість створення спеціального класу Extension
. Ви можете зробити це,
розширивши з 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 $containerConfigurator, ContainerBuilder $containerBuilder): 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()
викликається тільки під час компіляції.
Додавання класів для компіляції
Пакети можуть натякати 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([
// ви можете визначити повністю кваліфіковані імена класів...
'App\\Controller\\DefaultController',
// ... але також підтримуються глобальні патерни:
'**Bundle\\Controller\\',
// ...
]);
}
Note
Якщо якийсь клас розширюється з інших класів, всі його батьки автоматично додаються у список класів для компіляції.
Патерни трансформуються у справжні простори імен класів, викоирстовуючи карту класів,
згенеровану Composer. Отже, до використання цих схем, ви маєте згенерувати повну
карту класів, що виконує команду Composer dump-autoload
.
Caution
Ця техніка не може бути використана, коли класи для компіляції використовують
константи __DIR__
або __FILE__
, так як їх значення будуть змінюватися
при завантаженні цих класів з файлу classes.php
.