Дата обновления перевода 2022-01-03
Как создать приложение Symfony с несколькими ядрами¶
Caution
Создание приложений с несколькими ядрами больше не рекомендуется Symfony. Рассмотрите вариант создания нескольких маленьких приложений вместо этого.
В большинстве приложений Symfony входящие запросы обрабатываются фронт контроллером
public/index.php
, который инстанциирует класс src/Kernel.php
для создания ядра
приложения, загружающего пакеты и работающего с запросом лля генерирования ответа.
Подход одного ядра - это удобное решение, но приложения Symfony могут определять любое количество ядер. В то время, как окружения выполняют одно и то же приложение с разными конфигурациями, ядра могут выполнять разные части одного и того же приложения.
Вот наиболее распространённые случаи применения создания множества ядер:
- Приложение, которое определяет API, может определить два ядра по причине производительности. Первое ядро будет служить обычному приложению, а второе - реагировать только на API запросы, загружая пакеты и подключая меньше функций;
- Высокочувствительное приложение может также определять два ядра. Первое будет только загружать маршруты, совпадающие с публичными частями приложения. Второе - загружать остальное приложение и его доступ будет защищён веб-сервером;
- Приложение, ориентированное на микросервисы, может определять несколько ядер для выборочного подключения или отключения сервисов, превращая традиционное монолитное приложение в несколько микро-приложений.
Добавление нового ядра в приложение¶
Создание нового ядра в приложении - это процесс, состоящий из трёх шагов:
- Создайте новый фронт контроллер для загрузки нового ядра;
- Создайте новый класс ядра;
- Определите конфигурацию, загружаемую новым ядром.
Следующий пример показывает, как создать новое ядро для API заданного приложения Symfony.
Шаг 1) Создайте новый фронт контроллер¶
Вместо создания нового фронт контроллера с нуля, легче будет дублировать уже
существующий. Например, создайте public/api.php
из public/index.php
.
Далее, обновите код нового фронт контроллера, чтобы инстанциировать новый класс ядра,
вместо обычного класса Kernel
:
// public/api.php
// ...
$kernel = new ApiKernel(
$_SERVER['APP_ENV'] ?? 'dev',
$_SERVER['APP_DEBUG'] ?? ('prod' !== ($_SERVER['APP_ENV'] ?? 'dev'))
);
// ...
Tip
Другой подход заключается в том, чтобы оставить существующий фронт контроллер
index.php
, но добавить утверждение if
для загрузки другого ядра,
основанного на URL (например, если URL начинается с``/api``, используйте ApiKernel
).
Шаг 2) Создайте новый класс ядра¶
Теперь вам нужно определить класс ApiKernel
, используемый новым фронт контроллером.
Легче всего это сделать дублировав существующий файл src/Kernel.php`
и внеся в него
необходимые изменения.
В этом примере, ApiKernel
будет загружать меньше пакетов, чем Kernel по умолчанию.
Убедитесь в том, что вы также изменили локацию кеша, логов и файлов конфигурации, чтобы
они не сталкивались с файлами из src/Kernel.php
:
// src/ApiKernel.php
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
class ApiKernel extends Kernel
{
use MicroKernelTrait;
public function getProjectDir(): string
{
return \dirname(__DIR__);
}
public function getCacheDir(): string
{
return $this->getProjectDir().'/var/cache/api/'.$this->environment;
}
public function getLogDir(): string
{
return $this->getProjectDir().'/var/log/api';
}
protected function configureContainer(ContainerConfigurator $container): void
{
$container->import('../config/api/{packages}/*.yaml');
$container->import('../config/api/{packages}/'.$this->environment.'/*.yaml');
if (is_file(\dirname(__DIR__).'/config/api/services.yaml')) {
$container->import('../config/api/services.yaml');
$container->import('../config/api/{services}_'.$this->environment.'.yaml');
} else {
$container->import('../config/api/{services}.php');
}
}
protected function configureRoutes(RoutingConfigurator $routes): void
{
$routes->import('../config/api/{routes}/'.$this->environment.'/*.yaml');
$routes->import('../config/api/{routes}/*.yaml');
// ... загружать только, если маршруты конфигурации нужны для API
}
// Если вам нужно выполнить некоторую логику, чтобы решить, какие пакеты загружать,
// вы можете захотеть использовать вместо этого метод registerBundles()
private function getBundlesPath(): string
{
// load only the bundles strictly needed for the API
return $this->getProjectDir().'/config/api_bundles.php';
}
}
New in version 5.4: Метод getBundlesPath()
был представлен в Symfony 5.4.
Шаг 3) Определите конфигурацию ядра¶
Наконец, определите файлы конфигурации, которые будет загружать новый ApiKernel
.
Следуя коду выше, эта конфигурация будет жить в одном из множества файлов,
хранящихся в каталогах config/api/
и config/api/ENVIRONMENT_NAME/
.
Новые файлы конфигурации могут быть созданы с нуля при загрузке всего нескольких пакетов, так как это очень просто. В других случаях, дублируйте существующие в``config/packages/`` файлы конфигурации, или, что ещё лучше - импортируйте их и переопределите необходимые опции:
Выполнение команд с другим ядром¶
Скрипт bin/console
, используемый для запуска команд Symfony всегда использует
класс по умолчанию Kernel
, чтобы построить приложение и загрузить команды.
Если вам нужно выполнить консольные команды, используя новое ядро, дублируйте скрипт
bin/console
и переименуйте его (например, bin/api
).
Далее, замените инстанциирование Kernel
вашим собственным инстанциированием ядра
(например, ApiKernel
) и теперь вы можете выполнять команды, используя новое ядро
(например, php bin/api cache:clear
). Тепеоь вы можете выполнять команды, используя
новое ядро.
Note
Команды, доступные для каждого конспольного скрипта (например, bin/console
и bin/api
) могут отличаться, так как они зависят от пакетов, подключенных
дла каждого ядра, которые могут отличаться.
Отображение шаблонов, определённых в другом ядре¶
Если вы следуете Лучшим практикам Symfony, то шаблоны нового ядра будут храниться в
templates/
. Попытка отобразить эти шаблоны в другом ядре, приведут к
ошибки Не существует зарегистрированных путей для пространста имён “__main__”.
Чтобы решить эту проблему, добавьте следующую конфигурацию к вашему ядру:
1 2 3 4 5 | # config/api/twig.yaml
twig:
paths:
# позволяет использовать api/templates/ dir в ApiKernel
"%kernel.project_dir%/api/templates": ~
|
Выполнение тестов, используя другое ядро¶
В приложениях Symfony функциональные тесты по умолчанию расширяются из класса
WebTestCase
. Внутри этого класса,
метод под названием getKernelClass()
пытается найти класс ядра, для запуска
приложения во время тестирования. Логика этого метода не поддерживает приложения
с несколькими ядрами, так что ваши тесты не будут использовать правильное ядро.
Решением будет создать пользовательский базовый класс для функциональных тестов,
расширяющийся из класса WebTestCase
и переопределяющий метод getKernelClass()
,
чтобы возвращать полное имя класса ядра для использования:
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
// тесты, которым нужно, чтобы ApiKernel работал, теперь должны расширять этот
// класс ApiTestCase вместо класса WebTestCase по умолчанию
class ApiTestCase extends WebTestCase
{
protected static function getKernelClass()
{
return 'App\ApiKernel';
}
// это нужно, так как класс KernelTestCase содержит ссылку на созданное
// ранее ядро и его статичное свойство $kernel. Следовательно, если ваши
// функциональные тесты не запускают изолированный процесс, позднейший запуск
// теста для другого ядра будет повторно использовать созданный ранее экземпляр,
// указывающий на другое ядро
protected function tearDown()
{
parent::tearDown();
static::$class = null;
}
}
Добавление большего количества ядер в приложение¶
Если ваше приложеиие очень сложное и вы создаёте несколько ядер, то лучше хранить
их в собственных каталогах, вместо того, чтобы путаться с кучей файлов в каталоге
src/
по умолчанию:
1 2 3 4 5 6 7 8 9 10 11 12 | project/
├─ src/
│ ├─ ...
│ └─ Kernel.php
├─ api/
│ ├─ ...
│ └─ ApiKernel.php
├─ ...
└─ public/
├─ ...
├─ api.php
└─ index.php
|
Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.