diff --git a/README.md b/README.md index 7de0c9dd..f8faf3f7 100755 --- a/README.md +++ b/README.md @@ -2,18 +2,42 @@ [![Maintainability](https://qlty.sh/badges/d9252114-5cc4-405e-bbf7-6419ec50266f/maintainability.svg)](https://qlty.sh/gh/Jagepard/projects/Rudra-Router) [![CodeFactor](https://www.codefactor.io/repository/github/jagepard/rudra-router/badge)](https://www.codefactor.io/repository/github/jagepard/rudra-router) [![Coverage Status](https://coveralls.io/repos/github/Jagepard/Rudra-Router/badge.svg?branch=master)](https://coveralls.io/github/Jagepard/Rudra-Router?branch=master) + ----- # Rudra-Router -#### Basic installation / Базовая установка +A lightweight and transparent HTTP router for PHP. Supports dynamic parameters, regular expressions, middleware, and RESTful resources. + +## Features + +- Dynamic URL parameters (`:name`) and regular expressions (`:[\d]{1,3}`) +- All HTTP methods supported: GET, POST, PUT, PATCH, DELETE +- Method spoofing via `_method` (for PUT/PATCH/DELETE from POST requests) +- Middleware executed before and after controller execution +- RESTful resources in a single line +- Automatic dependency injection via IoC container +- Works via instance or Facade + +## Installation + +```bash +composer require rudra/router +``` + +## Basic Usage + +### Initialization + ```php use Rudra\Router\Router; use Rudra\Container\Rudra; $router = new Router(Rudra::run()); ``` -#### Installation for facade use / Установка для использования фасада + +### Facade Usage + ```php use Rudra\Container\Facades\Rudra; use Rudra\Router\RouterFacade as Router; @@ -22,113 +46,216 @@ use Rudra\Container\Interfaces\RudraInterface; Rudra::binding()->set([RudraInterface::class => Rudra::run()]); ``` -#### Setting the route / Устанавливаем маршрут callback/:name +## Route Definition + +### Simple Routes with Closure + ```php -$router->get('callback/:name', function ($name) { +$router->get('hello/:name', function ($name) { echo "Hello $name!"; }); ``` -_with Regex_ + +### With Regular Expressions + ```php -$router->get('callback/:[\d]{1,3}', function ($name) { - echo "Hello $name!"; +$router->get('user/:[\d]{1,3}', function ($id) { + echo "User ID: $id"; }); ``` -_To call through the Facade / Для вызова через Фасад_ + +### Controller Method Call + ```php -Router::get('callback/:name', function ($name) { - echo "Hello $name!"; -}); +$router->get('read/:id', [MainController::class, 'read']); ``` -_with Regex_ + +### Via Facade + ```php -Router::get('callback/:[\d]{1,3}', function ($name) { +Router::get('callback/:name', function ($name) { echo "Hello $name!"; }); -``` -_call / вызывает MainController::read_ -```php -$router->get('read/:id', [MainController::class, 'read']); -``` -_To call through the Facade / Для вызова через Фасад_ -```php + Router::get('read/:id', [MainController::class, 'read']); ``` -_call MainController::read with middleware_ + +## HTTP Methods + ```php -$router->get('read/page', [MainController::class, 'read'], ['before' => [Middleware::class]); +$router->get('read/:id', [MainController::class, 'read']); +$router->post('create/:id', [MainController::class, 'create']); +$router->put('update/:id', [MainController::class, 'update']); +$router->patch('patch/:id', [MainController::class, 'patch']); +$router->delete('delete/:id', [MainController::class, 'delete']); ``` -_To call through the Facade / Для вызова через Фасад_ + +### Any Method (GET|POST|PUT|PATCH|DELETE) + ```php -Router::get('read/page', [MainController::class, 'read'], ['before' => [Middleware::class]); +$router->any('any/:id', [MainController::class, 'any']); ``` -_С параметрами для middleware_ + +## Middleware + +Middleware runs before (`before`) and after (`after`) the controller. Each middleware must implement the `__invoke()` method. + +### Basic Setup + ```php -$router->get('', [MainController::class, 'read'], [ - 'before' => [FirstMidddleware::class, [SecondMidddleware::class, ['int' => 456, new \stdClass]]], - 'after' => [FirstMidddleware::class, [SecondMidddleware::class, ['int' => 456, new \stdClass]]] +$router->get('read/page', [MainController::class, 'read'], [ + 'before' => [AuthMiddleware::class], + 'after' => [LogMiddleware::class] ]); ``` -_call / вызывает MainController::create_ -```php -$router->post('create/:id', [MainController::class, 'create']); -``` -_call / вызывает MainController::update_ + +### Middleware with Parameters + ```php -$router->put('update/:id', [MainController::class, 'update']); +$router->get('admin/:id', [AdminController::class, 'show'], [ + 'before' => [ + AuthMiddleware::class, + [RoleMiddleware::class, ['role' => 'admin', new PermissionChecker()]] + ], + 'after' => [ + LogMiddleware::class, + [CacheMiddleware::class, ['ttl' => 3600]] + ] +]); ``` -_call / вызывает MainController::update_ + +### Middleware Example + ```php -$router->patch('update/:id', [MainController::class, 'update']); +use Rudra\Router\RouterFacade as Router; + +class AuthMiddleware +{ + public function __invoke($next, ...$params) + { + // Logic before controller + if (!Auth::check()) { + throw new UnauthorizedException(); + } + + // Pass control to the next middleware in chain + if ($next) { + Router::handleMiddleware($next); + } + + // Logic after controller (optional) + } +} ``` -_call / вызывает MainController::delete_ + +Simple middleware without chain: + ```php -$router->delete('delete/:id', [MainController::class, 'delete']); +class UnsetSessionMiddleware +{ + public function __invoke($next, ...$params) + { + Session::remove('value'); + Session::remove('alert'); + Session::remove('errors'); + + if ($next) { + Router::handleMiddleware($next); + } + } +} ``` -_call / вызывает MainController::any 'GET|POST|PUT|PATCH|DELETE'_ +## RESTful Resources + +A single line registers all standard CRUD routes: + ```php -$router->any('any/:id', [MainController::class, 'any']); +$router->resource('api/users', UserController::class); ``` -_call / вызывает MainController::read для GET_ -_call / вызывает MainController::create для POST_ +This creates the following routes: -_call / вызывает MainController::update для PUT_ +| Method | URL | Controller Method | +|--------|-----------|-------------------| +| GET | api/users | read | +| POST | api/users | create | +| PUT | api/users | update | +| PATCH | api/users | update | +| DELETE | api/users | delete | + +### Custom Method Names -_call / вызывает MainController::delete для DELETE_ -```php -$router->resource('api/:id', MainController::class); -``` -Изменить методы контроллера по умолчанию можно передав массив с вашими именами\ -You can change the default controller methods by passing an array with your names ```php -$router->resource('api/:id', MainController::class, ['actionIndex', 'actionAdd', 'actionUpdate', 'actionDrop']); +$router->resource('api/posts', PostController::class, [ + 'actionIndex', + 'actionAdd', + 'actionUpdate', + 'actionDrop' +]); ``` -#### A variant of declaring a route using the set method / Вариант объявления маршрута методом set -_call / вызывает MainController::actionIndex_ +## The set() Method — Extended Syntax + +Allows defining a route with multiple HTTP methods via `|`: + ```php -$router->set(['/test/:id', 'DELETE|PUT', [MainController::class, 'actionIndex'], [ - 'before' => [First::class, Second::class], - 'after' => [[First::class], [Second::class]] -]]); +$router->set([ + 'url' => '/api/users/:id', + 'method' => 'GET|POST', + 'controller' => [UserController::class, 'handle'], + 'middleware' => [ + 'before' => [AuthMiddleware::class], + 'after' => [LogMiddleware::class] + ] +]); ``` -_Exemple / Пример Middleware_ + +## Controller Lifecycle + +When a controller method is invoked, the following stages are executed: + +1. `shipInit()` — base component initialization +2. `containerInit()` — container initialization +3. `init()` — user-defined initialization +4. `before()` — hook before middleware +5. **`before` middleware** +6. **Action method call** (with automatic dependency injection) +7. **`after` middleware** +8. `after()` — hook after middleware + +## Automatic Dependency Injection + +Action method parameters are automatically resolved via the IoC container: + ```php -/** - * Handles requests as a middleware using __invoke(). - */ -class SomeMiddleware +class UserController extends Controller { - public function __invoke($next, ...$params) + public function show(int $id, Request $request, UserService $service) { - // Logic here - - if ($next) { - $next(); - } + // $id — from URL + // $request and $service — injected automatically } } ``` + +## Method Spoofing + +For forms that do not support PUT/PATCH/DELETE, use the `_method` parameter: + +```html +
+ + +
+``` + +The router automatically recognizes this as a PUT request. + +## Error Handling + +- `RouterException("Not Found", 404)` — route not found or parameters do not match +- `RouterException("Service Unavailable", 503)` — controller method does not exist +- `MiddlewareException` — error in the middleware chain + ## License This project is licensed under the **Mozilla Public License 2.0 (MPL-2.0)** — a free, open-source license that: @@ -139,14 +266,4 @@ This project is licensed under the **Mozilla Public License 2.0 (MPL-2.0)** — - Permits combining with proprietary code in larger works. 📄 Full license text: [LICENSE](./LICENSE) -🌐 Official MPL-2.0 page: https://mozilla.org/MPL/2.0/ - --------------------------- -Проект распространяется под лицензией **Mozilla Public License 2.0 (MPL-2.0)**. Это означает: - - Вы можете свободно использовать, изменять и распространять код. - - При изменении файлов, содержащих исходный код из этого репозитория, вы обязаны оставить их открытыми под той же лицензией. - - Вы **обязаны сохранять уведомления об авторстве** и ссылку на оригинал. - - Вы можете встраивать код в проприетарные проекты, если исходные файлы остаются под MPL. - -📄 Полный текст лицензии (на английском): [LICENSE](./LICENSE) -🌐 Официальная страница: https://mozilla.org/MPL/2.0/ \ No newline at end of file +🌐 Official MPL-2.0 page: https://mozilla.org/MPL/2.0/ \ No newline at end of file diff --git a/composer.json b/composer.json index d9c06502..1ffb92bb 100755 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "source": "https://github.com/Jagepard/Rudra-Router" }, "require": { - "php": ">=8.3", + "php": "^8.3", "rudra/annotation": "self.version", "rudra/container" : "self.version", "rudra/exception" : "self.version" diff --git a/docs.md b/docs.md index 02f23775..7a6dc644 100644 --- a/docs.md +++ b/docs.md @@ -1,38 +1,59 @@ ## Table of contents +- [Rudra\Router\Attributes\Middleware](#rudra_router_attributes_middleware) +- [Rudra\Router\Attributes\Routing](#rudra_router_attributes_routing) - [Rudra\Router\Router](#rudra_router_router) - [Rudra\Router\RouterFacade](#rudra_router_routerfacade) - [Rudra\Router\RouterInterface](#rudra_router_routerinterface) -- [Rudra\Router\Routing](#rudra_router_routing) - [Rudra\Router\Traits\RouterAnnotationTrait](#rudra_router_traits_routerannotationtrait) - [Rudra\Router\Traits\RouterRequestMethodTrait](#rudra_router_traits_routerrequestmethodtrait) -
+ + +--- + + + + + +### Class: Rudra\Router\Attributes\Middleware +| Visibility | Function | +|:-----------|:---------| +| public | `__construct(string $name, ?string $params)`
| + + + + +### Class: Rudra\Router\Attributes\Routing +| Visibility | Function | +|:-----------|:---------| +| public | `__construct(string $url, array\|string $method)`
| + ### Class: Rudra\Router\Router | Visibility | Function | |:-----------|:---------| -| public | `set(array $route): void`
Sets the route, parsing HTTP methods (if multiple are specified via \|).
Registers a route handler for each method.
-------------------------
Устанавливает маршрут, разбирая HTTP-методы (если указано несколько через \|).
Для каждого метода регистрирует обработчик маршрута. | -| private | `handleRequestUri(array $route): void`
Processes the incoming URI request and checks if it matches the current route.
-------------------------
Обрабатывает входящий URI-запрос и проверяет его совпадение с текущим маршрутом. | -| private | `handleRequestMethod(): void`
Processes the HTTP request method, including spoofing via _method (for PUT/PATCH/DELETE)
-------------------------
Обрабатывает HTTP-метод запроса, включая spoofing через _method (для PUT/PATCH/DELETE) | -| private | `handlePattern(array $route, array $request): array`
Matches the URI from the route with the actual request, processing parameters of the form :param and :regexp.
This method is used to extract dynamic segments from a URI pattern:
-------------------------
Сопоставляет URI из маршрута с фактическим запросом, обрабатывая параметры вида :param и :regexp.
Метод извлекает динамические сегменты из URL-шаблона: | -| private | `setCallable(array $route, ?array $params): void`
Calls the controller associated with the route — either a Closure or a controller method.
-------------------------
Вызывает контроллер, связанный с маршрутом — либо Closure, либо метод контроллера. | -| public | `directCall(array $route, ?array $params): void`
Calls the controller and its method directly, performing the full lifecycle:
This method is used to fully dispatch a route after matching it with the current request.
-------------------------
Вызывает контроллер и его метод напрямую, выполняя полный жизненный цикл:
Метод используется для полной диспетчеризации маршрута после его совпадения с текущим запросом. | -| private | `callActionThroughReflection(?array $params, string $action, object $controller): void`
Calls the controller method using Reflection, performing automatic parameter injection based on type hints.
This method is typically used when the zend.exception_ignore_args setting is enabled,
allowing for more flexible and type-safe dependency resolution.
-------------------------
Вызывает метод контроллера с помощью Reflection, выполняя автоматическое внедрение параметров на основе типизации.
Этот метод обычно используется, когда включена настройка zend.exception_ignore_args,
что позволяет более гибко и безопасно разрешать зависимости по типам. | -| private | `callActionThroughException(?array $params, string $action, object $controller): void`
Calls the specified controller method directly.
If the argument type or number does not match — tries to automatically inject required dependencies.
This is a fallback mechanism for cases where Reflection-based injection is disabled or unavailable.
Handles two types of errors during invocation:
- \ArgumentCountError — thrown when the number of arguments doesn't match the method signature.
- \TypeError — thrown when an argument is not compatible with the expected type.
In both cases, Rudra's autowire system attempts to resolve and inject the correct dependencies.
-------------------------
Вызывает указанный метод контроллера напрямую.
Если тип или количество аргументов не совпадает — пытается автоматически внедрить нужные зависимости.
Это механизм отката, используемый, когда недоступен вызов через Reflection.
Обрабатываются следующие ошибки:
- \ArgumentCountError — выбрасывается, если количество аргументов не совпадает с ожидаемым.
- \TypeError — выбрасывается, если тип аргумента не соответствует ожидаемому.
В обоих случаях система автовайринга Rudra пытается разрешить и внедрить правильные зависимости. | -| public | `handleMiddleware(array $chain): void`
Executes a chain of middleware, recursively calling each element.
Middleware can be specified in one of the supported formats:
- 'MiddlewareClass' (string) — a simple class name to call without parameters.
- ['MiddlewareClass'] (array with class name) — same as above, allows for future extensions.
- ['MiddlewareClass', \$parameter] (array with class and parameter) — passes the parameter to the middleware.
Each middleware must implement the __invoke() method to be callable.
--------------------
Выполняет цепочку middleware, рекурсивно вызывая каждый элемент.
Middleware может быть указан в одном из поддерживаемых форматов:
- 'MiddlewareClass' (строка) — простое имя класса без параметров.
- ['MiddlewareClass'] (массив с именем класса) — аналогично предыдущему, удобно для расширения.
- ['MiddlewareClass', \$parameter] (массив с классом и параметром) — передаёт параметр в middleware.
Каждый middleware должен реализовывать метод __invoke(), чтобы быть вызываемым. | -| public | `annotationCollector(array $controllers, bool $getter, bool $attributes): ?array`
Collects and processes annotations from the specified controllers.
This method scans each controller class for Routing and Middleware annotations,
builds route definitions based on those annotations, and either:
- Registers them directly via `set()` (if \$getter = false), or
- Returns them as an array (if \$getter = true).
--------------------
Собирает и обрабатывает аннотации указанных контроллеров.
Метод сканирует каждый контроллер на наличие аннотаций Routing и Middleware,
формирует определения маршрутов и либо:
- Регистрирует их напрямую через `set()` (если \$getter = false),
- Возвращает как массив (если \$getter = true). | -| protected | `handleAnnotationMiddleware(array $annotation): array`
Processes middleware annotations into a valid middleware format.
--------------------
Обрабатывает аннотации middleware в поддерживаемый формат.
```#[Middleware(name: "Auth", params: "admin")]```
в:
```['Auth', 'admin']``` | +| public | `set(array $route): void`
Sets the route, parsing HTTP methods (if multiple are specified via \|).
Registers a route handler for each method. | +| private | `handleRequestUri(array $route): void`
Processes the incoming URI request and checks if it matches the current route. | +| private | `handleRequestMethod(): void`
Processes the HTTP request method, including spoofing via _method (for PUT/PATCH/DELETE) | +| private | `handlePattern(array $route, array $request): array`
Matches the URI from the route with the actual request, processing parameters of the form :param and :regexp.
This method is used to extract dynamic segments from a URI pattern | +| private | `setCallable(array $route, ?array $params): void`
Calls the controller associated with the route — either a Closure or a controller method. | +| public | `directCall(array $route, ?array $params): void`
Calls the controller and its method directly, performing the full lifecycle:
This method is used to fully dispatch a route after matching it with the current request. | +| private | `callActionThroughReflection(?array $params, string $action, object $controller): void`
Calls the controller method using Reflection, performing automatic parameter injection based on type hints.
This method is typically used when the zend.exception_ignore_args setting is enabled,
allowing for more flexible and type-safe dependency resolution. | +| private | `callActionThroughException(?array $params, string $action, object $controller): void`
Calls the specified controller method directly.
If the argument type or number does not match — tries to automatically inject required dependencies.
This is a fallback mechanism for cases where Reflection-based injection is disabled or unavailable.
Handles two types of errors during invocation:
- \ArgumentCountError — thrown when the number of arguments doesn't match the method signature.
- \TypeError — thrown when an argument is not compatible with the expected type.
In both cases, Rudra's autowire system attempts to resolve and inject the correct dependencies. | +| public | `handleMiddleware(array $chain): void`
Executes a chain of middleware, recursively calling each element.
Middleware can be specified in one of the supported formats:
- 'MiddlewareClass' (string) — a simple class name to call without parameters.
- ['MiddlewareClass'] (array with class name) — same as above, allows for future extensions.
- ['MiddlewareClass', \$parameter] (array with class and parameter) — passes the parameter to the middleware.
Each middleware must implement the __invoke() method to be callable. | +| public | `annotationCollector(array $controllers, bool $getter, bool $attributes): ?array`
Collects and processes annotations from the specified controllers.
This method scans each controller class for Routing and Middleware annotations,
builds route definitions based on those annotations, and either:
- Registers them directly via `set()` (if \$getter = false), or
- Returns them as an array (if \$getter = true). | +| protected | `handleAnnotationMiddleware(array $annotation): array`
Processes middleware annotations into a valid middleware format.
```#[Middleware(name: "Auth", params: "admin")]```
to:
```['Auth', 'admin']``` | | public | `__construct(Rudra\Container\Interfaces\RudraInterface $rudra)`
| | public | `rudra(): Rudra\Container\Interfaces\RudraInterface`
| -| public | `get(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the GET HTTP method.
--------------------
Регистрирует маршрут с использованием метода GET. | -| public | `post(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the POST HTTP method.
--------------------
Регистрирует маршрут с использованием метода POST. | -| public | `put(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the PUT HTTP method.
--------------------
Регистрирует маршрут с использованием метода PUT. | -| public | `patch(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the PATCH HTTP method.
--------------------
Регистрирует маршрут с использованием метода PATCH. | -| public | `delete(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the DELETE HTTP method.
--------------------
Регистрирует маршрут с использованием метода DELETE. | -| public | `any(string $pattern, callable\|array $target, array $middleware): void`
Registers a route that supports all HTTP methods.
Sets the method to a pipe-separated string ('GET\|POST\|PUT\|PATCH\|DELETE'),
allowing the same route to handle multiple request types.
--------------------
Регистрирует маршрут, поддерживающий все HTTP-методы.
Устанавливает метод как строку с разделителем \| ('GET\|POST\|PUT\|PATCH\|DELETE'),
что позволяет использовать один маршрут для нескольких типов запросов. | -| public | `resource(string $pattern, string $controller, array $actions): void`
Registers a resource route, mapping standard actions to controller methods.
Supports common CRUD operations by default:
- GET=> read
- POST => create
- PUT=> update
- DELETE => delete
Can be customized with an optional \$actions array.
--------------------
Регистрирует ресурсный маршрут, связывая стандартные действия с методами контроллера.
По умолчанию поддерживает CRUD-операции:
- GET=> read
- POST => create
- PUT=> update
- DELETE => delete
Может быть переопределён с помощью массива \$actions. | -| protected | `setRoute(string $pattern, $target, string $httpMethod, array $middleware): void`
The method constructs a route definition and passes it to the `set()` method for registration.
--------------------
Метод формирует определение маршрута и передает его в метод `set()` для регистрации. | +| public | `get(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the GET HTTP method. | +| public | `post(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the POST HTTP method. | +| public | `put(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the PUT HTTP method. | +| public | `patch(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the PATCH HTTP method. | +| public | `delete(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the DELETE HTTP method. | +| public | `any(string $pattern, callable\|array $target, array $middleware): void`
Registers a route that supports all HTTP methods.
Sets the method to a pipe-separated string ('GET\|POST\|PUT\|PATCH\|DELETE'),
allowing the same route to handle multiple request types. | +| public | `resource(string $pattern, string $controller, array $actions): void`
Registers a resource route, mapping standard actions to controller methods.
Supports common CRUD operations by default:
- GET=> read
- POST => create
- PUT=> update
- DELETE => delete
Can be customized with an optional \$actions array. | +| protected | `setRoute(string $pattern, $target, string $httpMethod, array $middleware): void`
The method constructs a route definition and passes it to the `set()` method for registration. | @@ -40,7 +61,7 @@ ### Class: Rudra\Router\RouterFacade | Visibility | Function | |:-----------|:---------| -| public static | `__callStatic(string $method, array $parameters): ?mixed`
| +| public static | `__callStatic(string $method, array $parameters): mixed`
Handles static method calls for the Facade class
It dynamically resolves the underlying class name by removing "Facade" from the class name
If the resolved class does not exist, it attempts to clean up the class name by removing spaces
If the resolved class is not already registered in the container, it registers it
Finally, it delegates the static method call to the resolved class instance | @@ -48,15 +69,8 @@ ### Class: Rudra\Router\RouterInterface | Visibility | Function | |:-----------|:---------| -| abstract public | `set(array $route): void`
Sets the route, parsing HTTP methods (if multiple are specified via \|).
Registers a route handler for each method.
-------------------------
Устанавливает маршрут, разбирая HTTP-методы (если указано несколько через \|).
Для каждого метода регистрирует обработчик маршрута. | -| abstract public | `directCall(array $route, ?array $params): void`
Calls the controller and its method directly, performing the full lifecycle:
This method is used to fully dispatch a route after matching it with the current request.
-------------------------
Вызывает контроллер и его метод напрямую, выполняя полный жизненный цикл:
Метод используется для полной диспетчеризации маршрута после его совпадения с текущим запросом. | - - - - -### Class: Rudra\Router\Routing -| Visibility | Function | -|:-----------|:---------| +| abstract public | `set(array $route): void`
| +| abstract public | `directCall(array $route, ?array $params): void`
| @@ -64,8 +78,8 @@ ### Class: Rudra\Router\Traits\RouterAnnotationTrait | Visibility | Function | |:-----------|:---------| -| public | `annotationCollector(array $controllers, bool $getter, bool $attributes): ?array`
Collects and processes annotations from the specified controllers.
This method scans each controller class for Routing and Middleware annotations,
builds route definitions based on those annotations, and either:
- Registers them directly via `set()` (if \$getter = false), or
- Returns them as an array (if \$getter = true).
--------------------
Собирает и обрабатывает аннотации указанных контроллеров.
Метод сканирует каждый контроллер на наличие аннотаций Routing и Middleware,
формирует определения маршрутов и либо:
- Регистрирует их напрямую через `set()` (если \$getter = false),
- Возвращает как массив (если \$getter = true). | -| protected | `handleAnnotationMiddleware(array $annotation): array`
Processes middleware annotations into a valid middleware format.
--------------------
Обрабатывает аннотации middleware в поддерживаемый формат.
```#[Middleware(name: "Auth", params: "admin")]```
в:
```['Auth', 'admin']``` | +| public | `annotationCollector(array $controllers, bool $getter, bool $attributes): ?array`
Collects and processes annotations from the specified controllers.
This method scans each controller class for Routing and Middleware annotations,
builds route definitions based on those annotations, and either:
- Registers them directly via `set()` (if \$getter = false), or
- Returns them as an array (if \$getter = true). | +| protected | `handleAnnotationMiddleware(array $annotation): array`
Processes middleware annotations into a valid middleware format.
```#[Middleware(name: "Auth", params: "admin")]```
to:
```['Auth', 'admin']``` | @@ -73,14 +87,16 @@ ### Class: Rudra\Router\Traits\RouterRequestMethodTrait | Visibility | Function | |:-----------|:---------| -| public | `get(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the GET HTTP method.
--------------------
Регистрирует маршрут с использованием метода GET. | -| public | `post(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the POST HTTP method.
--------------------
Регистрирует маршрут с использованием метода POST. | -| public | `put(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the PUT HTTP method.
--------------------
Регистрирует маршрут с использованием метода PUT. | -| public | `patch(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the PATCH HTTP method.
--------------------
Регистрирует маршрут с использованием метода PATCH. | -| public | `delete(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the DELETE HTTP method.
--------------------
Регистрирует маршрут с использованием метода DELETE. | -| public | `any(string $pattern, callable\|array $target, array $middleware): void`
Registers a route that supports all HTTP methods.
Sets the method to a pipe-separated string ('GET\|POST\|PUT\|PATCH\|DELETE'),
allowing the same route to handle multiple request types.
--------------------
Регистрирует маршрут, поддерживающий все HTTP-методы.
Устанавливает метод как строку с разделителем \| ('GET\|POST\|PUT\|PATCH\|DELETE'),
что позволяет использовать один маршрут для нескольких типов запросов. | -| public | `resource(string $pattern, string $controller, array $actions): void`
Registers a resource route, mapping standard actions to controller methods.
Supports common CRUD operations by default:
- GET=> read
- POST => create
- PUT=> update
- DELETE => delete
Can be customized with an optional \$actions array.
--------------------
Регистрирует ресурсный маршрут, связывая стандартные действия с методами контроллера.
По умолчанию поддерживает CRUD-операции:
- GET=> read
- POST => create
- PUT=> update
- DELETE => delete
Может быть переопределён с помощью массива \$actions. | -| protected | `setRoute(string $pattern, $target, string $httpMethod, array $middleware): void`
The method constructs a route definition and passes it to the `set()` method for registration.
--------------------
Метод формирует определение маршрута и передает его в метод `set()` для регистрации. | -
- -###### created with [Rudra-Documentation-Collector](#https://github.com/Jagepard/Rudra-Documentation-Collector) +| public | `get(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the GET HTTP method. | +| public | `post(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the POST HTTP method. | +| public | `put(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the PUT HTTP method. | +| public | `patch(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the PATCH HTTP method. | +| public | `delete(string $pattern, callable\|array $target, array $middleware): void`
Registers a route with the DELETE HTTP method. | +| public | `any(string $pattern, callable\|array $target, array $middleware): void`
Registers a route that supports all HTTP methods.
Sets the method to a pipe-separated string ('GET\|POST\|PUT\|PATCH\|DELETE'),
allowing the same route to handle multiple request types. | +| public | `resource(string $pattern, string $controller, array $actions): void`
Registers a resource route, mapping standard actions to controller methods.
Supports common CRUD operations by default:
- GET=> read
- POST => create
- PUT=> update
- DELETE => delete
Can be customized with an optional \$actions array. | +| protected | `setRoute(string $pattern, $target, string $httpMethod, array $middleware): void`
The method constructs a route definition and passes it to the `set()` method for registration. | + + +--- + +###### created with [Rudra-Documentation-Collector](https://github.com/Jagepard/Rudra-Documentation-Collector) diff --git a/src/Router.php b/src/Router.php index 47b242e5..788f2134 100755 --- a/src/Router.php +++ b/src/Router.php @@ -13,8 +13,10 @@ use ReflectionException; use Rudra\Container\Traits\SetRudraContainersTrait; -use Rudra\Exceptions\{MiddlewareException, RouterException}; -use Rudra\Router\Traits\{RouterAnnotationTrait, RouterRequestMethodTrait}; +use Rudra\Exceptions\MiddlewareException; +use Rudra\Exceptions\RouterException; +use Rudra\Router\Traits\RouterAnnotationTrait; +use Rudra\Router\Traits\RouterRequestMethodTrait; class Router implements RouterInterface { @@ -27,12 +29,6 @@ class Router implements RouterInterface /** * Sets the route, parsing HTTP methods (if multiple are specified via |). * Registers a route handler for each method. - * ------------------------- - * Устанавливает маршрут, разбирая HTTP-методы (если указано несколько через |). - * Для каждого метода регистрирует обработчик маршрута. - * - * @param array $route - * @return void */ public function set(array $route): void { @@ -48,11 +44,6 @@ public function set(array $route): void /** * Processes the incoming URI request and checks if it matches the current route. - * ------------------------- - * Обрабатывает входящий URI-запрос и проверяет его совпадение с текущим маршрутом. - * - * @param array $route - * @return void */ private function handleRequestUri(array $route): void { @@ -78,10 +69,6 @@ private function handleRequestUri(array $route): void /** * Processes the HTTP request method, including spoofing via _method (for PUT/PATCH/DELETE) - * ------------------------- - * Обрабатывает HTTP-метод запроса, включая spoofing через _method (для PUT/PATCH/DELETE) - * - * @return void */ private function handleRequestMethod(): void { @@ -107,14 +94,7 @@ private function handleRequestMethod(): void /** * Matches the URI from the route with the actual request, processing parameters of the form :param and :regexp. - * This method is used to extract dynamic segments from a URI pattern: - * ------------------------- - * Сопоставляет URI из маршрута с фактическим запросом, обрабатывая параметры вида :param и :regexp. - * Метод извлекает динамические сегменты из URL-шаблона: - * - * @param array $route - * @param array $request - * @return array + * This method is used to extract dynamic segments from a URI pattern */ private function handlePattern(array $route, array $request): array { @@ -153,12 +133,6 @@ private function handlePattern(array $route, array $request): array /** * Calls the controller associated with the route — either a Closure or a controller method. - * ------------------------- - * Вызывает контроллер, связанный с маршрутом — либо Closure, либо метод контроллера. - * - * @param array $route - * @param array|null $params - * @return void */ private function setCallable(array $route, ?array $params): void { @@ -182,13 +156,7 @@ private function setCallable(array $route, ?array $params): void /** * Calls the controller and its method directly, performing the full lifecycle: * This method is used to fully dispatch a route after matching it with the current request. - * ------------------------- - * Вызывает контроллер и его метод напрямую, выполняя полный жизненный цикл: - * Метод используется для полной диспетчеризации маршрута после его совпадения с текущим запросом. - * - * @param array $route - * @param array|null $params - * @return void + * * @throws RouterException */ public function directCall(array $route, ?array $params = null): void @@ -197,7 +165,7 @@ public function directCall(array $route, ?array $params = null): void $action = $route['action']; if (!method_exists($controller, $action)) { - throw new RouterException("503"); + throw new RouterException("Service Unavailable", 503); } $controller->shipInit(); @@ -230,22 +198,13 @@ public function directCall(array $route, ?array $params = null): void * * This method is typically used when the zend.exception_ignore_args setting is enabled, * allowing for more flexible and type-safe dependency resolution. - * ------------------------- - * Вызывает метод контроллера с помощью Reflection, выполняя автоматическое внедрение параметров на основе типизации. - * - * Этот метод обычно используется, когда включена настройка zend.exception_ignore_args, - * что позволяет более гибко и безопасно разрешать зависимости по типам. * - * @param array|null $params - * @param string action - * @param object $controller - * @return void * @throws RouterException */ private function callActionThroughReflection(?array $params, string $action, object $controller): void { if ($params && in_array('', $params, true)) { - throw new RouterException("404"); + throw new RouterException("Not Found", 404); } $cacheKey = get_class($controller) . "::$action"; @@ -272,28 +231,15 @@ private function callActionThroughReflection(?array $params, string $action, obj * - \TypeError — thrown when an argument is not compatible with the expected type. * * In both cases, Rudra's autowire system attempts to resolve and inject the correct dependencies. - * ------------------------- - * Вызывает указанный метод контроллера напрямую. - * - * Если тип или количество аргументов не совпадает — пытается автоматически внедрить нужные зависимости. - * Это механизм отката, используемый, когда недоступен вызов через Reflection. - * - * Обрабатываются следующие ошибки: - * - \ArgumentCountError — выбрасывается, если количество аргументов не совпадает с ожидаемым. - * - \TypeError — выбрасывается, если тип аргумента не соответствует ожидаемому. - * - * В обоих случаях система автовайринга Rudra пытается разрешить и внедрить правильные зависимости. - * - * @param array|null $params - * @param string $action - * @param object $controller - * @return void + * * @throws RouterException + * @throws \TypeError + * @throws \ArgumentCountError */ private function callActionThroughException(?array $params, string $action, object $controller): void { if (isset($params) && in_array('', $params)) { - throw new RouterException("404"); + throw new RouterException("Not Found", 404); } try { @@ -320,18 +266,7 @@ private function callActionThroughException(?array $params, string $action, obje * - ['MiddlewareClass', $parameter] (array with class and parameter) — passes the parameter to the middleware. * * Each middleware must implement the __invoke() method to be callable. - * -------------------- - * Выполняет цепочку middleware, рекурсивно вызывая каждый элемент. - * - * Middleware может быть указан в одном из поддерживаемых форматов: - * - 'MiddlewareClass' (строка) — простое имя класса без параметров. - * - ['MiddlewareClass'] (массив с именем класса) — аналогично предыдущему, удобно для расширения. - * - ['MiddlewareClass', $parameter] (массив с классом и параметром) — передаёт параметр в middleware. - * - * Каждый middleware должен реализовывать метод __invoke(), чтобы быть вызываемым. - * - * @param array $chain - * @return void + * * @throws \Rudra\Router\Exceptions\MiddlewareException */ public function handleMiddleware(array $chain): void diff --git a/src/RouterInterface.php b/src/RouterInterface.php index 0dc1b700..e190f092 100755 --- a/src/RouterInterface.php +++ b/src/RouterInterface.php @@ -15,29 +15,6 @@ interface RouterInterface { - /** - * Sets the route, parsing HTTP methods (if multiple are specified via |). - * Registers a route handler for each method. - * ------------------------- - * Устанавливает маршрут, разбирая HTTP-методы (если указано несколько через |). - * Для каждого метода регистрирует обработчик маршрута. - * - * @param array $route - * @return void - */ public function set(array $route): void; - - /** - * Calls the controller and its method directly, performing the full lifecycle: - * This method is used to fully dispatch a route after matching it with the current request. - * ------------------------- - * Вызывает контроллер и его метод напрямую, выполняя полный жизненный цикл: - * Метод используется для полной диспетчеризации маршрута после его совпадения с текущим запросом. - * - * @param array $route - * @param array|null $params - * @return void - * @throws RouterException - */ public function directCall(array $route, ?array $params = null): void; } diff --git a/src/Traits/RouterAnnotationTrait.php b/src/Traits/RouterAnnotationTrait.php index d4ea8de9..25a4ddfa 100755 --- a/src/Traits/RouterAnnotationTrait.php +++ b/src/Traits/RouterAnnotationTrait.php @@ -23,18 +23,8 @@ trait RouterAnnotationTrait * builds route definitions based on those annotations, and either: * - Registers them directly via `set()` (if $getter = false), or * - Returns them as an array (if $getter = true). - * -------------------- - * Собирает и обрабатывает аннотации указанных контроллеров. - * - * Метод сканирует каждый контроллер на наличие аннотаций Routing и Middleware, - * формирует определения маршрутов и либо: - * - Регистрирует их напрямую через `set()` (если $getter = false), - * - Возвращает как массив (если $getter = true). - * - * @param array $controllers - * @param bool $getter - * @param bool $attributes - * @return array|null + * + * @throws \Exception If a specified controller class does not exist. */ public function annotationCollector(array $controllers, bool $getter = false, bool $attributes = false): ?array { @@ -43,7 +33,7 @@ public function annotationCollector(array $controllers, bool $getter = false, bo foreach ($controllers as $controller) { if (!class_exists($controller)) { - throw new \Exception("Удалите контроллер $controller из файла routes.php"); + throw new \Exception("Remove the $controller controller from the routes.php file."); } $reflection = new \ReflectionClass($controller); @@ -87,15 +77,10 @@ public function annotationCollector(array $controllers, bool $getter = false, bo /** * Processes middleware annotations into a valid middleware format. - * -------------------- - * Обрабатывает аннотации middleware в поддерживаемый формат. * * ```#[Middleware(name: "Auth", params: "admin")]``` - * в: + * to: * ```['Auth', 'admin']``` - * - * @param array $annotation - * @return array */ protected function handleAnnotationMiddleware(array $annotation): array { diff --git a/src/Traits/RouterRequestMethodTrait.php b/src/Traits/RouterRequestMethodTrait.php index 1cd8a5e4..8bcbde4c 100755 --- a/src/Traits/RouterRequestMethodTrait.php +++ b/src/Traits/RouterRequestMethodTrait.php @@ -15,12 +15,6 @@ trait RouterRequestMethodTrait { /** * Registers a route with the GET HTTP method. - * -------------------- - * Регистрирует маршрут с использованием метода GET. - * - * @param string $pattern - * @param array|callable $target - * @param array $middleware */ public function get(string $pattern, array|callable $target, array $middleware = []): void { @@ -29,10 +23,6 @@ public function get(string $pattern, array|callable $target, array $middleware = /** * Registers a route with the POST HTTP method. - * -------------------- - * Регистрирует маршрут с использованием метода POST. - * - * @param array $route */ public function post(string $pattern, array|callable $target, array $middleware = []): void { @@ -41,10 +31,6 @@ public function post(string $pattern, array|callable $target, array $middleware /** * Registers a route with the PUT HTTP method. - * -------------------- - * Регистрирует маршрут с использованием метода PUT. - * - * @param array $route */ public function put(string $pattern, array|callable $target, array $middleware = []): void { @@ -53,10 +39,6 @@ public function put(string $pattern, array|callable $target, array $middleware = /** * Registers a route with the PATCH HTTP method. - * -------------------- - * Регистрирует маршрут с использованием метода PATCH. - * - * @param array $route */ public function patch(string $pattern, array|callable $target, array $middleware = []): void { @@ -65,10 +47,6 @@ public function patch(string $pattern, array|callable $target, array $middleware /** * Registers a route with the DELETE HTTP method. - * -------------------- - * Регистрирует маршрут с использованием метода DELETE. - * - * @param array $route */ public function delete(string $pattern, array|callable $target, array $middleware = []): void { @@ -80,13 +58,6 @@ public function delete(string $pattern, array|callable $target, array $middlewar * * Sets the method to a pipe-separated string ('GET|POST|PUT|PATCH|DELETE'), * allowing the same route to handle multiple request types. - * -------------------- - * Регистрирует маршрут, поддерживающий все HTTP-методы. - * - * Устанавливает метод как строку с разделителем | ('GET|POST|PUT|PATCH|DELETE'), - * что позволяет использовать один маршрут для нескольких типов запросов. - * - * @param array $route */ public function any(string $pattern, array|callable $target, array $middleware = []): void { @@ -103,21 +74,6 @@ public function any(string $pattern, array|callable $target, array $middleware = * - DELETE => delete * * Can be customized with an optional $actions array. - * -------------------- - * Регистрирует ресурсный маршрут, связывая стандартные действия с методами контроллера. - * - * По умолчанию поддерживает CRUD-операции: - * - GET => read - * - POST => create - * - PUT => update - * - DELETE => delete - * - * Может быть переопределён с помощью массива $actions. - * - * @param string $pattern - * @param string $controller - * @param array $actions - * @return void */ public function resource(string $pattern, string $controller, array $actions = ['read', 'create', 'update', 'delete']): void { @@ -149,7 +105,7 @@ public function resource(string $pattern, string $controller, array $actions = [ $route['action'] = $actions[3]; // delete break; default: - return; // Неизвестный метод — игнорируем + return; // Unknown method — ignore } $route['url'] = $pattern; @@ -160,13 +116,6 @@ public function resource(string $pattern, string $controller, array $actions = [ /** * The method constructs a route definition and passes it to the `set()` method for registration. - * -------------------- - * Метод формирует определение маршрута и передает его в метод `set()` для регистрации. - * - * @param string $pattern - * @param mixed $target - * @param string $httpMethod - * @param array $middleware */ protected function setRoute(string $pattern, $target, string $httpMethod, array $middleware = []): void { diff --git a/tests/RouterAnnotationTraitTest.php b/tests/RouterAnnotationTraitTest.php index 3a4feece..16e3574a 100644 --- a/tests/RouterAnnotationTraitTest.php +++ b/tests/RouterAnnotationTraitTest.php @@ -8,18 +8,18 @@ * @author Korotkov Danila (Jagepard) * @license https://mozilla.org/MPL/2.0/ MPL-2.0 * - * phpunit src/tests/ContainerTest --coverage-html src/tests/coverage-html + * phpunit src/tests/RouterAnnotationTraitTest --coverage-html src/tests/coverage-html */ namespace Rudra\Router\Tests; -use Rudra\Container\{Facades\Rudra,Interfaces\RudraInterface}; use Rudra\Annotation\Annotation; +use Rudra\Container\Facades\Rudra; +use Rudra\Container\Interfaces\RudraInterface; use Rudra\Router\Router as Rtr; use Rudra\Router\RouterFacade as Router; -use PHPUnit\Framework\TestCase as PHPUnit_Framework_TestCase; -class RouterAnnotationTraitTest extends PHPUnit_Framework_TestCase +class RouterAnnotationTraitTest extends \PHPUnit\Framework\TestCase { protected function setContainer() { diff --git a/tests/RouterTest.php b/tests/RouterTest.php index 648898c3..c4c005e9 100755 --- a/tests/RouterTest.php +++ b/tests/RouterTest.php @@ -8,18 +8,19 @@ * @author Korotkov Danila (Jagepard) * @license https://mozilla.org/MPL/2.0/ MPL-2.0 * - * phpunit src/tests/ContainerTest --coverage-html src/tests/coverage-html + * phpunit src/tests/RouterTest --coverage-html src/tests/coverage-html */ namespace Rudra\Router\Tests; +use Rudra\Container\Facades\Rudra; +use Rudra\Container\Interfaces\RudraInterface; +use Rudra\Container\Rudra as R; use Rudra\Router\RouterFacade as Router; -use Rudra\Router\Tests\Stub\Middleware\Middleware; use Rudra\Router\Tests\Stub\Controllers\MainController; -use PHPUnit\Framework\TestCase as PHPUnit_Framework_TestCase; -use Rudra\Container\{Rudra as R, Facades\Rudra, Interfaces\RudraInterface}; +use Rudra\Router\Tests\Stub\Middleware\Middleware; -class RouterTest extends PHPUnit_Framework_TestCase +class RouterTest extends \PHPUnit\Framework\TestCase { protected function setContainer() {