Система конфигурации Symfony — одна из ключевых тем экзамена. Нужно знать форматы конфигурации, приоритеты загрузки, работу с environment variables, параметрами и секретами.
Форматы конфигурации
Symfony поддерживает три формата конфигурации: YAML, PHP и XML.
YAML (самый распространённый)
# config/packages/framework.yaml
framework:
secret: '%env(APP_SECRET)%'
http_method_override: false
handle_all_throwables: true
php_errors:
log: true
session:
handler_id: null
cookie_secure: auto
cookie_samesite: lax
PHP (рекомендуемый в Symfony 8.0)
<?php
declare(strict_types=1);
// config/packages/framework.php
use Symfony\Config\FrameworkConfig;
return static function (FrameworkConfig $framework): void {
$framework->secret('%env(APP_SECRET)%');
$framework->httpMethodOverride(false);
$framework->handleAllThrowables(true);
$framework->phpErrors()
->log(true);
$framework->session()
->handlerId(null)
->cookieSecure('auto')
->cookieSameSite('lax');
};
XML
<!-- config/packages/framework.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:framework="http://symfony.com/schema/dic/symfony">
<framework:config secret="%env(APP_SECRET)%"
http-method-override="false"
handle-all-throwables="true">
<framework:php-errors log="true"/>
<framework:session handler-id="null"
cookie-secure="auto"
cookie-samesite="lax"/>
</framework:config>
</container>
Подвох экзамена: PHP-формат конфигурации обеспечивает автодополнение IDE (typed config classes вроде
FrameworkConfig). YAML — наиболее читаемый. XML — наиболее строгий (валидация по XSD). Все форматы равноценны по функциональности, но PHP стал рекомендуемым в Symfony 8.0.
Структура config/
config/
├── bundles.php # Registered bundles
├── packages/ # Package configuration
│ ├── cache.yaml # Cache configuration
│ ├── doctrine.yaml # Doctrine ORM
│ ├── framework.yaml # Framework core
│ ├── messenger.yaml # Messenger (queues)
│ ├── routing.yaml # Routing defaults
│ ├── security.yaml # Security
│ ├── twig.yaml # Twig templates
│ └── validator.yaml # Validator
├── packages/dev/ # Dev-only overrides
│ ├── debug.yaml
│ ├── monolog.yaml
│ └── web_profiler.yaml
├── packages/prod/ # Prod-only overrides
│ └── monolog.yaml
├── packages/test/ # Test-only overrides
│ └── framework.yaml
├── routes.yaml # Main routes
├── routes/ # Route imports
│ ├── framework.yaml
│ └── web_profiler.yaml
├── services.yaml # Service container
└── services_test.yaml # Test service overrides
Порядок загрузки конфигурации
1. config/packages/*.yaml — базовая конфигурация (все окружения)
2. config/packages/{env}/*.yaml — переопределения для конкретного окружения
3. config/services.yaml — определение сервисов
4. config/services_{env}.yaml — переопределения сервисов для окружения
Подвох экзамена: Файлы из
config/packages/dev/загружаются ПОСЛЕ файлов изconfig/packages/и ПЕРЕОПРЕДЕЛЯЮТ их. Еслиframework.yamlустанавливаетsession.handler_id: null, аdev/framework.yamlустанавливаетsession.handler_id: 'session.handler.native_file', в dev будет использоваться файловый handler.
Environment Variables
.env файлы
# .env — defaults, committed to Git
APP_ENV=dev
APP_SECRET=some-default-secret
DATABASE_URL="postgresql://user:[email protected]:5432/mydb?serverVersion=16"
# .env.local — local overrides, NOT committed
APP_SECRET=my-real-secret
DATABASE_URL="postgresql://root:root@db:5432/localdb"
# .env.test — test environment defaults
APP_ENV=test
DATABASE_URL="postgresql://test:[email protected]:5432/testdb"
# .env.test.local — local test overrides, NOT committed
Порядок загрузки .env
1. .env — defaults (committed)
2. .env.local — local overrides (not committed)
3. .env.{env} — environment-specific (committed)
4. .env.{env}.local — local env-specific (not committed)
| Файл | Git | Окружение | Приоритет |
|---|---|---|---|
.env |
Да | Все | Самый низкий |
.env.local |
Нет | Все кроме test | 2 |
.env.test |
Да | Test | 3 |
.env.test.local |
Нет | Test | Самый высокий |
Подвох экзамена:
.env.localНЕ загружается в test-окружении! Это предотвращает случайное использование production-переменных в тестах. Для тестов используйте.env.testи.env.test.local. Реальные env-переменные системы ВСЕГДА имеют наивысший приоритет.
Использование env-переменных в конфигурации
# config/packages/doctrine.yaml
doctrine:
dbal:
url: '%env(DATABASE_URL)%'
# Typed env processors
framework:
secret: '%env(APP_SECRET)%' # string (default)
parameters:
redis_port: '%env(int:REDIS_PORT)%' # cast to int
debug_mode: '%env(bool:DEBUG)%' # cast to bool
api_key: '%env(base64:API_KEY)%' # base64 decode
config: '%env(json:CONFIG_JSON)%' # JSON decode
db_url: '%env(resolve:DATABASE_URL)%' # resolve %param% inside
file: '%env(file:SECRET_FILE)%' # read file contents
trimmed: '%env(trim:SOME_VAR)%' # trim whitespace
url_parts: '%env(key:host:url:DATABASE_URL)%' # extract URL part
Environment Variable Processors
<?php
declare(strict_types=1);
// Available env processors in Symfony:
// string — default, no conversion
// bool — 'true'/'1' → true, 'false'/'0'/'' → false
// int — cast to integer
// float — cast to float
// json — json_decode
// base64 — base64_decode
// file — read file contents
// trim — trim whitespace
// key — extract key from parsed value
// url — parse_url()
// query_string — parse_str()
// resolve — resolve %parameters% in the value
// csv — str_getcsv()
// shuffle — shuffle array
// const — PHP constant value
// enum — PHP enum case
// default — fallback value if empty
// not — negate boolean
// require — throw if empty
// Chaining processors (right to left):
// '%env(int:trim:file:DATABASE_PORT_FILE)%'
// 1. Read file contents
// 2. Trim whitespace
// 3. Cast to int
Подвох экзамена: Env processors применяются справа налево (как функции).
%env(int:trim:FILE_VAR)%сначала вызоветtrim, потомint. Процессорdefaultпозволяет задать fallback:%env(default:fallback_param:MAYBE_EMPTY)%.
Parameters (параметры)
Параметры — это статические значения, доступные во всём приложении.
# config/services.yaml
parameters:
app.items_per_page: 20
app.supported_locales: ['en', 'ru', 'de']
app.admin_email: '[email protected]'
services:
App\Service\PaginationService:
arguments:
$itemsPerPage: '%app.items_per_page%'
Доступ к параметрам
<?php
declare(strict_types=1);
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\HttpFoundation\Response;
class SettingsController extends AbstractController
{
public function __construct(
// Inject parameter via #[Autowire]
#[Autowire('%app.items_per_page%')]
private readonly int $itemsPerPage,
#[Autowire('%app.admin_email%')]
private readonly string $adminEmail,
// Inject env variable
#[Autowire('%env(APP_SECRET)%')]
private readonly string $appSecret,
) {
}
public function index(): Response
{
// In controller — access via getParameter()
$locales = $this->getParameter('app.supported_locales');
return $this->json([
'items_per_page' => $this->itemsPerPage,
'locales' => $locales,
]);
}
}
Параметры vs Environment Variables
| Характеристика | Parameters | Env Variables |
|---|---|---|
| Где определяются | services.yaml |
.env, OS, Docker |
| Когда разрешаются | Компиляция контейнера | Runtime |
| Типизация | Автоматическая | Строки (нужны processors) |
| Использование | %param_name% |
%env(VAR_NAME)% |
| Назначение | Настройки приложения | Инфраструктура, секреты |
Подвох экзамена: Parameters разрешаются при компиляции контейнера (build time). Env variables разрешаются при ПЕРВОМ обращении (runtime). Поэтому для значений, которые зависят от среды (DATABASE_URL, API keys), всегда используйте env variables, а не parameters.
Secrets (секреты)
Symfony Secrets — встроенная система для безопасного хранения секретных значений.
# Generate encryption keys
php bin/console secrets:generate-keys
# Add a secret
php bin/console secrets:set DATABASE_PASSWORD
# Add for specific environment
php bin/console secrets:set DATABASE_PASSWORD --env=prod
# List secrets (names only, not values)
php bin/console secrets:list
# List with values (decrypted)
php bin/console secrets:list --reveal
# Remove a secret
php bin/console secrets:remove DATABASE_PASSWORD
Структура файлов секретов
config/
└── secrets/
├── prod/
│ ├── prod.encrypt.public.php # Public key (committed)
│ ├── prod.decrypt.private.php # Private key (NOT committed!)
│ └── prod.DATABASE_PASSWORD.28a...php # Encrypted secret
└── dev/
├── dev.encrypt.public.php
├── dev.decrypt.private.php
└── dev.DATABASE_PASSWORD.a3f...php
# config/packages/doctrine.yaml
doctrine:
dbal:
password: '%env(DATABASE_PASSWORD)%' # Resolved from secrets vault
Подвох экзамена: Секреты доступны как обычные env-переменные (
%env(SECRET_NAME)%). Если реальная env-переменная и секрет имеют одинаковое имя — env-переменная имеет приоритет. Это позволяет переопределять секреты в dev через.env.local.
Конфигурация сервисов
# config/services.yaml
services:
# Default settings for all services
_defaults:
autowire: true # Auto-inject dependencies
autoconfigure: true # Auto-apply tags (EventListener, Command, etc.)
# Auto-register all classes in src/ as services
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
# Explicit service definition with arguments
App\Service\PaymentGateway:
arguments:
$apiKey: '%env(PAYMENT_API_KEY)%'
$sandbox: '%env(bool:PAYMENT_SANDBOX)%'
# Service alias
App\Contract\PaymentInterface: '@App\Service\PaymentGateway'
# Tagged services
App\EventListener\AuditListener:
tags:
- { name: kernel.event_listener, event: kernel.request, priority: 10 }
PHP-формат конфигурации сервисов
<?php
declare(strict_types=1);
// config/services.php
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $container): void {
$services = $container->services()
->defaults()
->autowire()
->autoconfigure()
;
$services->load('App\\', '../src/')
->exclude([
'../src/DependencyInjection/',
'../src/Entity/',
'../src/Kernel.php',
])
;
$services->set(App\Service\PaymentGateway::class)
->arg('$apiKey', '%env(PAYMENT_API_KEY)%')
->arg('$sandbox', '%env(bool:PAYMENT_SANDBOX)%')
;
$services->alias(
App\Contract\PaymentInterface::class,
App\Service\PaymentGateway::class,
);
};
When (условная конфигурация)
# config/packages/framework.yaml
when@dev:
framework:
profiler:
collect: true
when@test:
framework:
test: true
session:
storage_factory_id: session.storage.factory.mock_file
when@prod:
framework:
profiler:
collect: false
<?php
declare(strict_types=1);
// config/packages/framework.php — PHP equivalent
use Symfony\Config\FrameworkConfig;
return static function (FrameworkConfig $framework, string $env): void {
if ($env === 'dev') {
$framework->profiler()->collect(true);
}
if ($env === 'test') {
$framework->test(true);
$framework->session()->storageFactoryId('session.storage.factory.mock_file');
}
if ($env === 'prod') {
$framework->profiler()->collect(false);
}
};
Symfony 8.0:
when@envсинтаксис в YAML полностью заменяет отдельные файлы вconfig/packages/dev/,config/packages/prod/. Оба подхода работают, ноwhen@позволяет хранить всю конфигурацию пакета в одном файле.
Debugging конфигурации
# Show all container parameters
php bin/console debug:container --parameters
# Show specific parameter
php bin/console debug:container --parameter=app.items_per_page
# Show all env variables used in config
php bin/console debug:container --env-vars
# Show specific env variable
php bin/console debug:container --env-var=DATABASE_URL
# Dump resolved configuration for a bundle
php bin/console debug:config framework
# Dump default config for a bundle
php bin/console config:dump-reference framework
# Show all services
php bin/console debug:container
# Find service by class
php bin/console debug:container App\Service\PaymentGateway