Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
a60d03b
Add attributes support
rustamwin Mar 28, 2023
b328c82
Apply fixes from StyleCI
StyleCIBot Mar 28, 2023
3496866
Fix psalm annotation
rustamwin Mar 28, 2023
69d9832
Add tests
rustamwin Mar 28, 2023
bc421e9
Merge branch 'master' into add-attributes
xepozz May 29, 2023
875d7fd
Merge branch 'master' into add-attributes
xepozz Jun 8, 2023
777ff54
Add attributes registrar
rustamwin Jun 12, 2023
3959325
Apply fixes from StyleCI
StyleCIBot Jun 12, 2023
1651071
Add tests
rustamwin Jun 12, 2023
838bbc4
Fix tests & psalm issues
rustamwin Jun 15, 2023
4e63476
Apply fixes from StyleCI
StyleCIBot Jun 15, 2023
a0fb7a2
Add test cases
rustamwin Jun 15, 2023
ed2f60f
Apply fixes from StyleCI
StyleCIBot Jun 15, 2023
c239d53
Improve Route
rustamwin Aug 19, 2023
e8367aa
Add test
rustamwin Aug 19, 2023
2ab8dc2
Merge branch 'master' into add-attributes
xepozz Aug 19, 2023
2a60945
Increase coverage
rustamwin Aug 19, 2023
61eafb0
Merge remote-tracking branch 'origin/add-attributes' into add-attributes
rustamwin Aug 19, 2023
01665f4
Merge branch 'master' into add-attributes
xepozz Oct 9, 2023
e7d7a43
Add routes resource & attributes (#220)
rustamwin Oct 10, 2023
ab43b76
Fix AttributeRoutesProvider
rustamwin Oct 11, 2023
7a0e222
Allow attributes to use in classes
rustamwin Oct 15, 2023
2c38b06
Fix psalm annotation
rustamwin Oct 15, 2023
6a2bd4c
Add `RouteAttributeInterface` (#221)
vjik Oct 15, 2023
ab467d8
Adjust naming
rustamwin Oct 16, 2023
61cbc83
Minor improvements
rustamwin Oct 16, 2023
d85e667
Minor
rustamwin Oct 16, 2023
0ebcb5a
Move attribute collector it's own package
rustamwin Oct 23, 2023
3ff6921
Cleanup
rustamwin Oct 23, 2023
a81c91a
Minor
rustamwin Oct 23, 2023
5be62b4
Add changelog
rustamwin Nov 2, 2023
63467dc
Apply Rector changes (CI)
rustamwin Nov 2, 2023
91b5a87
Merge remote-tracking branch 'origin/master' into add-attributes
rustamwin Oct 21, 2025
81a5858
Fixes
rustamwin Oct 22, 2025
b44cd31
Apply Rector changes (CI)
rustamwin Oct 22, 2025
d3bc8e4
Apply fixes from StyleCI
StyleCIBot Oct 22, 2025
f4b3020
Fix psalm issues
rustamwin Oct 22, 2025
333edf7
Merge remote-tracking branch 'origin/master' into add-attributes
rustamwin Feb 11, 2026
5a0221d
Apply PHP CS Fixer and Rector changes (CI)
rustamwin Feb 11, 2026
26ea39e
Merge remote-tracking branch 'origin/master' into add-attributes
rustamwin Feb 23, 2026
00bf155
Fix: BC
rustamwin Mar 16, 2026
3326413
Add tests for default override and middleware behavior; enhance file …
rustamwin Mar 22, 2026
72c9f66
Refactor: remove unused properties in Group; add return type to middl…
rustamwin Mar 24, 2026
24f5323
Merge branch 'master' into add-attributes
samdark Mar 25, 2026
302fae5
Refactor: extract host normalization logic to a shared private method…
rustamwin Mar 26, 2026
f38b6da
Apply PHP CS Fixer and Rector changes (CI)
rustamwin Mar 26, 2026
b7f262f
Apply PHP CS Fixer and Rector changes (CI)
samdark Mar 26, 2026
bb2a333
Update CHANGELOG: consolidate duplicate entries for #196
rustamwin Mar 26, 2026
0b981f1
Refactor: improve PHPDoc for route attributes and update validation m…
rustamwin Apr 2, 2026
4ec6f08
Apply PHP CS Fixer and Rector changes (CI)
rustamwin Apr 2, 2026
a9dffd4
Update CHANGELOG: add bug fix entry for `Group::hosts()` method consi…
rustamwin Apr 2, 2026
b0e9813
Add phpdoc
samdark Apr 3, 2026
65e1e13
Mark `Group::create`, `RouteCollectorInterface`, `RouteCollector`, an…
rustamwin Apr 9, 2026
a8b9596
Update src/Route.php
samdark Apr 9, 2026
58a88d5
Fix incorrectly backtick usage and wrong class name in @deperecated
samdark Apr 9, 2026
1c16802
Add validation for single route case
samdark Apr 9, 2026
35c4c40
Apply PHP CS Fixer and Rector changes (CI)
samdark Apr 9, 2026
82c8fa1
Allow passing method as a single value instead of an array
samdark Apr 10, 2026
1206c2a
Action is used more than name, swap order
samdark Apr 10, 2026
652bdae
Add missing phpdoc
samdark Apr 10, 2026
69c2c62
Add missing Group phpdoc
samdark Apr 10, 2026
60bd8ee
Remove unclear statement
samdark Apr 10, 2026
9626883
Use cast instead of check to get an array from $method
samdark Apr 10, 2026
e1ad7e8
Apply PHP CS Fixer and Rector changes (CI)
samdark Apr 10, 2026
8b5cdbc
Compare with empty array instead of using `empty()`
samdark Apr 10, 2026
cc20fc2
Fix: suppress psalm warnings and enhance PHPDocs in Route and RouteCo…
rustamwin Apr 14, 2026
12bd3fc
Apply PHP CS Fixer and Rector changes (CI)
rustamwin Apr 14, 2026
860f963
Fix: suppress psalm warnings and improve PHPDocs in RouteCollection a…
rustamwin Apr 14, 2026
a03bfb4
Merge remote-tracking branch 'origin/add-attributes' into add-attributes
rustamwin Apr 14, 2026
f6abda7
Fix: suppress psalm warnings and enhance PHPDocs in RouteCollection
rustamwin Apr 14, 2026
a5b3a60
Fix: adjust psalm suppression placement in RouteCollection PHPDoc
rustamwin Apr 14, 2026
c080a1c
Kill mutation
rustamwin Apr 15, 2026
2aa46f1
Refactor: mark `$container` as readonly in `RouterCollector` and upda…
rustamwin Apr 18, 2026
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## 4.0.3 under development

- New #196: Add PHP Attributes support (@rustamwin)
- New #196: Add `RoutesProviderInterface` interface providing routes from various resources (@rustamwin)
- Bug #196: Fix the behavior of `Group::hosts()` method to be consistent with `Route::hosts()` method (@rustamwin)

@samdark samdark Apr 10, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to mention the deprecation of Route static constructors and describe these in the README.

- Chg #196: Make constructor of `Route` and `Group` classes public (@rustamwin)
- Chg #196: Deprecate static methods of `Route` and `Group` classes (@rustamwin)
- Enh #276: Explicitly import classes, functions, and constants in the "use" section (@rustamwin)
- Enh #277, #281: Remove restrictions from `prependMiddleware()` and `middleware()` methods (@klsoft-web, @vjik)

Expand Down
33 changes: 32 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ with an adapter package. Currently, the only adapter available is [FastRoute](ht
- Ready to use middleware for route matching.
- Convenient `CurrentRoute` service that holds information about last matched route.
- Out of the box CORS middleware support.
- Declaring routes using PHP attributes.

@samdark samdark Apr 10, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be an example for using attributes and then reading these with yiisoft/router-composer-attribute-collector.


## Requirements

Expand All @@ -45,7 +46,7 @@ Additionally, you will need an adapter such as [FastRoute](https://github.com/yi

## Defining routes and URL matching

Common usage of the router looks like the following:
#### Common usage of the router looks like the following

```php
use Yiisoft\Router\CurrentRoute;
Expand Down Expand Up @@ -101,6 +102,36 @@ if (!$result->isSuccess()) {
$response = $result->process($request, $notFoundHandler);
```

#### Using attributes is also supported

In controller:

```php
use Yiisoft\Router\Attribute\Get;

final class SiteController
{
//...

#[Get('/')]
public function home(ServerRequestInterface $request): ResponseInterface
{
return $this->responseFactory->createResponse()->withBody(
$this->streamFactory->createStream('You are at homepage.')
);
}

#[Get('/test/{id:\w+}')]
public function test(CurrentRoute $currentRoute): ResponseInterface
{
$id = $currentRoute->getArgument('id');

return $this->responseFactory->createResponse()->withBody(
$this->streamFactory->createStream('You are at test with argument ' . $id)
);
}
```

> Note: Despite `UrlGeneratorInterface` and `UrlMatcherInterface` being common for all adapters available, certain
> features and, especially, pattern syntax may differ. To check usage and configuration details, please refer
> to specific adapter documentation. All examples in this document are for
Expand Down
58 changes: 58 additions & 0 deletions src/Attribute/Delete.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Router\Attribute;

use Attribute;
use Stringable;
use Yiisoft\Http\Method;
use Yiisoft\Router\Route;

/**
* Route attribute that defines a DELETE HTTP method route.
*/
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
final class Delete implements RouteAttributeInterface
{
private readonly Route $route;

/**
* @param string $pattern Route pattern.
* @param string|null $name Route name.
* @param array[]|callable[]|string[] $middlewares Middlewares to be added to the route.
* @param array<string,scalar|Stringable|null> $defaults Parameter default values indexed by parameter names.
* @param string[] $hosts Hosts that the route should match.
* @param bool $override Marks route as override. When added, it will replace the existing route with the same name.
* @param array $disabledMiddlewares 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.
*
* @psalm-param list<array|callable|string> $middlewares
*/
public function __construct(
string $pattern,
?string $name = null,
array $middlewares = [],
array $defaults = [],
array $hosts = [],
bool $override = false,
array $disabledMiddlewares = [],
) {
$this->route = new Route(
method: [Method::DELETE],
pattern: $pattern,
name: $name,
middlewares: $middlewares,
defaults: $defaults,
hosts: $hosts,
override: $override,
disabledMiddlewares: $disabledMiddlewares,
);
}

public function getRoute(): Route
{
return $this->route;
}
}
58 changes: 58 additions & 0 deletions src/Attribute/Get.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Router\Attribute;

use Attribute;
use Stringable;
use Yiisoft\Http\Method;
use Yiisoft\Router\Route;

/**
* Route attribute that defines a GET HTTP method route.
*/
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
final class Get implements RouteAttributeInterface
{
private readonly Route $route;

/**
* @param string $pattern Route pattern.
* @param string|null $name Route name.
* @param array[]|callable[]|string[] $middlewares Middlewares to be added to the route.
* @param array<string,scalar|Stringable|null> $defaults Parameter default values indexed by parameter names.
* @param string[] $hosts Hosts that the route should match.
* @param bool $override Marks route as override. When added it will replace existing route with the same name.
* @param array $disabledMiddlewares 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.
*
* @psalm-param list<array|callable|string> $middlewares
*/
public function __construct(
string $pattern,
?string $name = null,
array $middlewares = [],
array $defaults = [],
array $hosts = [],
bool $override = false,
array $disabledMiddlewares = [],
) {
$this->route = new Route(
method: [Method::GET],
pattern: $pattern,
name: $name,
middlewares: $middlewares,
defaults: $defaults,
hosts: $hosts,
override: $override,
disabledMiddlewares: $disabledMiddlewares,
);
}

public function getRoute(): Route
{
return $this->route;
}
}
58 changes: 58 additions & 0 deletions src/Attribute/Head.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Router\Attribute;

use Attribute;
use Stringable;
use Yiisoft\Http\Method;
use Yiisoft\Router\Route;

/**
* Route attribute that defines a HEAD HTTP method route.
*/
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
final class Head implements RouteAttributeInterface
{
private readonly Route $route;

/**
* @param string $pattern Route pattern.
* @param string|null $name Route name.
* @param array[]|callable[]|string[] $middlewares Middlewares to be added to the route.
* @param array<string,scalar|Stringable|null> $defaults Parameter default values indexed by parameter names.
* @param string[] $hosts Hosts that the route should match.
* @param bool $override Marks route as override. When added, it will replace the existing route with the same name.
* @param array $disabledMiddlewares 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.
*
* @psalm-param list<array|callable|string> $middlewares
*/
public function __construct(
string $pattern,
?string $name = null,
array $middlewares = [],
array $defaults = [],
array $hosts = [],
bool $override = false,
array $disabledMiddlewares = [],
) {
$this->route = new Route(
method: [Method::HEAD],
pattern: $pattern,
name: $name,
middlewares: $middlewares,
defaults: $defaults,
hosts: $hosts,
override: $override,
disabledMiddlewares: $disabledMiddlewares,
);
}

public function getRoute(): Route
{
return $this->route;
}
}
58 changes: 58 additions & 0 deletions src/Attribute/Options.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Router\Attribute;

use Attribute;
use Stringable;
use Yiisoft\Http\Method;
use Yiisoft\Router\Route;

/**
* Route attribute that defines an OPTIONS HTTP method route.
*/
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
final class Options implements RouteAttributeInterface
{
private readonly Route $route;

/**
* @param string $pattern Route pattern.
* @param string|null $name Route name.
* @param array[]|callable[]|string[] $middlewares Middlewares to be added to the route.
* @param array<string,scalar|Stringable|null> $defaults Parameter default values indexed by parameter names.
* @param string[] $hosts Hosts that the route should match.
* @param bool $override Marks route as override. When added, it will replace the existing route with the same name.
* @param array $disabledMiddlewares 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.
*
* @psalm-param list<array|callable|string> $middlewares
*/
public function __construct(
string $pattern,
?string $name = null,
array $middlewares = [],
array $defaults = [],
array $hosts = [],
bool $override = false,
array $disabledMiddlewares = [],
) {
$this->route = new Route(
method: [Method::OPTIONS],
pattern: $pattern,
name: $name,
middlewares: $middlewares,
defaults: $defaults,
hosts: $hosts,
override: $override,
disabledMiddlewares: $disabledMiddlewares,
);
}

public function getRoute(): Route
{
return $this->route;
}
}
58 changes: 58 additions & 0 deletions src/Attribute/Patch.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Router\Attribute;

use Attribute;
use Stringable;
use Yiisoft\Http\Method;
use Yiisoft\Router\Route;

/**
* Route attribute that defines a PATCH HTTP method route.
*/
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
final class Patch implements RouteAttributeInterface
{
private readonly Route $route;

/**
* @param string $pattern Route pattern.
* @param string|null $name Route name.
* @param array[]|callable[]|string[] $middlewares Middlewares to be added to the route.
* @param array<string,scalar|Stringable|null> $defaults Parameter default values indexed by parameter names.
* @param string[] $hosts Hosts that the route should match.
* @param bool $override Marks route as override. When added, it will replace the existing route with the same name.
* @param array $disabledMiddlewares 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.
*
* @psalm-param list<array|callable|string> $middlewares
*/
public function __construct(
string $pattern,
?string $name = null,
array $middlewares = [],
array $defaults = [],
array $hosts = [],
bool $override = false,
array $disabledMiddlewares = [],
) {
$this->route = new Route(
method: [Method::PATCH],
pattern: $pattern,
name: $name,
middlewares: $middlewares,
defaults: $defaults,
hosts: $hosts,
override: $override,
disabledMiddlewares: $disabledMiddlewares,
);
}

public function getRoute(): Route
{
return $this->route;
}
}
Loading
Loading