MidТеория5 min

Компоненты и бандлы

Standalone components, bundles vs libraries, bridges, полный список компонентов Symfony

Symfony — не монолитный фреймворк, а набор из 50+ самостоятельных компонентов. На экзамене проверяют понимание разницы между component, bundle и bridge, знание ключевых компонентов и их назначения.

Архитектура Symfony

Три типа пакетов

┌─────────────────────────────────────────────┐
│              Symfony Application              │
│                                               │
│  ┌──────────┐   ┌──────────┐   ┌──────────┐  │
│  │  Bundle   │   │  Bundle   │   │  Bundle   │ │
│  │(TwigBundle│   │(Security │   │(Doctrine  │ │
│  │          )│   │ Bundle)  │   │ Bundle)  │  │
│  └────┬─────┘   └────┬─────┘   └────┬─────┘  │
│       │              │              │          │
│  ┌────┴─────┐   ┌────┴─────┐   ┌────┴─────┐  │
│  │  Bridge   │   │Component │   │  Bridge   │ │
│  │(TwigBridge│   │(Security)│   │(Doctrine  │ │
│  │          )│   │          │   │ Bridge)  │  │
│  └────┬─────┘   └──────────┘   └────┬─────┘  │
│       │                              │         │
│  ┌────┴─────┐                  ┌────┴─────┐   │
│  │ 3rd party│                  │ 3rd party │   │
│  │ (Twig)   │                  │ (Doctrine)│   │
│  └──────────┘                  └──────────┘   │
└───────────────────────────────────────────────┘

Сравнение типов

Характеристика Component Bundle Bridge
Самостоятельный Да Нет Нет
Нужен FrameworkBundle Нет Да Нет
Установка без Symfony Да Нет Зависит
Конфигурация Программная YAML/XML/PHP Программная
Примеры HttpFoundation, Console TwigBundle, SecurityBundle TwigBridge, DoctrineBridge

Components (компоненты)

Компонент — самостоятельная PHP-библиотека, решающая конкретную задачу. Можно использовать в любом PHP-проекте без Symfony Framework.

<?php

declare(strict_types=1);

// Using Symfony Component WITHOUT Symfony Framework
// Just install: composer require symfony/http-foundation

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

$request = Request::createFromGlobals();
$name = $request->query->get('name', 'World');

$response = new Response(
    content: sprintf('Hello %s!', htmlspecialchars($name)),
    status: Response::HTTP_OK,
    headers: ['Content-Type' => 'text/plain'],
);

$response->send();

Ключевые компоненты Symfony

Ядро (Core)

Компонент Назначение Standalone
HttpFoundation Request/Response объекты Да
HttpKernel Обработка запросов, events pipeline Да
Routing Маршрутизация URL → Controller Да
DependencyInjection DI-контейнер (PSR-11) Да
EventDispatcher Система событий (PSR-14) Да
Config Загрузка и валидация конфигурации Да

Ввод/Вывод

Компонент Назначение Standalone
Console CLI-команды Да
Form Создание и обработка HTML-форм Да
Validator Валидация данных Да
Serializer Сериализация/десериализация Да

Безопасность и аутентификация

Компонент Назначение Standalone
Security Аутентификация и авторизация Частично
PasswordHasher Хэширование паролей Да
RateLimiter Ограничение частоты запросов Да

Инфраструктура

Компонент Назначение Standalone
Messenger Очереди сообщений Да
Mailer Отправка email Да
Notifier Уведомления (SMS, Slack, etc.) Да
Cache Кэширование (PSR-6, PSR-16) Да
HttpClient HTTP-клиент (PSR-18) Да
Lock Блокировки для concurrency Да
Scheduler Планирование задач (cron) Да

Утилиты

Компонент Назначение Standalone
Filesystem Операции с файловой системой Да
Finder Поиск файлов и директорий Да
Process Запуск внешних процессов Да
String Работа со строками (Slugger, etc.) Да
Uid UUID, ULID генерация Да
Yaml Парсинг YAML Да
ExpressionLanguage Выражения и условия Да
PropertyAccess Доступ к свойствам объектов Да

Подвох экзамена: Все компоненты Symfony можно использовать standalone. Однако для полноценной интеграции в Symfony-приложение нужен Bundle. Если вопрос спрашивает "можно ли использовать HttpFoundation вне Symfony" — ответ: да, это standalone-компонент.

Bundles (бандлы)

Bundle — это плагин для Symfony-приложения. Он интегрирует компоненты и библиотеки в фреймворк: регистрирует сервисы, добавляет конфигурацию, предоставляет команды.

<?php

declare(strict_types=1);

namespace App;

// Bundles are registered in config/bundles.php
// config/bundles.php
return [
    // Core framework — always required
    Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],

    // Template engine
    Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],

    // Database ORM
    Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],

    // Security
    Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],

    // Dev tools — only in dev/test
    Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
    Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
    Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
];

Структура бандла

<?php

declare(strict_types=1);

namespace Acme\BlogBundle;

use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

// Symfony 7+/8.0: AbstractBundle is the recommended base class
class AcmeBlogBundle extends AbstractBundle
{
    public function configure(DefinitionConfigurator $definition): void
    {
        $definition->rootNode()
            ->children()
                ->scalarNode('api_key')->isRequired()->end()
                ->integerNode('cache_ttl')->defaultValue(3600)->end()
            ->end()
        ;
    }

    public function loadExtension(
        array $config,
        ContainerConfigurator $container,
        ContainerBuilder $builder,
    ): void {
        $container->services()
            ->set('acme_blog.api_client', ApiClient::class)
                ->args([$config['api_key'], $config['cache_ttl']])
                ->autowire()
        ;
    }
}

Symfony 8.0: AbstractBundle полностью заменяет старые Bundle + Extension + Configuration. Методы configure() и loadExtension() объединяют конфигурацию и загрузку сервисов в одном классе. Старый подход с отдельной Extension deprecated.

Ключевые бандлы Symfony

Bundle Зависит от Предоставляет
FrameworkBundle HttpKernel, DI, Routing, etc. Базовый фреймворк, контроллеры
TwigBundle TwigBridge, Twig Шаблонизация
SecurityBundle Security component Аутентификация, авторизация
WebProfilerBundle Profiler, TwigBundle Debug toolbar, profiler
MonologBundle Monolog Логирование
DebugBundle VarDumper dump() функция
MakerBundle Console Генерация кода (make:controller, etc.)

Bridges (мосты)

Bridge — адаптер между компонентом Symfony и сторонней библиотекой. Он обеспечивает интеграцию без жёсткой связи.

<?php

declare(strict_types=1);

// Example: TwigBridge connects Symfony components with Twig library
// It provides:
// - Twig extensions for Symfony (routing, forms, security)
// - Form theme rendering
// - Translation integration

// DoctrineBridge connects Symfony with Doctrine
// It provides:
// - Form types for Doctrine entities
// - Validator constraints
// - Security user provider
// - Data collectors for profiler

// MonologBridge connects Symfony with Monolog
// It provides:
// - Processors for request data
// - Handlers for Symfony-specific logging

Полная цепочка на примере Twig

Twig (3rd-party library)
    ↑ uses
TwigBridge (Symfony ↔ Twig integration)
    ↑ configured by
TwigBundle (registers services, adds config, provides Twig in Symfony app)
    ↑ used by
Symfony Application
# Installing Twig — what Flex installs:
composer require twig

# Actually installs:
# - twig/twig (3rd-party library)
# - symfony/twig-bridge (integration)
# - symfony/twig-bundle (framework integration)
# - twig/extra-bundle (extra Twig extensions)

Полная цепочка на примере Doctrine

doctrine/orm + doctrine/dbal (3rd-party library)
    ↑ uses
symfony/doctrine-bridge (Symfony ↔ Doctrine integration)
    ↑ configured by
doctrine/doctrine-bundle (registers services, adds config)
doctrine/doctrine-migrations-bundle (migration commands)
    ↑ used by
Symfony Application

Подвох экзамена: Bridge НЕ зависит от FrameworkBundle — он работает на уровне компонентов. Это позволяет использовать Bridge и в standalone-проектах. Например, TwigBridge можно использовать без TwigBundle, если вы интегрируете Twig с Symfony Forms в не-Symfony проекте.

Создание собственного бандла

<?php

declare(strict_types=1);

namespace Acme\PaymentBundle;

use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;

class AcmePaymentBundle extends AbstractBundle
{
    public function configure(DefinitionConfigurator $definition): void
    {
        $definition->rootNode()
            ->children()
                ->scalarNode('gateway')
                    ->isRequired()
                    ->validate()
                        ->ifNotInArray(['stripe', 'paypal', 'braintree'])
                        ->thenInvalid('Invalid gateway %s')
                    ->end()
                ->end()
                ->scalarNode('api_key')->isRequired()->end()
                ->booleanNode('sandbox')->defaultTrue()->end()
            ->end()
        ;
    }

    public function loadExtension(
        array $config,
        ContainerConfigurator $container,
        ContainerBuilder $builder,
    ): void {
        // Load services definition
        $container->import('../config/services.yaml');

        // Set parameters from config
        $container->parameters()
            ->set('acme_payment.gateway', $config['gateway'])
            ->set('acme_payment.sandbox', $config['sandbox'])
        ;
    }
}

Соглашения именования бандлов

Правило Пример правильно Пример неправильно
Суффикс Bundle AcmePaymentBundle AcmePayment
Vendor prefix AcmePaymentBundle PaymentBundle
Имя класса = имя папки AcmePaymentBundle/ Payment/

Компоненты для сертификации

На экзамене чаще всего спрашивают эти компоненты:

<?php

declare(strict_types=1);

// HttpFoundation — Request/Response abstraction
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\StreamedResponse;

// HttpKernel — request handling pipeline
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

// Routing — URL matching and generation
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

// DependencyInjection — service container
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;

// EventDispatcher — event system
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;

// Validator — data validation
use Symfony\Component\Validator\Constraints as Assert;

// Security — authentication/authorization
use Symfony\Component\Security\Http\Attribute\IsGranted;

Подвох экзамена: HttpKernel\Exception\* — это HTTP-специфичные исключения. NotFoundHttpException автоматически конвертируется в 404 ответ, AccessDeniedHttpException — в 403. Не путайте с обычными PHP-исключениями. Symfony перехватывает HttpExceptionInterface в kernel.exception и создаёт соответствующий Response.


Проверь себя

Можно ли использовать `symfony/http-foundation` в проекте без Symfony Framework?

Что такое Bridge в архитектуре Symfony?

Какой компонент реализует PSR-14 (Event Dispatcher) в Symfony?

Какой базовый класс рекомендуется для создания бандлов в Symfony 7+/8.0?

Чем Component отличается от Bundle в Symfony?