Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove usage middleware dispatcher in Route, Group and MatchingResult #210

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .phpstorm.meta.php/Group.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
'corsMiddleware',
'items',
'middlewareDefinitions',
'hasDispatcher',
'hasCorsMiddleware'
);
}
}
5 changes: 2 additions & 3 deletions .phpstorm.meta.php/Route.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
'methods',
'override',
'defaults',
'dispatcherWithMiddlewares',
'hasDispatcher',
'middlewareDefinitions',
'hasMiddlewares'
);
}
}
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 4.0.0 under development

- Chg #210: Remove usage middleware dispatcher in `Route`, `Group` and `MatchingResult` (@vjik)
vjik marked this conversation as resolved.
Show resolved Hide resolved
- Chg #207: Replace two `RouteCollectorInterface` methods `addRoute()` and `addGroup()` to single `addRoute()` (@vjik)
- Enh #202: Add support for `psr/http-message` version `^2.0` (@vjik)

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ The code is statically analyzed with [Psalm](https://psalm.dev/). To run static

## License

The Yii Dependency Injection is free software. It is released under the terms of the BSD License.
The Yii Router is free software. It is released under the terms of the BSD License.
Please see [`LICENSE`](./LICENSE.md) for more information.

Maintained by [Yii Software](https://www.yiiframework.com/).
Expand Down
5 changes: 4 additions & 1 deletion psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="src" />
<directory name="src"/>
<ignoreFiles>
<directory name="vendor"/>
</ignoreFiles>
</projectFiles>
<issueHandlers>
<MixedAssignment errorLevel="suppress"/>
</issueHandlers>
</psalm>
32 changes: 5 additions & 27 deletions src/Group.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use InvalidArgumentException;
use RuntimeException;
use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher;

use function in_array;

Expand Down Expand Up @@ -36,21 +35,18 @@ final class Group
*/
private $corsMiddleware = null;

private function __construct(private ?string $prefix = null, private ?MiddlewareDispatcher $dispatcher = null)
private function __construct(private ?string $prefix = null)
{
}

/**
* Create a new group instance.
*
* @param string|null $prefix URL prefix to prepend to all routes of the group.
* @param MiddlewareDispatcher|null $dispatcher Middleware dispatcher to use for the group.
*/
public static function create(
?string $prefix = null,
MiddlewareDispatcher $dispatcher = null
): self {
return new self($prefix, $dispatcher);
public static function create(?string $prefix = null): self
{
return new self($prefix);
}

public function routes(self|Route ...$routes): self
Expand All @@ -60,9 +56,6 @@ public function routes(self|Route ...$routes): self
}
$new = clone $this;
foreach ($routes as $route) {
if ($new->dispatcher !== null && !$route->getData('hasDispatcher')) {
$route = $route->withDispatcher($new->dispatcher);
}
$new->items[] = $route;
}

Expand All @@ -71,20 +64,6 @@ public function routes(self|Route ...$routes): self
return $new;
}

public function withDispatcher(MiddlewareDispatcher $dispatcher): self
{
$group = clone $this;
$group->dispatcher = $dispatcher;
foreach ($group->items as $index => $item) {
if (!$item->getData('hasDispatcher')) {
$item = $item->withDispatcher($dispatcher);
$group->items[$index] = $item;
}
}

return $group;
}

/**
* Adds a middleware definition that handles CORS requests.
* If set, routes for {@see Method::OPTIONS} request will be added automatically.
Expand Down Expand Up @@ -180,7 +159,7 @@ public function disableMiddleware(mixed ...$middlewareDefinition): self
* T is ('prefix'|'namePrefix'|'host') ? string|null :
* (T is 'items' ? Group[]|Route[] :
* (T is 'hosts' ? array<array-key, string> :
* (T is ('hasCorsMiddleware'|'hasDispatcher') ? bool :
* (T is ('hasCorsMiddleware') ? bool :
* (T is 'middlewareDefinitions' ? list<array|callable|string> :
* (T is 'corsMiddleware' ? array|callable|string|null : mixed)
* )
Expand All @@ -199,7 +178,6 @@ public function getData(string $key): mixed
'corsMiddleware' => $this->corsMiddleware,
'items' => $this->items,
'hasCorsMiddleware' => $this->corsMiddleware !== null,
'hasDispatcher' => $this->dispatcher !== null,
'middlewareDefinitions' => $this->getMiddlewareDefinitions(),
default => throw new InvalidArgumentException('Unknown data key: ' . $key),
};
Expand Down
33 changes: 1 addition & 32 deletions src/MatchingResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@

namespace Yiisoft\Router;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use RuntimeException;
use Yiisoft\Http\Method;
use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher;

final class MatchingResult implements MiddlewareInterface
final class MatchingResult
{
/**
* @var array<string,string>
Expand All @@ -24,19 +19,10 @@ final class MatchingResult implements MiddlewareInterface
*/
private array $methods = [];

private ?MiddlewareDispatcher $dispatcher = null;

private function __construct(private ?Route $route)
{
}

public function withDispatcher(MiddlewareDispatcher $dispatcher): self
{
$new = clone $this;
$new->dispatcher = $dispatcher;
return $new;
}

/**
* @param array<string,string> $arguments
*/
Expand Down Expand Up @@ -94,21 +80,4 @@ public function route(): Route

return $this->route;
}

public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
if (!$this->isSuccess()) {
return $handler->handle($request);
}

// Inject dispatcher only if we have not previously injected.
// This improves performance in event-loop applications.
if ($this->dispatcher !== null && !$this->route->getData('hasDispatcher')) {
$this->route->injectDispatcher($this->dispatcher);
}

return $this->route
->getData('dispatcherWithMiddlewares')
->dispatch($request, $handler);
}
}
6 changes: 3 additions & 3 deletions src/Middleware/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface

$this->currentRoute->setRouteWithArguments($result->route(), $result->arguments());

return $result
->withDispatcher($this->dispatcher)
->process($request, $handler);
return $this->dispatcher
->withMiddlewares($result->route()->getData('middlewareDefinitions'))
->dispatch($request, $handler);
}
}
80 changes: 24 additions & 56 deletions src/Route.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use RuntimeException;
use Stringable;
use Yiisoft\Http\Method;
use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher;

use function in_array;

Expand Down Expand Up @@ -44,69 +43,50 @@ final class Route implements Stringable
private function __construct(
private array $methods,
private string $pattern,
private ?MiddlewareDispatcher $dispatcher = null
) {
}

/**
* @psalm-assert MiddlewareDispatcher $this->dispatcher
*/
public function injectDispatcher(MiddlewareDispatcher $dispatcher): void
{
$this->dispatcher = $dispatcher;
}

public function withDispatcher(MiddlewareDispatcher $dispatcher): self
public static function get(string $pattern): self
{
$route = clone $this;
$route->dispatcher = $dispatcher;
return $route;
return self::methods([Method::GET], $pattern);
}

public static function get(string $pattern, ?MiddlewareDispatcher $dispatcher = null): self
public static function post(string $pattern): self
{
return self::methods([Method::GET], $pattern, $dispatcher);
return self::methods([Method::POST], $pattern);
}

public static function post(string $pattern, ?MiddlewareDispatcher $dispatcher = null): self
public static function put(string $pattern): self
{
return self::methods([Method::POST], $pattern, $dispatcher);
return self::methods([Method::PUT], $pattern);
}

public static function put(string $pattern, ?MiddlewareDispatcher $dispatcher = null): self
public static function delete(string $pattern): self
{
return self::methods([Method::PUT], $pattern, $dispatcher);
return self::methods([Method::DELETE], $pattern);
}

public static function delete(string $pattern, ?MiddlewareDispatcher $dispatcher = null): self
public static function patch(string $pattern): self
{
return self::methods([Method::DELETE], $pattern, $dispatcher);
return self::methods([Method::PATCH], $pattern);
}

public static function patch(string $pattern, ?MiddlewareDispatcher $dispatcher = null): self
public static function head(string $pattern): self
{
return self::methods([Method::PATCH], $pattern, $dispatcher);
return self::methods([Method::HEAD], $pattern);
}

public static function head(string $pattern, ?MiddlewareDispatcher $dispatcher = null): self
public static function options(string $pattern): self
{
return self::methods([Method::HEAD], $pattern, $dispatcher);
}

public static function options(string $pattern, ?MiddlewareDispatcher $dispatcher = null): self
{
return self::methods([Method::OPTIONS], $pattern, $dispatcher);
return self::methods([Method::OPTIONS], $pattern);
}

/**
* @param string[] $methods
*/
public static function methods(
array $methods,
string $pattern,
?MiddlewareDispatcher $dispatcher = null
): self {
return new self($methods, $pattern, $dispatcher);
public static function methods(array $methods, string $pattern): self
{
return new self($methods, $pattern);
}

public function name(string $name): self
Expand Down Expand Up @@ -235,8 +215,8 @@ public function disableMiddleware(mixed ...$middlewareDefinition): self
* (T is 'hosts' ? array<array-key, string> :
* (T is 'methods' ? array<array-key,string> :
* (T is 'defaults' ? array<string,string> :
* (T is ('override'|'hasMiddlewares'|'hasDispatcher') ? bool :
* (T is 'dispatcherWithMiddlewares' ? MiddlewareDispatcher : mixed)
* (T is ('override'|'hasMiddlewares') ? bool :
* (T is 'middlewareDefinitions' ? array<array-key,array|callable|string> : mixed)
* )
* )
* )
Expand All @@ -246,6 +226,7 @@ public function disableMiddleware(mixed ...$middlewareDefinition): self
*/
public function getData(string $key): mixed
{
$middlewareDefinitions = $this->getEnabledMiddlewareDefinitions();
return match ($key) {
'name' => $this->name ??
(implode(', ', $this->methods) . ' ' . implode('|', $this->hosts) . $this->pattern),
Expand All @@ -255,9 +236,8 @@ public function getData(string $key): mixed
'methods' => $this->methods,
'defaults' => $this->defaults,
'override' => $this->override,
'dispatcherWithMiddlewares' => $this->getDispatcherWithMiddlewares(),
'hasMiddlewares' => $this->middlewareDefinitions !== [],
'hasDispatcher' => $this->dispatcher !== null,
'middlewareDefinitions' => $middlewareDefinitions,
'hasMiddlewares' => !empty($middlewareDefinitions),
default => throw new InvalidArgumentException('Unknown data key: ' . $key),
};
}
Expand Down Expand Up @@ -297,29 +277,17 @@ public function __debugInfo()
'actionAdded' => $this->actionAdded,
'middlewareDefinitions' => $this->middlewareDefinitions,
'disabledMiddlewareDefinitions' => $this->disabledMiddlewareDefinitions,
'middlewareDispatcher' => $this->dispatcher,
];
}

private function getDispatcherWithMiddlewares(): MiddlewareDispatcher
private function getEnabledMiddlewareDefinitions(): array
{
if ($this->dispatcher === null) {
throw new RuntimeException(sprintf('There is no dispatcher in the route %s.', $this->getData('name')));
}

// Don't add middlewares to dispatcher if we did it earlier.
// This improves performance in event-loop applications.
if ($this->dispatcher->hasMiddlewares()) {
return $this->dispatcher;
}

/** @var mixed $definition */
foreach ($this->middlewareDefinitions as $index => $definition) {
if (in_array($definition, $this->disabledMiddlewareDefinitions, true)) {
unset($this->middlewareDefinitions[$index]);
}
}

return $this->dispatcher = $this->dispatcher->withMiddlewares($this->middlewareDefinitions);
return $this->middlewareDefinitions;
}
}
Loading