-
Notifications
You must be signed in to change notification settings - Fork 196
Route with optional params throws errors with Zend Router and View #186
Comments
You're accustomed to the ZF2 behavior. 😄 In ZF2, we inject the URL helpers with the RouteMatch, allowing it to use matched values unless overridden. To get similar behavior in Expressive, we'd need to inject helpers (or the TwigExtension, or similar features for other template renderer implementations) with the For the record, the I think we should likely take the following actions:
I think the first two can be done during the RC status, and I'll slate the third to a 1.1 release, as it would be a new feature. Once the first two items are accomplished, you can have your middleware injected with the When we accomplish the third item, we can then ship zend-expressive-zendviewrenderer with middleware to accomplish this automatically. |
You're accustomed to the ZF2 behavior. 😄 Seems that I am getting to be old-school these days. ;-) Sounds great and I guess I will not be the only one demanding this feature. Until all this is implemented I have just split my route into two different routes. One without the params and one with them. That solved the problem for now. But I am really looking forward for your suggested solution. |
@RalfEggert #200 is helping address this, and I'll be following that up with a PR against zendframework/zend-expressive-zendviewrenderer to provide a delegator factory to use with that renderer; the result will be injection of the URL view helper with the calculated |
@RalfEggert Also for your review: zendframework/zend-expressive-zendviewrenderer#9 and zendframework/zend-expressive-skeleton#25. |
@weierophinney |
Wait until RC3 is tagged on both the zend-expressive AND zend-expressive-skeleton repos; that'll be the easiest way to test it out. The skeleton repo will also show you how you can register the delegator factory (assuming you're using zend-servicemanager) to make the behavior automatic. |
Ok, I will wait then. :-) |
@RalfEggert This is now addressed in RC3! If you already have an application, you'll need to update your dependency versions for all router and template selections to use Finally, you'll need to add the following to the
In
At that point, everything should work together. zendviewrenderer wraps the |
Ok, my
I added the configs as you suggested. But working with optional route params like described in the original post still does not work. This means, I still get an What did I miss? |
Maybe my routing definition is wrong? |
I've tracked it down; it's an order of operations issue. The The problem is that this is the first that the Interestingly, I ran into a related, but different, situation yesterday when using my phly-expressive-mustache package: in that case, I'm pulling the I think I'm going to need to alter this, and have the namespace Zend\Expressive\Container;
use Interop\Container\ContainerInterface;
use Zend\Expressive\Application;
use Zend\Expressive\Helper\UrlHelper;
class ApplicationFactory
{
function __invoke(ContainerInterface $container)
{
/* create the application instance, inject routes, etc. */
if ($container->has(UrlHelper::class)) {
$application->attachRouteResultObserver($container->get(UrlHelper::class));
}
return $application;
} The second would look like this: namespace Zend\Expressive\Helper;
use Zend\Expressive\Router\RouteResultSubjectInterface;
class UrlHelperMiddleware
{
private $application;
private $helper;
public function __construct(UrlHelper $helper, RouteResultSubjectInterface $application)
{
$this->helper = $helper;
$this->application = $application;
}
public function __invoke($request, $response, callable $next)
{
$this->application->attachRouteResultObserver($this->helper);
return $next($request, $response);
}
} A third approach is to use delegator factories (if using the service manager), or Pimple's In both cases, the The first approach would be more turn-key; however, it also depends on you having the zend-expressive-helpers package installed. I'm not sure how I feel about specifying a service that the package does not require. Additionally, it opens the gates for having another configuration feature (route result observers), and that's another vector to maintain. The second approach would work regardless of middleware library, so long as you're also consuming zend-expressive-router. However, it requires a bit more configuration. That said, we could do this by default in the skeleton, just like we do with the I'll get something in place for an RC4 in the next 1–2 days. Thanks for challenging me on this, @RalfEggert ! |
Thanks for the explanation. I don't mind if the solution works kind of out of the box or is rather an configuration issue. If it needs to be installed via the skeleton, than its OK to me. Most important is that it works for beginners with the 1.0.0 release. |
@RalfEggert Yes, the idea is to ensure this works out-of-the-box. If you could, please take a look at zendframework/zend-expressive-helpers#2, as it implements the middleware-based solution. Once I've merged that I'll also update the skeleton, and then the docs for zend-expressive. |
@RalfEggert I've merged the changes in zend-expressive-helpers and released v1.2.0 of that package. I've also now updated zend-expressive-skeleton to use that version, and to add configuration for the new To test it locally, I did the following: Created a new application based on dev-master of the skeleton$ composer create-project zendframework/zend-expressive-skeleton expressive "~1.0.0-dev@dev" I selected:
Manually created the route reportedIn $app->get('/voting[/:pos[/:neg]]', function ($req, $res, $next) use ($container) {
$renderer = $container->get(TemplateRendererInterface::class);
$r = new ReflectionProperty($renderer, 'renderer');
$r->setAccessible(true);
$phpRenderer = $r->getValue($renderer);
$res->write(sprintf("url(): %s<br />\n", $phpRenderer->url()));
$res->write(sprintf("url('voting'): %s<br />\n", $phpRenderer->url('voting')));
$res->write(sprintf("url('voting', ['pos' => 10000]): %s<br />\n", $phpRenderer->url('voting', ['pos' => 10000])));
$res->write(sprintf("url('voting', ['neg' => 10000]): %s<br />\n", $phpRenderer->url('voting', ['neg' => 10000])));
return $res;
}, 'voting'); Started a web serverI used the built-in web server: $ php -S 0.0.0.0:8080 -t public/ Navigated to the new routeI navigated to
So, I can verify it's now working correctly! |
Just verified the changes solved my issues in phly-expressive-mustache as well! 😄 |
Checked it and it works as expected! Nice work! |
Hello @RalfEggert , @weierophinney . I had similar doubts with the new url helpers Let's assume a named route 'voting' as implemented in your prevous examples. What if I wish that $urlHelper->generate('voting', /*[]*/); would provide just '/voting' I tried the new url helpers with the following route segments alternately 'hello[/:name]'; /*(1)*/
'hello[/:[name]]'; /*(2)*/ with a simple route defined as //...
[
'name' => 'hello',
'path' => '/hello[/:name]'/*(1)*/,/*'hello[/:[name]]*/ /*(2)*/
'middleware' => App\Action\HelloAction::class,
'allowed_methods' => ['GET'],
], In both cases calling generate() without a 'name' parameter results a zend mvc exception If i use ['name' => null] i get the same exception (parameter check is using isset) '/hello/'; // with route 1
'/hello'; // with route 2 i get the same results setting the 'name' parameter using //...
[
'name' => 'hello',
'path' => '/hello[/[:name]]',
'middleware' => App\Action\HelloAction::class,
'allowed_methods' => ['GET'],
'options' => [
'defaults' => [
'name' => '',
]
]
],
//... Wouldn't it be better to allow null|unset parameters for optional segments? kind regards. |
@pine3ree The behavior you're seeing is not due to the zend-expressive implementation, but rather how the zend-mvc router works with regards to generating URIs. As such, raise an issue in zendframework/zend-mvc. |
@weierophinney |
I am using
Zend\Expressive
with the Zend View and the Zend Router and have some problems with an optional route param.The routing works fine. But the usage of the URL view helper does not. It forces me to always path values for both optional params.
But if I pass no values for the optional params, I get a
Zend\Mvc\Router\Exception\InvalidArgumentException
with messageMissing parameter "pos"
.Is this a bug or is my route config wrong?
The text was updated successfully, but these errors were encountered: