handbookНаписать

lessons/002-extract-repository/step-2/README.md · тема · 4 языка · 23 теста

Шаг 2: шлюз таблицы ​

Все SQL-строки для orders уезжают в класс OrdersTable, контроллер зовёт его методы, но всё ещё работает с рядами.

Урок: Выделение репозитория. Предыдущий шаг: SQL прямо в контроллере. Следующий: репозиторий в домене.

Что было ​

Контроллер писал SQL сам: один и тот же SELECT по id дважды, имена колонок в каждом методе, правило отмены между запросами.

Что меняем ​

Выделяем шлюз таблицы (Table Data Gateway): OrdersTable знает таблицу orders и только её. У него четыре метода по числу запросов: find(id) возвращает ряд или пусто, findByCustomer, insert сам берёт следующий id и возвращает его, updateStatus. Каждая SQL-строка теперь написана ровно один раз.

Контроллер получает OrdersTable в конструкторе вместо Database. Логика методов не меняется: те же проверки, те же ответы, только вместо query('SELECT ...') вызов find. Тесты не меняются вовсе, кроме строки сборки: new OrdersController(new OrdersTable(new Database())).

Это механический шаг, его можно делать почти без риска: переносим запрос в метод шлюза, заменяем вызов, гоняем тесты.

Как это собирается ​

Цепочка из трёх объектов: база, шлюз над ней, контроллер над шлюзом. В приложении её собирает контейнер, роутер только вызывает действия. Сценарий тот же, что на первом шаге, и вывод совпадает строка в строку.

Сценарий целиком с выводом: пример на PHP, он же на Go, Python и TypeScript в панели кода.

Что стало лучше ​

  • SQL в одном месте. Переименовать колонку или добавить запрос - правка одного класса.
  • Методы контроллера стали короче, и правило отмены стало заметнее: между find и updateStatus остались только проверки.
  • Шлюз можно проверить отдельно от HTTP, а контроллер больше не знает текста запросов.

Что ещё болит ​

  • Контроллер по-прежнему работает с рядами: $row['status'], row["total_cents"]. Он знает имена колонок, а в Go всё так же приводит any к строке.
  • Правило отмены всё ещё в контроллере. Шлюз - это таблица, а не заказ, ему правила не положены.
  • OrdersTable - конкретный класс над конкретной Database. Подменить его в тесте можно только наследованием или моком, и контроллер по-прежнему тестируется вместе с базой.

Запуск: make test T=lessons/002-extract-repository/step-2

© 2014-2026 Тимур ТурдыевСайт и справочник работают на VPS от AdminVPS