#444: Use matched incoming parameters for same route generation on a hierarchial
basis
---------------------+------------------------------------------------------
Reporter: david | Owner: dominik
Type: task | Status: new
Priority: highest | Milestone: 0.11
Component: routing | Version: 0.11.0RC2
Severity: blocker | Keywords:
---------------------+------------------------------------------------------
[1714] implemented #434 which disabled the use of incoming request params
as defaults when generating the same URL as the one that matched in the
request.
Well, turns out that was not such a good idea after all. While the issue
described there is fixed, the new behavior might not be the most
convenient or even intuitive.
Never thought I'd say this, but we can copy an idea from Ruby on Rails
here: assuming a hierarchy of values.
The basic idea is that when generating a route, and that route was the one
that matched during the current request, then the incoming values are used
as defaults, but only those '''to the left of the leftmost supplied
parameter'''. Example:
{{{
<route name="search" pattern="^/search/(term:[^/]+)/(page:\d+)/$">
<default for="page">1</default>
</route>
}}}
Let's assume our incoming url is {{{/search/agavi/13/}}}, then
* {{{$ro->gen('search', array('page' => 14));}}} would produce
{{{/search/agavi/14/}}}.
* {{{$ro->gen('search', array('term' => 'snoopy'));}}} would produce
{{{/search/snoopy/1/}}}.
That is fairly simple then. However, if we change our route example a
little bit so the page is optional:
{{{
<route name="search" pattern="^/search/(term:[^/]+)/({page:\d+}/)?$">
<default for="page">1</default>
</route>
}}}
then {{{$ro->gen('search', array('term' => 'snoopy'));}}} could produce
two things:
* {{{/search/snoopy/1/}}}
* {{{/search/snoopy/}}}
The issue here is the default. Without it, things would be simple. The
page would be simply omitted. The problem is that you _want_ the page
default because you then get a value in your action even if none was
supplied in the URL.
Rails doesn't have this problem. There, all URL chunks count as optional,
and the {{{/}}} is "hardcoded" as a delimiter, they have no inline regular
expressions. We have these, it's not as simple in our case, and we have to
find a decent solution.
One thing to keep in mind here is that it should still be optional to
"skip" parameters by passing {{{null}}} for it in the gen() call (e.g.
{{{$ro->gen('lala', array('foo' => null));}}}). Right now, this always
omits the respective parameter portion in the pattern entirely. I have
thought of the following change for when {{{null}}} is passed:
* If the parameter is an optional pattern, it is skipped entirely and not
present in the route
* If the parameter is not an optional pattern, the default for the
parameter is used
Applying that to Snoopy's problem outlined above, we could establish that
all parameters to the right side of the last supplied parameter are
assumed to be null. Therefor, the result would be {{{/search/snoopy/}}}
because the page parameter is optional and the default is not used.
----
Also, something regarding parent routes. If we have this (yes, the actual
date patterns would have to be more complex):
{{{
<route name="blog" pattern="^/blog/(name:[^/]+)" module="Blog">
<route name=".index" pattern="^/$" action="Index" />
<route name=".entry" pattern="^/(id:\d+).html$" action="Entry" />
<route name=".archive"
pattern="^/(year:20\d{2})/({month:\d{2}/)?({day:\d{2}/)?"
action="Archive">
<default for="year">2007</default>
</route>
</route>
<route name="profile" pattern="^/profile/(name:[^/]+)/$" ... />
}}}
And our current URL is {{{/blog/woodstock/2006/07/13}}}, then:
* {{{$ro->gen('blog.archive', array('month' => 11));}}} will produce
{{{/blog/woodstock/2006/11/}}}
* {{{$ro->gen('blog.entry', array('id' => 22));}}} will produce
{{{/blog/woodstock/22.html}}}
* {{{$ro->gen('blog.archive', array('name' => 'snoopy'));}}} will produce
{{{/blog/snoopy/2007/}}}
That means parent routes are included in these rules, too.
One thing I should mention: Rails doesn't require named routes. I'm not
quite sure, but I ''think'' that in Rails {{{$ro->gen('profile');}}} would
produce {{{/profile/woodstock/}}} whereas in Agavi you'd end up with
{{{/profile//}}} since no {{{name}}} would be implied because the
{{{profile}}} route isn't on "the way upwards". All of the above would
only work for those generated routes that also matched during the current
request.
----
Is that all okay like that? Anything missing? Questions? Comments?
--
Ticket URL: <http://trac.agavi.org/ticket/444>
Agavi <http://www.agavi.org/>
An MVC Framework for PHP5
_______________________________________________
Agavi Tickets Mailing List
[email protected]
http://lists.agavi.org/mailman/listinfo/tickets