Middleware Component

Компонент triangle/middleware предоставляет систему промежуточного ПО для обработки запросов.

Установка

composer require triangle/middleware

Создание Middleware

Создайте класс middleware, реализующий интерфейс Triangle\Middleware\MiddlewareInterface:

<?php

namespace App\Middleware;

use Triangle\Engine\Request;
use Triangle\Middleware\MiddlewareInterface;

class AuthMiddleware implements MiddlewareInterface
{
    public function process($request, callable $next)
    {
        // Проверка аутентификации
        if (!$request->session()->get('user_id')) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        // Передача управления следующему middleware или обработчику
        return $next($request);
    }
}

Регистрация Middleware

Через конфигурацию (config/middleware.php)

<?php
// config/middleware.php

return [
    // Глобальное middleware (применяется ко всем маршрутам)
    '' => [
        \App\Middleware\CorsMiddleware::class,
        \App\Middleware\LoggingMiddleware::class,
    ],
    
    // Middleware для конкретного приложения
    'api' => [
        \App\Middleware\ApiAuthMiddleware::class,
    ],
];

Структура конфигурации:

  • '' (пустая строка) — глобальное middleware для всех приложений
  • 'api' — middleware для приложения api
  • Можно указать несколько приложений с их middleware

На маршруте

use Triangle\Router;

Router::get('/dashboard', [DashboardController::class, 'index'])
    ->middleware(\App\Middleware\AuthMiddleware::class);

// Несколько middleware
Router::get('/admin', [AdminController::class, 'index'])
    ->middleware([
        \App\Middleware\AuthMiddleware::class,
        \App\Middleware\AdminMiddleware::class,
    ]);

Через группу маршрутов

Router::group('/admin', function () {
    Router::get('/dashboard', [DashboardController::class, 'index']);
    Router::get('/users', [UserController::class, 'index']);
})->middleware(\App\Middleware\AuthMiddleware::class);

Через аннотации в контроллере

<?php

namespace App\Controller;

use Triangle\Annotation\Middleware;
use Triangle\Engine\Request;

#[Middleware(\App\Middleware\AuthMiddleware::class)]
class UserController
{
    public function index(Request $request)
    {
        // ...
    }
    
    // Middleware только для конкретного метода
    #[Middleware(\App\Middleware\AdminMiddleware::class)]
    public function delete(Request $request)
    {
        // ...
    }
}

Через свойство класса

<?php

namespace App\Controller;

use Triangle\Engine\Request;

class UserController
{
    protected array $middleware = [
        \App\Middleware\AuthMiddleware::class,
    ];
    
    public function index(Request $request)
    {
        // ...
    }
}

Порядок выполнения Middleware

Middleware выполняются в следующем порядке:

  1. Глобальное middleware (из config/middleware.php, ключ '')
  2. Middleware приложения (из config/middleware.php, по ключу приложения)
  3. Middleware маршрута (указанное через ->middleware())
  4. Middleware контроллера (из свойства $middleware или аннотаций)
  5. Middleware метода (из аннотаций метода)

После выполнения всех middleware вызывается обработчик маршрута, затем middleware выполняются в обратном порядке для обработки ответа.

Примеры Middleware

CORS Middleware

<?php

namespace App\Middleware;

use Triangle\Engine\Request;
use Triangle\Middleware\MiddlewareInterface;

class CorsMiddleware implements MiddlewareInterface
{
    public function process($request, callable $next)
    {
        $response = $next($request);
        
        $response->header('Access-Control-Allow-Origin', '*');
        $response->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
        $response->header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
        
        return $response;
    }
}

Rate Limiting

<?php

namespace App\Middleware;

use Triangle\Engine\Request;
use Triangle\Middleware\MiddlewareInterface;
use Triangle\Support\Cache;

class RateLimitMiddleware implements MiddlewareInterface
{
    public function process($request, callable $next)
    {
        $key = 'rate_limit:' . $request->getRealIp();
        $count = Cache::get($key, 0);
        
        if ($count >= 100) {
            return response()->json(['error' => 'Too many requests'], 429);
        }
        
        Cache::set($key, $count + 1, 60); // 60 секунд
        
        return $next($request);
    }
}

Логирование запросов

<?php

namespace App\Middleware;

use Triangle\Engine\Request;
use Triangle\Middleware\MiddlewareInterface;
use Triangle\Support\Log;

class LoggingMiddleware implements MiddlewareInterface
{
    public function process($request, callable $next)
    {
        $startTime = microtime(true);
        
        $response = $next($request);
        
        $duration = microtime(true) - $startTime;
        
        Log::info('Request processed', [
            'method' => $request->method(),
            'path' => $request->path(),
            'status' => $response->getStatusCode(),
            'duration' => round($duration * 1000, 2) . 'ms',
        ]);
        
        return $response;
    }
}

Middleware для плагинов

Middleware можно регистрировать для конкретных плагинов:

<?php
// config/middleware.php

return [
    // Middleware для плагина
    'plugin.oauth' => [
        \App\Middleware\OAuthMiddleware::class,
    ],
];

Динамическое создание Middleware

Router::get('/admin', [AdminController::class, 'index'])
    ->middleware(function ($request, $next) {
        // Inline middleware
        if (!$request->session()->get('is_admin')) {
            return response()->json(['error' => 'Forbidden'], 403);
        }
        return $next($request);
    });