Лабораторная работа 7. Сервисы, Dependency Injection, autowiring и рефакторинг бизнес-логики
Аудиторная работа: 3 ак. ч.
Самостоятельная работа: 4 ак. ч.
Цель: вынести бизнес-правила из контроллеров в тестируемые сервисы.
Symfony построен вокруг Dependency Injection Container; при стандартной конфигурации autowiring позволяет внедрять зависимости по type hint. [19]
Задание
-
Проанализируйте существующие контроллеры.
-
Найдите бизнес-логику, которая не должна находиться в контроллере.
-
Создайте:
src/Service/PricingService.php
src/Service/OrderService.php
src/Service/DashboardService.php
src/Service/OrderNumberGenerator.php
-
Создайте интерфейс:
DiscountPolicyInterface
-
Реализуйте минимум три политики:
RegularDiscountPolicy
VolumeDiscountPolicy
VipCustomerDiscountPolicy
-
Каждая политика должна определять:
подходит ли она к заказу;
какую скидку применяет.
-
Используйте constructor dependency injection.
-
Запрещено:
$service = new PricingService(...);
внутри контроллера.
-
Настройте autowiring.
-
Одну зависимость настройте явно в:
config/services.yaml
-
Добавьте параметр:
business.max_discount
-
Значение:
30
-
PricingService не должен позволять итоговую скидку выше указанного ограничения.
-
Создайте enum:
OrderStatus
-
Реализуйте правила перехода:
NEW -> CONFIRMED
CONFIRMED -> PAID
PAID -> SHIPPED
SHIPPED -> COMPLETED
-
Реализуйте допустимый переход:
NEW -> CANCELLED
CONFIRMED -> CANCELLED
-
Запретите:
COMPLETED -> NEW
CANCELLED -> PAID
-
Переход статуса должен выполняться через OrderService.
-
Создайте unit tests для каждого допустимого и недопустимого перехода.
-
Создайте unit tests для каждой политики скидок.
-
Используйте test doubles там, где это оправданно.
PHPUnit предоставляет механизмы test stubs и mock objects для изоляции тестируемых компонентов. [20]
-
Выполните:
php bin/console debug:container
-
Выполните:
php bin/console debug:container PricingService
-
Сохраните результат:
docs/lab07-container.txt
Обязательный запрос ИИ-агенту рефакторинга
Ты — software architect.
Проанализируй src/Controller.
Найди:
бизнес-логику;
расчеты;
изменение статусов;
прямое использование EntityManager;
дублирующиеся правила.
Предложи рефакторинг в application/domain services.
Ограничения:
контроллер должен принимать HTTP request,
делегировать работу сервису,
формировать HTTP response.
Не создавай God Service.
Обязательный запрос ИИ-ревьюеру
Проверь dependency graph сервисов.
Найди:
циклические зависимости;
service locator anti-pattern;
скрытые зависимости;
создание сервисов через new;
избыточное использование EntityManager;
слишком большие сервисы.
Предложи минимальный рефакторинг.
Самопроверка
php bin/console lint:yaml config
php bin/console debug:container
php bin/phpunit
Критерии приемки
[ ] бизнес-логика вынесена из контроллеров
[ ] используется constructor injection
[ ] работает autowiring
[ ] имеется DiscountPolicyInterface
[ ] имеется минимум три реализации
[ ] реализованы правила статусов
[ ] недопустимые переходы блокируются
[ ] unit tests проходят
[ ] имеется AI log
Dependency injection делает зависимости класса явными и позволяет контейнеру Symfony автоматически создавать и связывать сервисы; constructor injection является штатно поддерживаемым вариантом. [21]
