-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Routing] UrlGenerator: add a method 'hasRoute' to check whether a route exists #19273
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
Conversation
* | ||
* @return bool | ||
*/ | ||
public function hasRoute($name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because of backwards compatibility breaks, it cannot be added to the interface before Symfony 4.0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In any case, I would not add it even in 4.0 as this does not belongs to a generator interface IMHO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, indeed, it would make more sense in the Router
interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you describe use-case when you need optional routes? From my point of view, optional routes make code more fragile and unpredictable. |
@unkind imagine loading routes from a database (e.g. using Symfony CMF's DynamicRouter). This is one of the core concepts of a CMS (and thus a core concept of all CMSes built on Symfony). |
@unkind, For example, I want to automatically create CRUD buttons for resources like 'products', 'options', and etc: $resource = 'product';
...
$actions = [];
foreach ([ 'view', 'edit', 'delete' ] as $action) {
if ($router->hasRoute($resource . '_' . $action)) {
$actions[$action] = $router->generate($resource . '_' . $action, [ 'id' => $resourceId ]);
}
} |
*/ | ||
public function hasRoute($name) | ||
{ | ||
return $this->getGenerator()->hasRoute($name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the interface doesn't have this method anymore, you shouldn't directly use it.
getGenerator()
may return different implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@unkind, you're rigth! I think we could add a method availability checking:
public function hasRoute($name)
{
if (!method_exists($this->getGenerator(), 'hasRoute')) {
throw new \RuntimeException("Current implementation of an url generator doesn't support this method.");
}
return $this->getGenerator()->hasRoute($name);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's terrible IMO.
It's clear that new interface is missing.
@wouterj does it make sense to make separate contract This behaviour is specific for dynamic routers, but in general it's not great. |
@unkind I think that the word "dynamic" means nothing in this case. IMO the word "dynamic" means that we can to add new routes at the runtime. But we just want to check a route existence. |
Maybe "dynamic" is not good naming for this case, but I failed to find better one. |
@unkind |
@unkind, I've added the |
I'm sorry for confusion, but my idea is to make truly separate service which has nothing to do with |
Seems strange that only the generator implements hasRoute but the matcher doesn't. |
@Tobion, the url matche is dumped to class with public function match($pathinfo)
{
$allow = array();
$pathinfo = rawurldecode($pathinfo);
$context = $this->context;
$request = $this->request;
if (0 === strpos($pathinfo, '/_')) {
// _wdt
if (0 === strpos($pathinfo, '/_wdt') && preg_match('#^/_wdt/(?P<token>[^/]++)$#s', $pathinfo, $matches)) {
return $this->mergeDefaults(array_replace($matches, array('_route' => '_wdt')), array ('_controller' => 'web_profiler.controller.profiler:toolbarAction'));
}
if (0 === strpos($pathinfo, '/_profiler')) {
// _profiler_home
if (rtrim($pathinfo, '/') === '/_profiler') {
if (substr($pathinfo, -1) !== '/') {
return $this->redirect($pathinfo.'/', '_profiler_home');
}
return array ( '_controller' => 'web_profiler.controller.profiler:homeAction', '_route' => '_profiler_home',);
}
}
// ...
} So, we haven't access to the route names after matcher was dumped. |
use Symfony\Component\Routing\Exception\RouteNotFoundException; | ||
use Symfony\Component\Routing\RequestContext; | ||
use Symfony\Component\Routing\RouteCollection; | ||
use Symfony\Component\Routing\RoutePresenceCheckableInterface; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The order change of use statements must be reverted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fabpot, Fixed.
* | ||
* @author Oleg Voronkovich <oleg-voronkovich@yandex.ru> | ||
*/ | ||
interface RoutePresenceCheckableInterface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add this method instead in Symfony 4.0 and not create this RoutePresenceCheckableInterface
? It looks overkill to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@javiereguiluz, So, to which interface the hasRoute
method should be moved?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any hint @javiereguiluz ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know about the internal details, but I'd like to call this method on the router
object:
// old Symfony
public function indexAction()
{
if ($this->get('router')->hasRoute('special_route')) {
// ...
}
}
// new Symfony
public function indexAction(RouterInterface $router)
{
if ($router->hasRoute('special_route')) {
// ...
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@javiereguiluz, the router
implements the RoutePresenceCheckableInterface
interface, so your code should work fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I was suggesting to add it in UrlGeneratorInterface
(only in Sf 4.0) to avoid creating micro-interfaces.
I'm really no fan of the extra interface, so 👎 to add it in the Routing component. Instead, I'd propose to add a new twig |
What about making this interface a bit more capable, to cover #19302 also? |
@nicolas-grekas, The dumper doesn't dump some matching-related data like route conditions and maybe something else. |
This doesn't have to be true tomorrow :)
|
@nicolas-grekas How do we move forward here? |
@voronkovich would that work for you? up to implement it? (let's forget about #19273 (comment)) |
This method is usefull when you want just to check whether a route exists:
See #19270 and symfony/symfony-docs#6710