Skip to content

Commit 4e29a50

Browse files
committed
Route grouping implementation
Signed-off-by: alexmerlin <[email protected]>
1 parent 4a106d2 commit 4e29a50

File tree

10 files changed

+503
-0
lines changed

10 files changed

+503
-0
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Api\App\Route;
6+
7+
use Fig\Http\Message\RequestMethodInterface;
8+
use Mezzio\Application;
9+
10+
use function in_array;
11+
use function is_string;
12+
13+
abstract class AbstractRoute implements RouteInterface
14+
{
15+
/** @var class-string[] $excludedMiddlewares */
16+
protected array $excludedMiddlewares = [];
17+
/** @var class-string[] $middlewares */
18+
protected array $middlewares = [];
19+
/** @var non-empty-string $name */
20+
protected string $name;
21+
/** @var non-empty-string $path */
22+
protected string $path;
23+
/** @var non-empty-string $method */
24+
protected string $method;
25+
26+
public function __construct(
27+
?string $path = null,
28+
null|array|string $middlewares = null,
29+
?string $name = null,
30+
?string $method = null
31+
) {
32+
$path && $this->setPath($path);
33+
$middlewares && $this->setMiddlewares($middlewares);
34+
$name && $this->setName($name);
35+
$method && $this->setMethod($method);
36+
}
37+
38+
/**
39+
* @param class-string $middleware
40+
*/
41+
public function addMiddleware(string $middleware): self
42+
{
43+
if (! in_array($middleware, $this->middlewares, true)) {
44+
$this->middlewares[] = $middleware;
45+
}
46+
47+
return $this;
48+
}
49+
50+
public function getMiddlewares(): array
51+
{
52+
return $this->middlewares;
53+
}
54+
55+
/**
56+
* @param class-string[]|class-string $middlewares
57+
*/
58+
public function setMiddlewares(array|string $middlewares): self
59+
{
60+
if (is_string($middlewares)) {
61+
$middlewares = [$middlewares];
62+
}
63+
64+
foreach ($middlewares as $middleware) {
65+
$this->addMiddleware($middleware);
66+
}
67+
68+
return $this;
69+
}
70+
71+
public function getName(): string
72+
{
73+
return $this->name;
74+
}
75+
76+
/**
77+
* @param non-empty-string $name
78+
*/
79+
public function setName(string $name): self
80+
{
81+
$this->name = $name;
82+
83+
return $this;
84+
}
85+
86+
public function getPath(): string
87+
{
88+
return $this->path;
89+
}
90+
91+
/**
92+
* @param non-empty-string $path
93+
*/
94+
public function setPath(string $path): self
95+
{
96+
$this->path = $path;
97+
98+
return $this;
99+
}
100+
101+
public function getMethod(): string
102+
{
103+
return $this->method;
104+
}
105+
106+
/**
107+
* @param non-empty-string $method
108+
*/
109+
public function setMethod(string $method): self
110+
{
111+
$this->method = $method;
112+
113+
return $this;
114+
}
115+
116+
public function register(Application $app): void
117+
{
118+
match ($this->method) {
119+
RequestMethodInterface::METHOD_DELETE => $app->delete($this->path, $this->middlewares, $this->name),
120+
RequestMethodInterface::METHOD_GET => $app->get($this->path, $this->middlewares, $this->name),
121+
RequestMethodInterface::METHOD_PATCH => $app->patch($this->path, $this->middlewares, $this->name),
122+
RequestMethodInterface::METHOD_POST => $app->post($this->path, $this->middlewares, $this->name),
123+
RequestMethodInterface::METHOD_PUT => $app->put($this->path, $this->middlewares, $this->name),
124+
default => null,
125+
};
126+
}
127+
128+
/**
129+
* @param class-string[]|class-string $middlewares
130+
*/
131+
public function excludeMiddlewares(array|string $middlewares): self
132+
{
133+
if (is_string($middlewares)) {
134+
$middlewares = [$middlewares];
135+
}
136+
137+
foreach ($middlewares as $middleware) {
138+
if (in_array($middleware, $this->excludedMiddlewares, true)) {
139+
continue;
140+
}
141+
$this->excludedMiddlewares[] = $middleware;
142+
}
143+
144+
return $this;
145+
}
146+
147+
public function getExcludedMiddlewares(): array
148+
{
149+
return $this->excludedMiddlewares;
150+
}
151+
}

src/App/src/Route/Delete.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Api\App\Route;
6+
7+
use Fig\Http\Message\RequestMethodInterface;
8+
9+
class Delete extends AbstractRoute
10+
{
11+
public function __construct(?string $path = null, null|array|string $handlers = null, ?string $name = null)
12+
{
13+
parent::__construct($path, $handlers, $name, RequestMethodInterface::METHOD_DELETE);
14+
}
15+
}

src/App/src/Route/Get.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Api\App\Route;
6+
7+
use Fig\Http\Message\RequestMethodInterface;
8+
9+
class Get extends AbstractRoute
10+
{
11+
public function __construct(?string $path = null, null|array|string $handlers = null, ?string $name = null)
12+
{
13+
parent::__construct($path, $handlers, $name, RequestMethodInterface::METHOD_GET);
14+
}
15+
}

src/App/src/Route/Patch.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Api\App\Route;
6+
7+
use Fig\Http\Message\RequestMethodInterface;
8+
9+
class Patch extends AbstractRoute
10+
{
11+
public function __construct(?string $path = null, null|array|string $handlers = null, ?string $name = null)
12+
{
13+
parent::__construct($path, $handlers, $name, RequestMethodInterface::METHOD_PATCH);
14+
}
15+
}

src/App/src/Route/Post.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Api\App\Route;
6+
7+
use Fig\Http\Message\RequestMethodInterface;
8+
9+
class Post extends AbstractRoute
10+
{
11+
public function __construct(?string $path = null, null|array|string $handlers = null, ?string $name = null)
12+
{
13+
parent::__construct($path, $handlers, $name, RequestMethodInterface::METHOD_POST);
14+
}
15+
}

src/App/src/Route/Put.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Api\App\Route;
6+
7+
use Fig\Http\Message\RequestMethodInterface;
8+
9+
class Put extends AbstractRoute
10+
{
11+
public function __construct(?string $path = null, null|array|string $handlers = null, ?string $name = null)
12+
{
13+
parent::__construct($path, $handlers, $name, RequestMethodInterface::METHOD_PUT);
14+
}
15+
}

src/App/src/Route/Route.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Api\App\Route;
6+
7+
class Route extends AbstractRoute
8+
{
9+
public function __construct(
10+
?string $path = null,
11+
array|string|null $middlewares = null,
12+
?string $name = null,
13+
?string $method = null
14+
) {
15+
parent::__construct($path, $middlewares, $name, $method);
16+
}
17+
18+
public function delete(string $path, string $handler, string $name): RouteInterface
19+
{
20+
return new Delete($path, $handler, $name);
21+
}
22+
23+
public function get(string $path, string $handler, string $name): RouteInterface
24+
{
25+
return new Get($path, $handler, $name);
26+
}
27+
28+
public function patch(string $path, string $handler, string $name): RouteInterface
29+
{
30+
return new Patch($path, $handler, $name);
31+
}
32+
33+
public function post(string $path, string $handler, string $name): RouteInterface
34+
{
35+
return new Post($path, $handler, $name);
36+
}
37+
38+
public function put(string $path, string $handler, string $name): RouteInterface
39+
{
40+
return new Put($path, $handler, $name);
41+
}
42+
43+
public function redirect(string $path, string $handler, string $name): self
44+
{
45+
return $this;
46+
}
47+
}

src/App/src/Route/RouteGroup.php

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Api\App\Route;
6+
7+
use Mezzio\Application;
8+
9+
use function array_search;
10+
use function in_array;
11+
use function is_string;
12+
use function sprintf;
13+
14+
class RouteGroup
15+
{
16+
/** @var RouteInterface[] $routes */
17+
private array $routes;
18+
private string $prefix;
19+
private array $middlewares = [];
20+
21+
public function __construct(
22+
?string $prefix = null,
23+
?array $middlewares = null,
24+
) {
25+
$prefix && $this->setPrefix($prefix);
26+
$middlewares && $this->setMiddlewares($middlewares);
27+
}
28+
29+
public function addRoute(RouteInterface $route): self
30+
{
31+
$this->routes[] = $route;
32+
33+
return $this;
34+
}
35+
36+
public function setPrefix(string $prefix): self
37+
{
38+
$this->prefix = $prefix;
39+
40+
return $this;
41+
}
42+
43+
/**
44+
* @param class-string $middleware
45+
*/
46+
public function addMiddleware(string $middleware): self
47+
{
48+
if (! in_array($middleware, $this->middlewares, true)) {
49+
$this->middlewares[] = $middleware;
50+
}
51+
52+
return $this;
53+
}
54+
55+
public function getMiddlewares(): array
56+
{
57+
return $this->middlewares;
58+
}
59+
60+
/**
61+
* @param class-string[] $middlewares
62+
*/
63+
public function setMiddlewares(array|string $middlewares): self
64+
{
65+
if (is_string($middlewares)) {
66+
$middlewares = [$middlewares];
67+
}
68+
69+
foreach ($middlewares as $middleware) {
70+
$this->addMiddleware($middleware);
71+
}
72+
73+
return $this;
74+
}
75+
76+
public function register(Application $app): void
77+
{
78+
foreach ($this->routes as $route) {
79+
$route
80+
->setPath(sprintf('%s%s', $this->prefix, $route->getPath()))
81+
->setMiddlewares(
82+
$this->combineMiddlewares(
83+
$this->middlewares,
84+
$route->getMiddlewares(),
85+
$route->getExcludedMiddlewares()
86+
)
87+
)
88+
->register($app);
89+
}
90+
}
91+
92+
private function combineMiddlewares(
93+
array $routeGroupMiddlewares = [],
94+
array $routeMiddlewares = [],
95+
array $excludedMiddlewares = []
96+
): array {
97+
$middlewares = $routeGroupMiddlewares;
98+
99+
foreach ($routeMiddlewares as $routeMiddleware) {
100+
if (in_array($routeMiddleware, $middlewares, true)) {
101+
continue;
102+
}
103+
$middlewares[$routeMiddleware] = $routeMiddleware;
104+
}
105+
106+
foreach ($excludedMiddlewares as $excludedMiddleware) {
107+
if (in_array($excludedMiddleware, $middlewares)) {
108+
unset($middlewares[array_search($excludedMiddleware, $middlewares, true)]);
109+
}
110+
}
111+
112+
return $middlewares;
113+
}
114+
}

0 commit comments

Comments
 (0)