Контроллеры в Symfony: первые шаги для новичка
Разберём, как создать первый контроллер в Symfony 7.x, вернуть JSON и HTML, принять параметры из URL и не запутаться в маршрутах. На выходе — рабочая страница за 20 минут.

К концу этой инструкции у вас будет работающий контроллер в Symfony 7.x: страница, которая отвечает на запрос по адресу вроде /hello/Ivan, возвращает и HTML, и JSON, и умеет принимать параметры из URL. На всё уйдёт примерно 20 минут, если PHP и Composer уже стоят. Контроллер — это обычный PHP-класс, метод которого вызывается, когда пользователь заходит по определённому адресу. Ничего магического, разберёмся по шагам.
Что нужно иметь до начала
Прежде чем писать первую строку, проверьте окружение. Если чего-то не хватает — доберите сейчас, а не на середине.
- PHP 8.2 или новее. Symfony 7.x требует минимум 8.2. Проверьте:
php -v. - Composer. Менеджер зависимостей PHP. Проверьте:
composer --version. - Symfony CLI (необязательно, но удобно для локального сервера). Проверьте:
symfony version. - Установленный проект Symfony. Если его нет, создайте веб-приложение командой ниже.
# Создаём новый проект Symfony 7.x с веб-пакетами
composer create-project symfony/skeleton:"7.*" my-app
cd my-app
# Добавляем пакет для аннотаций-атрибутов маршрутов и работы с вебом
composer require symfony/framework-bundle symfony/runtime
composer require symfony/maker-bundle --dev
Пакет maker-bundle ставится в dev — он генерирует заготовки и в продакшене не нужен.
Шаг 1. Создаём контроллер генератором
Проще всего не писать класс руками, а попросить maker-bundle сделать заготовку.
php bin/console make:controller HelloController
Команда создаст файл src/Controller/HelloController.php и шаблон templates/hello/index.html.twig. В консоли появится строка вида created: src/Controller/HelloController.php. Если она есть — заготовка на месте.
Шаг 2. Разбираем, что сгенерировалось
Откройте src/Controller/HelloController.php. Внутри будет примерно такой класс:
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class HelloController extends AbstractController
{
#[Route('/hello', name: 'app_hello')]
public function index(): Response
{
return $this->render('hello/index.html.twig', [
'controller_name' => 'HelloController',
]);
}
}
Что здесь происходит:
- Атрибут
#[Route('/hello', name: 'app_hello')]связывает адрес/helloс методом. Имяapp_hello— внутренняя метка маршрута, по ней потом генерируют ссылки. - Метод возвращает
Response. Это обязательное правило Symfony: контроллер обязан вернуть объектResponse, иначе получите ошибку. $this->render(...)берёт Twig-шаблон, подставляет переменные и заворачивает результат вResponse.
Обратите внимание: в Symfony 7.x атрибут маршрута импортируется из Symfony\Component\Routing\Attribute\Route. В версиях до 6.4 путь был другим — Symfony\Component\Routing\Annotation\Route. Если копируете чужой пример и получаете ошибку «class not found» — сверьте импорт с вашей версией.
Шаг 3. Запускаем и проверяем
Поднимите локальный сервер:
# Через Symfony CLI
symfony server:start
# Или встроенным сервером PHP, если CLI не установлен
php -S 127.0.0.1:8000 -t public/
Откройте в браузере http://127.0.0.1:8000/hello. Должна открыться страница-заглушка с текстом про HelloController. Если видите её — маршрут работает.
Проверить все зарегистрированные маршруты можно командой:
php bin/console debug:router
В таблице должна быть строка с именем app_hello и путём /hello.
Шаг 4. Принимаем параметр из URL
Теперь научим контроллер здороваться по имени. Часть пути в фигурных скобках Symfony передаст в аргумент метода с тем же именем.
#[Route('/hello/{name}', name: 'app_hello')]
public function index(string $name = 'аноним'): Response
{
// $name придёт из URL: /hello/Ivan даст $name === 'Ivan'
return $this->render('hello/index.html.twig', [
'name' => $name,
]);
}
Значение по умолчанию 'аноним' делает параметр необязательным: адрес /hello тоже сработает. Откройте /hello/Ivan — в шаблон уйдёт Ivan. Чтобы имя появилось на странице, поправьте templates/hello/index.html.twig, добавив в тело {{ name }}.
Контроллер не должен знать, как рисуется страница, и не должен лезть в базу напрямую. Его работа — принять запрос, вызвать нужную логику и вернуть Response. Всё, что толще пары строк, выносите в сервисы.
Шаг 5. Возвращаем JSON вместо HTML
Если страница нужна не человеку, а фронтенду или мобильному приложению, верните JSON. У AbstractController для этого есть готовый метод json().
#[Route('/api/hello/{name}', name: 'app_api_hello')]
public function apiHello(string $name = 'аноним'): Response
{
// json() сам сериализует массив и проставит заголовок Content-Type
return $this->json([
'message' => 'Привет, ' . $name,
'length' => mb_strlen($name),
]);
}
Откройте /api/hello/Ivan — в ответе увидите {"message":"Привет, Ivan","length":4} с заголовком Content-Type: application/json. Метод json() доступен, потому что класс наследует AbstractController. Если вы пишете контроллер без наследования, придётся вернуть new JsonResponse(...) вручную.
Атрибуты или YAML: где описывать маршруты
Symfony позволяет задавать маршруты не только атрибутами над методом, но и в файле config/routes.yaml. Для первых шагов выбирайте атрибуты — они лежат рядом с кодом и их не потеряешь.
| Способ | Где живёт | Когда удобнее |
|---|---|---|
Атрибуты #[Route] | Над методом контроллера | Большинство случаев, маршрут виден рядом с логикой |
YAML в config/routes.yaml | Отдельный конфиг | Когда нужно собрать все маршруты в одном месте или подключить внешний бандл |
Смешивать оба способа для одного и того же адреса нельзя — получите конфликт маршрутов.
Если не получилось
Самые частые ошибки на старте и что с ними делать:
No route found for "GET /hello"— маршрут не зарегистрирован. Проверьте атрибут#[Route]и очистите кеш:php bin/console cache:clear.The controller must return a "Response" object but it returned ...— метод вернул строку или массив вместоResponse. Оберните результат в$this->render(),$this->json()илиnew Response().Attribute class "Route" not found— неправильныйuse. Для Symfony 7.x должен бытьuse Symfony\Component\Routing\Attribute\Route;.Unable to find template "hello/index.html.twig"— не установлен Twig или нет файла шаблона. Поставьтеcomposer require twigи проверьте путь вtemplates/.- Белый экран без ошибки — вы в prod-окружении, где ошибки скрыты. Убедитесь, что в
.envстоитAPP_ENV=dev, и смотритеvar/log/dev.log.
Что дальше
Когда первый контроллер отвечает, двигайтесь к следующему:
- Прочитать входящие данные запроса — тип-хинт
Request $requestв аргументе метода и$request->query->get('...')для параметров строки запроса. - Связать контроллер с базой данных через Doctrine ORM — это отдельная большая тема, здесь мы её только обозначаем.
- Разобраться с генерацией ссылок по имени маршрута:
$this->generateUrl('app_hello', ['name' => 'Ivan']).
За устройством контроллеров и полным списком доступных методов AbstractController идите в официальную документацию Symfony — она версионирована, и раздел про контроллеры отвечает именно на вопросы старта.
Карточки для маркетплейсов: Таблица товаров и папка фотографий на входе — комплект слайдов и описаний на выходе, по требованиям Wildberries и Ozon.
Спросить за 5 ₽Источники: Symfony Docs — Controller, Symfony Docs — Routing
Частые вопросы
А если у меня Symfony 6.4, а не 7.x?
Обязательно ли наследовать AbstractController?
Почему страница открывается, но параметр {name} пустой?
Что делать, если после изменения маршрута страница не обновляется?
Можно ли в одном контроллере иметь несколько методов-действий?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.