Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Що таке Chain of Responsibility і як на ньому побудовані middleware в Laravel?

Chain of Responsibility (Ланцюжок обов'язків) - запит проходить послідовністю обробників. Кожен вирішує: обробити запит і зупинити ланцюжок, або щось зробити й передати далі.

Middleware Laravel - саме такий ланцюжок:

final class EnsureUserIsSubscribed
{
    public function handle(Request $request, Closure $next): Response
    {
        if (! $request->user()?->subscribed()) {
            return redirect()->route('billing');   // зупинити ланцюжок
        }

        $response = $next($request);               // передати далі

        $response->headers->set('X-Plan', $request->user()->plan);   // після обробки
        return $response;
    }
}
  • $next($request) - виклик наступного обробника; код до нього виконується на шляху запиту, після - на шляху відповіді;
  • повернення відповіді без $next - ланцюжок зупиняється (автентифікація, CSRF, обмеження частоти, режим обслуговування);
  • обробники не знають один про одного - лише про $next.

Під капотом - Illuminate\Pipeline\Pipeline, який можна використати й для власних процесів:

$order = Pipeline::send($order)
    ->through([
        ValidateStock::class,
        ApplyDiscounts::class,
        CalculateTaxes::class,
        ReserveItems::class,
    ])
    ->thenReturn();

Кожен крок - клас з методом handle($order, Closure $next). Кроки легко переставити, додати, протестувати окремо.

Переваги:

  • відокремлення відправника від обробників;
  • набір і порядок обробників - конфігурація, а не код (групи middleware, порядок ->through());
  • кожен обробник з однією відповідальністю.

Пастки:

  • порядок має значення: middleware автентифікації після middleware, що використовує користувача, - помилка. Laravel має $middleware->priority() для впорядкування;
  • ніхто не обробив: у класичному варіанті запит може пройти весь ланцюжок без обробки - потрібен обробник за замовчуванням;
  • налагодження: довгий ланцюжок з побічними ефектами важко відстежити - кожен крок має бути простим;
  • продуктивність: глобальні middleware виконуються на кожен запит, тож у них не місце важким операціям.

Інші приклади: обробники винятків, валідатори з кількома правилами, системи знижок, ланцюжки фільтрів запитів (пошук з фільтрами - кожен фільтр додає умову й передає далі).

Докладніше в документації: Refactoring.Guru: Chain of Responsibility

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання