Введение

Ключевые понятия

Пять идей, из которых следует всё остальное. Прочитав эту страницу, вы поймёте, как устроен любой Winter-проект и куда смотреть дальше.

Стереотипы

Приложение собирается из классов-стереотипов — базовых классов с чёткой ролью. Вы наследуетесь от нужного, а фреймворк знает, как его обнаружить и вызвать.

Стереотип Роль База
Controller Принимает HTTP-запрос, возвращает ответ Stereotype\Controller
Service Бизнес-логика Stereotype\Service
Repository Доступ к данным (PPA/ORM) Ppa\Stereotype\Repository
Middleware Обработка до/после контроллера Stereotype\Middleware
Job Фоновая задача Stereotype\Job
Cmd / CmdCustom Консольная команда Console\Inc\Cmd

Типичный поток запроса: Controller → Service → Repository. Стереотипы создаёт генератор call make.

Атрибуты вместо конфигов

Winter описывает поведение атрибутами прямо на классах, методах и свойствах — регистрировать что-либо вручную не нужно.

main/Controllers/UserController.php
#[RequestMapping('users')]              // префикс маршрутов класса
class UserController extends Controller
{
  #[Autowired] private UserService $service;   // внедрение зависимости

  #[GetMapping('{id}')]                          // маршрут GET /users/{id}
  public function show(#[PathVariable] int $id): ResponseEntity
  {
      return ResponseEntity::ok($this->service->find($id));
  }
}

Те же принципы работают для привязки запроса (#[RequestJson], #[RequestQuery]…), валидации (#[Valid], #[NotBlank]…) и маппинга ORM (#[Table], #[Id], #[Varchar]…).

Внедрение зависимостей (DI)

Контроллеры, сервисы, репозитории, команды и джобы создаются через DI-контейнер. Зависимости приходят через конструктор или свойство с #[Autowired] — вы не вызываете new руками.

Три жизненных цикла: #[Singleton] (один на процесс), #[Request] (один на запрос), #[Transient] (каждый раз новый). Подробности и ручные привязки — в пакете Winter DI.

Конфигурация: Boot

Вся настройка проекта — в одном файле bootstrap.php, в классе Boot extends BaseBoot. Вы переопределяете только нужные хуки; порядок вызова фиксирован:

text
1. configure()   → Kernel::init(): пути, .env, логирование, таймзона
2. DI scan       → автопоиск #[Singleton] / #[Request] / #[Transient]
3. providers($c) → ручные привязки, фабрики, значения
4. channels()    → доп. каналы логов
5. plugins()     → подприложения с префиксом маршрута
6. httpCors()    → глобальная политика CORS
7. health()      → эндпоинты /actuator

Все хуки, кроме configure(), опциональны — по умолчанию это разумные no-op’ы. Подробно — в Конфигурации.

Точки входа

Один и тот же Boot обслуживает все рантаймы — меняется лишь вызываемый метод:

Файл Рантайм Тело
public/index.php PHP-FPM / dev-сервер Boot::web()
server.php Swoole HTTP Boot::swoole()
call CLI Boot::cli($argv)
wKernelExecutor Исполнитель задач Boot::executor($argv)

Собираем вместе

Запрос GET /users/1 проходит так:

text
public/index.php → Boot::web()
→ Router резолвит #[GetMapping('{id}')] в UserController
→ DI создаёт контроллер и внедряет UserService
→ #[PathVariable] привязывает id = 1
→ метод возвращает ResponseEntity::ok(...)
→ ответ отправляется клиенту

Дальше