-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Routing] Add support for 'priority' option for annotated Routes #11753
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
@@ -122,6 +132,10 @@ public function load($class, $type = null) | |||
$this->defaultRouteIndex = 0; | |||
foreach ($this->reader->getMethodAnnotations($method) as $annot) { | |||
if ($annot instanceof $this->routeAnnotationClass) { | |||
if ($annot->getOption('priority')) { | |||
$this->routesWithPriority[$annot->getOption('priority')][] |
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.
Where $this->routesWithPriority[$annot->getOption('priority')]
is initialized ?
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.
Which part do you mean? Priority key in option or routesWithPriority? first one will be in Route annotation from frameworkextrabundle, second is before the constructor
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.
Nevermind, I thought, that this code will raise a notice...
$foo = array();
$foo['bar'][] = 'baz';
Because $foo['bar']
is not defined, but it's works with E_STRICT
...
->will($this->returnValue($routeDatas)); | ||
|
||
$routeCollection = $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/BarClass.php'); | ||
$expectedOrder = array('foo', 'bar', 'home', 'login', 'static_contact', 'static_location', 'static_id'); |
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.
should'nt be array('static_contact', 'static_location', 'static_id', 'foo', 'bar', 'home', 'login');
? How to prioritize route before a route without priority.
Mays be routes without priority could be sets to 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 the original Issue there were no actual discussion about this and Ryan suggested to implement it in a way and let's see what will the community think. Of course that is also a viable option to set them to 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.
Yes, I agree with @jeremy-derusse: If there's no priority on a route, it should be treated like a 0. And so, a priority of 1 should be before all routes without a priority. This would be consistent with how event priority's are done: (https://github.com/symfony/symfony/blob/master/src/Symfony/Component/EventDispatcher/EventDispatcher.php#L95 and (https://github.com/symfony/symfony/blob/master/src/Symfony/Component/EventDispatcher/EventDispatcher.php#L176)
As far as implementing this, I'm not sure if the current approach of calling addPriorityRoutes
will work or not. We need to somehow take the final route $collection
(i.e. after the foreach
in AnnotationClassLoader
and re-order it based on the priority of all routes in that list. Perhaps a function that looks like $this->loader->reorderCollection($collection)
that compares the route names with an internal priority array that AnnotationClassLoader
has?
Thanks!
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.
Actually, I didn't wanted to touch RouteCollection
at all, but I have a proposal, RouteCollection
has a method, addOptions(), where if there is a route with priority at the end of the process I can pass in array(priority => 0)
and then every route in the RouteCollection
will have this value, and at the end in the DirectoryLoader
I add the routes with real priority option and with this, I don't need to change anything in the RouterCollection
.
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.
That sounds good to me! My proposal above also didn't touch RouteCollection
either, but as long as there's no downside to adding the option (I don't know of any), your idea will be cleaner.
At the end the solution was much easier, I created originally a new Collection of routes for the routes with priority and appended that one to the end of the original Collection, now I changed the order, I append the original routes to the end of the new Collection. |
What if I set a priority with a negative value (as I can do for events)? Your code will not place my route AFTER the routes without priority? foreach ($this->reader->getMethodAnnotations($method) as $annot) {
if ($annot instanceof $this->routeAnnotationClass) {
if (null === $priority = $annot->getOption('priority')) {
$priority = 0;
}
$this->routesWithPriority[$priority][] = array($annot, $globals, $class, $method);
}
} |
or simpler |
You are totally right Jeremy, I changed it as you suggested. |
} | ||
} | ||
} | ||
|
||
$collection = $this->addPriorityRoutes($collection); | ||
|
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.
you must reset the state of the loader here
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 looked for a way for that, but at the moment RouteCollection don't have such function, and if it's called in a directoryLoader, the named route will be removed and always appended to the end of the array, here in priority order. Or what do you mean by reseting?
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.
$routesWithPriority
is making the loader stateful. This means that if you import the routes from several classes explicitly, the second import will still see the priority routes of the first import, potentially creating weird issues
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.
Oh, I see what you mean. The original goal was that if you import the routes for the Controller directory, you can set up priority between the files.
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.
see my comment in the main discussion. This "feature" makes it very easy to break lots of things
I don't like the way the priority are working currently. Currently, the order of routes depends on the order of imports, and on the order inside the imported resource. This priority creates a new way for routes loaded through annotations, with interactions between several imported resources but not with resources from other formats.
I would vote for the second approach. And the implementation would be easy:
|
hmm, actually, the related ticket talks about controlling the order of files. This is much more complex (and is exactly the reason why the DirectoryLoader has been rejected from core) |
Yes, the original was that, but then if it's only for the directory, then it would be also a bit confusing to use it only there and why not in everywhere for annotations. But I also understand your problem here. |
Well, the issue is that ordering controllers compared to each other requires a different way to sort them, handled by the AnnotationDirectoryLoader, and sorting the controllers compared to each other only, not allowing to mix routes from each controller |
So I should implement it like I compare them only in the DirectoryLoader right? |
@ghostika if you want to solve the ordering of controllers, what should be found is a way to sort the different sub-collections loaded in the AnnotationDirectoryLoader. I don't know how we should define the priority then |
Closing this stale PR as the current implementation is not desirable. |
cherry picked, nice quick solutation still waiting for this feature in major symfony releases ... ;-) majbe not desirable for the team but desired from the people use symfony ;-) |
If the given route option parameter has a priority key, it will be sorted. The use case is described in the linked ticket. This is a new implementation, previous one (#11747) was proven bad.
If the changes are acceptable, then I will create the changes also for the Doc