What I did:
When I open http://localhost/say/Goodbye in a browser, the page displays “The message is: Hello!”, but “The message is: Goodbye” is expected.
What I did:
When I open http://localhost/say/Goodbye in a browser, the page displays “The message is: Hello!”, but “The message is: Goodbye” is expected.
I am having the same issue.
I wondered if the instructions were out of date as these two links have different instructions.
a) docs/guide/en/start/hello.md at master · yiisoft/docs · GitHub
I tried following a) but it doesn’t work, and b) gives an error.
By doesn’t work I mean it prints the default message, not what I pass in the URL.
I just asked Grok and it suggested the following which worked. Not sure if that makes it the correct approach.
The problem is in this line of your routes.php:
Route::get('/say[/{message}]')
The square brackets [] make the entire part /say/{message} optional in Yii Router (which uses yiisoft/router).
So this route matches both:
/say → $message gets the default value 'Hello!'
/say/anything → $message gets the value anything
But it also matches /say with no trailing slash or parameter at all, and when the parameter is missing, your action uses the default value 'Hello!'.
When you visit:
http://localhost:8080/say/Hello11
The router matches the route correctly and passes Hello11 as $message.
But you say it prints “Hello!” instead of “Hello11”.
That means: the $message parameter inside your action is NOT receiving the value from the URL.
You are using a custom attribute:
#[RouteArgument('message')]
But in yiisoft/router v2+ (which is used by Yii 3), the correct attribute is:
use Yiisoft\Router\CurrentRoute;
use Yiisoft\Router\Attribute\Argument; // or Parameter
The attribute class you are using:
use Yiisoft\Router\HydratorAttribute\RouteArgument;
→ This class was removed / renamed a long time ago (around 2021–2022).
It no longer exists in current versions of yiisoft/router.
So the attribute is completely ignored → the method receives only default parameters → $message stays 'Hello!'.
<?php
declare(strict_types=1);
namespace App\Web\Echo;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Yiisoft\Html\Html;
use Yiisoft\Router\CurrentRoute;
final readonly class Action
{
public function __construct(
private ResponseFactoryInterface $responseFactory,
private CurrentRoute $currentRoute,
) {}
public function __invoke(): ResponseInterface
{
$message = $this->currentRoute->getArgument('message', 'Hello!');
$response = $this->responseFactory->createResponse();
$response->getBody()->write('The message is: ' . Html::encode($message));
return $response;
}
}
And keep your route exactly as:
Route::get('/say[/{message}]')
->action(Web\Echo\Action::class)
->name('echo/say'),
This works perfectly.
use Yiisoft\Router\Attribute\Parameter;
public function __invoke(#[Parameter('message')] string $message = 'Hello!'): ResponseInterface
{
// ...
}
But note: the attribute class name has changed over time. In the latest versions it’s:
use Yiisoft\Router\Attribute\RouteParameter;
So:
use Yiisoft\Router\Attribute\RouteParameter;
public function __invoke(#[RouteParameter('message')] string $message = 'Hello!'): ResponseInterface
If you never want the default “Hello!”, just make it required:
Route::get('/say/{message}', Web\Echo\Action::class)->name('echo/say');
and remove the default value in PHP.
Your code doesn’t work because:
use Yiisoft\Router\HydratorAttribute\RouteArgument;
→ This attribute no longer exists in current Yii 3 / yiisoft/router.
Fix: Use CurrentRoute (recommended) or the correct up-to-date attribute (RouteParameter).
After changing to CurrentRoute, visiting /say/Hello11 will correctly show:
The message is: Hello11
Let me know which version of yiisoft/router you have (composer show yiisoft/router) if you want the exact attribute name for your version. But in 99% of Yii 3 projects today, the CurrentRoute solution above is the cleanest and most widely used.
Solution 1 works, but it is definitely not the standard approach.
Solution 2 almost works, but the conclusion of Yiisoft\Router\HydratorAttribute\RouteArgument is wrong.
So, the correct solution is
Replace:
#[RouteArgument('message')]
public function __invoke(string $message = 'Hello!'): ResponseInterface
with:
public function __invoke(#[RouteArgument('message')] string $message = 'Hello!'): ResponseInterface
Solution 3 does not work.
Thanks,
That worked!