Як визначати контролери як сервіси

Дата оновлення перекладу 2022-12-14

Як визначати контролери як сервіси

В Symfony контролер не повинен бути зареєстрований як сервіс. Але якщо ви використовуєте конфігурацію services.yaml за замовчуванням , і ваші контролери розширюють клас AbstractController, вони вже автоматично зареєстровані як сервіси. Це означає, що ви можете використовувати впровадження залежностей, як і будь-який інший нормальний сервіс.

Якщо ваші контроллери не розширюють клас AbstractController, ви повинні чітко помітити ваші сервіси контролера як public. Як варіант, ви можете застосувати тег controller.service_arguments до ваших сервісів контролера. Це зробить теговані сервіси public та дозволить вам впроваджувати сервіси у параметрах методу:

  • YAML
1
2
3
4
5
6
7
# config/services.yaml

# контролери імпортуються окреми, щоб гарантувати, що сервіси можуть бути впроваджені
# в якості аргументу дії, навіть якщо ви не розширюєте ніякий базовий клас контролера
App\Controller\:
   resource: '../src/Controller/'
   tags: ['controller.service_arguments']

If you prefer, you can use the #[AsController] PHP attribute to automatically apply the controller.service_arguments tag to your controller services:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// src/Controller/HelloController.php
namespace App\Controller;

use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Routing\Annotation\Route;

#[AsController]
class HelloController
{
    #[Route('/hello', name: 'hello', methods: ['GET'])]
    public function index()
    {
        // ...
    }
}

Реєстрація вашого контролера як сервісу - це перший крок, але ви також повинні переконатися, що ваш маршрутизатор коректно посилається на сервіс, щоб Symfony знала, що його потрібно використовувати.

Використовуйте синтаксис service_id::method_name, щоб посилатися на метод контролера. Якщо id сервісу є повністю кваліфікованим іменем класу (FQCN) вашого контролера, як рекомендує Symfony, то синтаксис буде таким же, як якщо б контролер не був сервісом, на кшталт: App\Controller\HelloController::index:

  • Attributes
  • YAML
  • XML
  • PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
// src/Controller/HelloController.php
namespace App\Controller;

use Symfony\Component\Routing\Annotation\Route;

class HelloController
{
    #[Route('/hello', name: 'hello', methods: ['GET'])]
    public function index()
    {
        // ...
    }
}

Викличні контролери

Контролери також можуть визначати одну дію, використовуючи метод __invoke(),
що є розповсюдженою практикою при дотриманні патерну ADR (Дія-Домен-Відповідач):

  • Attributes
  • YAML
  • XML
  • PHP
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($name = 'World')
    {
        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
24
25
// src/Controller/HelloController.php
namespace App\Controller;

use Symfony\Component\HttpFoundation\Response;
use Twig\Environment;

class HelloController
{
    private $twig;

    public function __construct(Environment $twig)
    {
        $this->twig = $twig;
    }

    public function index($name)
    {
        $content = $this->twig->render(
            'hello/index.html.twig',
            ['name' => $name]
        );

        return new Response($content);
    }
}

Ви також можете використати спеціальне впровадження залежності на основі дій , щоб отримувати сервіси в якості аргументів ваших методів дій контролера.

Базові методи контролера та їх сервісні заміни

Найкращий спосіб побачити, як замінити базові допоміжні методи Controller
  • це подивитися на клас AbstractController, що містить його логіку.

Якщо ви хочете дізнатися, яке типізування використати для кожного сервісу, дивіться метод getSubscribedServices() в AbstractController.