Як визначати контролери як сервіси
Дата оновлення перекладу 2023-09-01
Як визначати контролери як сервіси
В Symfony контролер не повинен бути зареєстрований як сервіс. Але якщо ви використовуєте конфігурацію services.yaml за замовчуванням , і ваші контролери розширюють клас AbstractController, вони вже автоматично зареєстровані як сервіси. Це означає, що ви можете використовувати впровадження залежностей, як і будь-який інший нормальний сервіс.
Якщо ваші контроллери не розширюють клас AbstractController, ви повинні чітко помітити
ваші сервіси контролера як public
. Як варіант, ви можете застосувати тег controller.service_arguments
до ваших сервісів контролера. Це зробить теговані сервіси public
та дозволить вам
впроваджувати сервіси у параметрах методу:
1 2 3 4 5 6 7
# config/services.yaml
# контролери імпортуються окреми, щоб гарантувати, що сервіси можуть бути впроваджені
# в якості аргументу дії, навіть якщо ви не розширюєте ніякий базовий клас контролера
App\Controller\:
resource: '../src/Controller/'
tags: ['controller.service_arguments']
Note
Якщо ви не використовуєте ні автомонтування, ні
автоконфігурацію , і розширюєте AbstractController
,
вам потрібно буде застосувати інші теги та зробити так, щоб деякі виклики методів
реєстрували ваші контролери як сервіси:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
# config/services.yaml
# ця розширена конфігурація необхідна лише коли автомонтування/автоконфігурація
# не використовується, що не є поширеним та не рекомендується
abstract_controller.locator:
class: Symfony\Component\DependencyInjection\ServiceLocator
arguments:
-
router: '@router'
request_stack: '@request_stack'
http_kernel: '@http_kernel'
session: '@session'
parameter_bag: '@parameter_bag'
# тут ви можете додати більше сервісів, по мірі необхідності (наприклад, сервіс `serializer`)
# і подивитися на клас AbstractController, щоб побачити, які сервіси визначені
# в локаторі
App\Controller\:
resource: '../src/Controller/'
tags: ['controller.service_arguments']
calls:
- [setContainer, ['@abstract_controller.locator']]
За бажанням, ви можете використовувати PHP-атрибут #[AsController]
для автоматичного
застосування тегу controller.service_arguments
до сервісів вашого контролера:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// src/Controller/HelloController.php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Routing\Annotation\Route;
#[AsController]
class HelloController
{
#[Route('/hello', name: 'hello', methods: ['GET'])]
public function index(): Response
{
// ...
}
}
Реєстрація вашого контролера як сервісу - це перший крок, але ви також повинні переконатися, що ваш маршрутизатор коректно посилається на сервіс, щоб Symfony знала, що його потрібно використовувати.
Використовуйте синтаксис service_id::method_name
, щоб посилатися на метод контролера.
Якщо id сервісу є повністю кваліфікованим іменем класу (FQCN) вашого контролера, як рекомендує
Symfony, то синтаксис буде таким же, як якщо б контролер не був сервісом, на кшталт:
App\Controller\HelloController::index
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// src/Controller/HelloController.php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class HelloController
{
#[Route('/hello', name: 'hello', methods: ['GET'])]
public function index(): Response
{
// ...
}
}
Викличні контролери
Контролери також можуть визначати одну дію, використовуючи метод __invoke()
,
що є розповсюдженою практикою при дотриманні патерну ADR (Дія-Домен-Відповідач):
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// src/Controller/Hello.php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
#[Route('/hello/{name}', name: 'hello')]
class Hello
{
public function __invoke(string $name = 'World'): Response
{
return new Response(sprintf('Hello %s!', $name));
}
}
Альтернативи базових методів контролера
При використанні контролера, визначеного як сервіс, ви все ще можете розширити базовий контролер AbstractController та використовувати його скорочення. Але ви не повинні цього робити! Ви можете обрати не розширювати нічого та використати впровадження залежності, щоб отримати доступ до різних сервісів.
Базовий початковий код класу контролера - це чудовий спосіб дізнатися, як можна
досягти виконання загальних задач. Наприклад, $this->render()
зазвичай використовується
для відображення шаблону Twig та повернення Відповіді. Але ви також можете зробити це
напряму:
У контролері, визначеному як сервіс, ви можете замість цього впровадити сервіс
twig
та використати його напряму:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
// src/Controller/HelloController.php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
use Twig\Environment;
class HelloController
{
public function __construct(
private Environment $twig,
) {
}
public function index(string $name): Response
{
$content = $this->twig->render(
'hello/index.html.twig',
['name' => $name]
);
return new Response($content);
}
}
Ви також можете використати спеціальне впровадження залежності на основі дій , щоб отримувати сервіси в якості аргументів ваших методів дій контролера.
Базові методи контролера та їх сервісні заміни
- Найкращий спосіб побачити, як замінити базові допоміжні методи
Controller
-
- це подивитися на клас AbstractController, що містить його логіку.
Якщо ви хочете дізнатися, яке типізування використати для кожного сервісу, дивіться
метод getSubscribedServices()
в AbstractController.