-
-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Simplify route classes & add route builders
- Loading branch information
Showing
22 changed files
with
1,607 additions
and
1,209 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Yiisoft\Router\Builder; | ||
|
||
use RuntimeException; | ||
use Yiisoft\Router\Group; | ||
use Yiisoft\Router\RoutableInterface; | ||
use Yiisoft\Router\Route; | ||
|
||
final class GroupBuilder implements RoutableInterface | ||
{ | ||
/** | ||
* @var Group[]|Route[]|RoutableInterface[] | ||
*/ | ||
private array $routes = []; | ||
|
||
/** | ||
* @var array[]|callable[]|string[] | ||
* @psalm-var list<array|callable|string> | ||
*/ | ||
private array $middlewares = []; | ||
|
||
private array $disabledMiddlewares = []; | ||
|
||
/** | ||
* @var string[] | ||
*/ | ||
private array $hosts = []; | ||
private bool $routesAdded = false; | ||
private bool $middlewareAdded = false; | ||
|
||
/** | ||
* @var array|callable|string|null Middleware definition for CORS requests. | ||
*/ | ||
private $corsMiddleware = null; | ||
|
||
private function __construct( | ||
private ?string $prefix = null, | ||
private ?string $namePrefix = null, | ||
) { | ||
} | ||
|
||
/** | ||
* Create a new group instance. | ||
* | ||
* @param string|null $prefix URL prefix to prepend to all routes of the group. | ||
*/ | ||
public static function create(?string $prefix = null, ?string $namePrefix = null): self | ||
{ | ||
return new self($prefix, $namePrefix); | ||
} | ||
|
||
public function routes(Group|Route|RoutableInterface ...$routes): self | ||
{ | ||
if ($this->middlewareAdded) { | ||
throw new RuntimeException('routes() can not be used after prependMiddleware().'); | ||
} | ||
|
||
$new = clone $this; | ||
$new->routes = $routes; | ||
$new->routesAdded = true; | ||
|
||
return $new; | ||
} | ||
|
||
/** | ||
* Adds a middleware definition that handles CORS requests. | ||
* If set, routes for {@see Method::OPTIONS} request will be added automatically. | ||
* | ||
* @param array|callable|string|null $middlewareDefinition Middleware definition for CORS requests. | ||
*/ | ||
public function withCors(array|callable|string|null $middlewareDefinition): self | ||
{ | ||
$group = clone $this; | ||
$group->corsMiddleware = $middlewareDefinition; | ||
|
||
return $group; | ||
} | ||
|
||
/** | ||
* Appends a handler middleware definition that should be invoked for a matched route. | ||
* First added handler will be executed first. | ||
*/ | ||
public function middleware(array|callable|string ...$definition): self | ||
{ | ||
if ($this->routesAdded) { | ||
throw new RuntimeException('middleware() can not be used after routes().'); | ||
} | ||
|
||
$new = clone $this; | ||
array_push( | ||
$new->middlewares, | ||
...array_values($definition) | ||
); | ||
|
||
return $new; | ||
} | ||
|
||
/** | ||
* Prepends a handler middleware definition that should be invoked for a matched route. | ||
* First added handler will be executed last. | ||
*/ | ||
public function prependMiddleware(array|callable|string ...$definition): self | ||
{ | ||
$new = clone $this; | ||
array_unshift( | ||
$new->middlewares, | ||
...array_values($definition) | ||
); | ||
|
||
$new->middlewareAdded = true; | ||
|
||
return $new; | ||
} | ||
|
||
public function namePrefix(string $namePrefix): self | ||
{ | ||
$new = clone $this; | ||
$new->namePrefix = $namePrefix; | ||
return $new; | ||
} | ||
|
||
public function host(string $host): self | ||
{ | ||
return $this->hosts($host); | ||
} | ||
|
||
public function hosts(string ...$hosts): self | ||
{ | ||
$new = clone $this; | ||
$new->hosts = array_values($hosts); | ||
Check warning on line 133 in src/Builder/GroupBuilder.php GitHub Actions / mutation / PHP 8.1-ubuntu-latest
|
||
|
||
return $new; | ||
} | ||
|
||
/** | ||
* Excludes middleware from being invoked when action is handled. | ||
* It is useful to avoid invoking one of the parent group middleware for | ||
* a certain route. | ||
*/ | ||
public function disableMiddleware(mixed ...$definition): self | ||
{ | ||
$new = clone $this; | ||
array_push( | ||
$new->disabledMiddlewares, | ||
...array_values($definition), | ||
); | ||
|
||
return $new; | ||
} | ||
|
||
public function toRoute(): Group|Route | ||
{ | ||
return new Group( | ||
prefix: $this->prefix, | ||
namePrefix: $this->namePrefix, | ||
routes: $this->routes, | ||
middlewares: $this->middlewares, | ||
hosts: $this->hosts, | ||
disabledMiddlewares: $this->disabledMiddlewares, | ||
corsMiddleware: $this->corsMiddleware | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,218 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Yiisoft\Router\Builder; | ||
|
||
use Stringable; | ||
use Yiisoft\Http\Method; | ||
use Yiisoft\Router\Group; | ||
use Yiisoft\Router\RoutableInterface; | ||
use Yiisoft\Router\Route; | ||
|
||
use function in_array; | ||
|
||
/** | ||
* Route defines a mapping from URL to callback / name and vice versa. | ||
*/ | ||
final class RouteBuilder implements RoutableInterface | ||
{ | ||
private ?string $name = null; | ||
|
||
/** | ||
* @var array|string|callable|null | ||
*/ | ||
private $action = null; | ||
|
||
/** | ||
* @var string[] | ||
*/ | ||
private array $hosts = []; | ||
|
||
private bool $override = false; | ||
|
||
private array $disabledMiddlewares = []; | ||
|
||
/** | ||
* @var array[]|callable[]|string[] | ||
* @psalm-var list<array|callable|string> | ||
*/ | ||
private array $middlewares = []; | ||
|
||
/** | ||
* @var array<array-key,scalar|Stringable|null> | ||
*/ | ||
private array $defaults = []; | ||
|
||
/** | ||
* @param string[] $methods | ||
*/ | ||
private function __construct( | ||
private array $methods, | ||
private string $pattern, | ||
) { | ||
} | ||
|
||
public static function get(string $pattern): self | ||
{ | ||
return self::methods([Method::GET], $pattern); | ||
} | ||
|
||
public static function post(string $pattern): self | ||
{ | ||
return self::methods([Method::POST], $pattern); | ||
} | ||
|
||
public static function put(string $pattern): self | ||
{ | ||
return self::methods([Method::PUT], $pattern); | ||
} | ||
|
||
public static function delete(string $pattern): self | ||
{ | ||
return self::methods([Method::DELETE], $pattern); | ||
} | ||
|
||
public static function patch(string $pattern): self | ||
{ | ||
return self::methods([Method::PATCH], $pattern); | ||
} | ||
|
||
public static function head(string $pattern): self | ||
{ | ||
return self::methods([Method::HEAD], $pattern); | ||
} | ||
|
||
public static function options(string $pattern): self | ||
{ | ||
return self::methods([Method::OPTIONS], $pattern); | ||
} | ||
|
||
/** | ||
* @param string[] $methods | ||
*/ | ||
public static function methods(array $methods, string $pattern): self | ||
{ | ||
return new self(methods: $methods, pattern: $pattern); | ||
} | ||
|
||
public function name(string $name): self | ||
{ | ||
$route = clone $this; | ||
$route->name = $name; | ||
return $route; | ||
} | ||
|
||
public function pattern(string $pattern): self | ||
{ | ||
$new = clone $this; | ||
$new->pattern = $pattern; | ||
return $new; | ||
} | ||
|
||
public function host(string $host): self | ||
{ | ||
return $this->hosts($host); | ||
} | ||
|
||
public function hosts(string ...$hosts): self | ||
{ | ||
$route = clone $this; | ||
$route->hosts = array_values($hosts); | ||
Check warning on line 121 in src/Builder/RouteBuilder.php GitHub Actions / mutation / PHP 8.1-ubuntu-latest
|
||
|
||
return $route; | ||
} | ||
|
||
/** | ||
* Marks route as override. When added it will replace existing route with the same name. | ||
*/ | ||
public function override(): self | ||
{ | ||
$route = clone $this; | ||
$route->override = true; | ||
return $route; | ||
} | ||
|
||
/** | ||
* Parameter default values indexed by parameter names. | ||
* | ||
* @psalm-param array<array-key,null|Stringable|scalar> $defaults | ||
*/ | ||
public function defaults(array $defaults): self | ||
{ | ||
$route = clone $this; | ||
$route->defaults = $defaults; | ||
return $route; | ||
} | ||
|
||
/** | ||
* Appends a handler middleware definition that should be invoked for a matched route. | ||
* First added handler will be executed first. | ||
*/ | ||
public function middleware(array|callable|string ...$definition): self | ||
{ | ||
$route = clone $this; | ||
array_push( | ||
$route->middlewares, | ||
...array_values($definition) | ||
); | ||
|
||
return $route; | ||
} | ||
|
||
/** | ||
* Prepends a handler middleware definition that should be invoked for a matched route. | ||
* Last added handler will be executed first. | ||
*/ | ||
public function prependMiddleware(array|callable|string ...$definition): self | ||
{ | ||
$route = clone $this; | ||
array_unshift( | ||
$route->middlewares, | ||
...array_values($definition) | ||
); | ||
|
||
return $route; | ||
} | ||
|
||
/** | ||
* Appends action handler. It is a primary middleware definition that should be invoked last for a matched route. | ||
*/ | ||
public function action(array|callable|string $middlewareDefinition): self | ||
{ | ||
$route = clone $this; | ||
$route->action = $middlewareDefinition; | ||
return $route; | ||
} | ||
|
||
/** | ||
* Excludes middleware from being invoked when action is handled. | ||
* It is useful to avoid invoking one of the parent group middleware for | ||
* a certain route. | ||
*/ | ||
public function disableMiddleware(mixed ...$definition): self | ||
{ | ||
$route = clone $this; | ||
array_push( | ||
$route->disabledMiddlewares, | ||
...array_values($definition) | ||
); | ||
|
||
return $route; | ||
} | ||
|
||
public function toRoute(): Group|Route | ||
{ | ||
return new Route( | ||
methods: $this->methods, | ||
pattern: $this->pattern, | ||
name: $this->name, | ||
action: $this->action, | ||
middlewares: $this->middlewares, | ||
defaults: $this->defaults, | ||
hosts: $this->hosts, | ||
override: $this->override, | ||
disabledMiddlewares: $this->disabledMiddlewares | ||
); | ||
} | ||
} |
Oops, something went wrong.