Hi,
I've just run into a problem when trying to assemble a route into a link.
Allow me to demonstrate:
$route = new Zend_Controller_Router_Route_Regex(
'foo/(\d+)(/(\w+))?',
array(
'module' => 'MyModule',
'controller' => 'Foo',
'action' => 'index'
),
array(
1 => 'id',
3 => 'action'
),
'foo/%d/%s'
);
$router = Zend_Controller_Front::getInstance()->getRouter();
$router->addRoute('MyRoute', $route);
This route should match urls:
* /foo/123 (action = index)
* /foo/123/ (action = index) (this works due to the matcher striping
off leading/trailing slashes)
* /foo/123/bar (action = bar)
If I were to put the / as a required part of the regexp like this:
'foo/(\d+)/(\w+)?'
then this will never match the index case without specifying it
explicitly (i.e. the first two example URLs above will not match).
If, during a request, this route *was matched* (this is important), it
will be filled in with the various bits of data that matched the regexp,
including the 2nd expression that I really don't care about.
If, in the controller/action code, I need to generate a new link using
this route, I would use the assemble() method.
$router = Zend_Controller_Front::getInstance()->getRouter();
$route = $router->getRoute('MyRoute');
$link = $route->assemble(array('id'=>123, 'action'=>'wibble'));
In this example $link == 'foo/123//bar' which is clearly wrong (it
should be 'foo/123/wibble').
If the link was not matched during that request, it works fine.
Now, I can generate the link differently:
$link = $route->assemble(array('id'=>123, 2=>null,
'action'=>'wibble'));
And this works, but this requires external (from the perspective of the
route definition) knowledge of the how the route works, which is not
good programming practice.
Looking at the code in Zend_Controller_Router_Route_Regex, call-time
nullification is the only time this can be work.
I'm not actually sure why you'd want to do this at call time. I can't
think of an example as to where this would be useful. Perhaps someone
can enlighten me?
If however, I were setup the *defaults* to tell it to ignore some
matches, then this, to me, seems a sensible approach:
$route = new Zend_Controller_Router_Route_Regex(
'foo/(\d+)(/(\w+))?',
array(
'module' => 'MyModule',
'controller' => 'Foo',
'action' => 'index',
2 => null /* ignore the 2nd match */
),
array(
1 => 'id',
3 => 'action'
),
'foo/%d/%s'
);
Sadly, this doesn't work :(
If I patch the regexp route, I can make it work:
Index: Controller/Router/Route/Regex.php
===================================================================
--- Controller/Router/Route/Regex.php (revision 30213)
+++ Controller/Router/Route/Regex.php (working copy)
@@ -155,12 +155,11 @@
$dataValuesMapped = $this->_getMappedValues($data, true,
false);
// handle resets, if so requested (By null value) to do so
- if (($resetKeys = array_search(null, $dataValuesMapped, true))
!== false) {
+ if (($resetKeys = array_search(null, $defaultValuesMapped,
true)) !== false) {
foreach ((array) $resetKeys as $resetKey) {
- if (isset($matchedValuesMapped[$resetKey])) {
- unset($matchedValuesMapped[$resetKey]);
- unset($dataValuesMapped[$resetKey]);
- }
+ unset($matchedValuesMapped[$resetKey]);
+ unset($dataValuesMapped[$resetKey]);
+ unset($defaultValuesMapped[$resetKey]);
}
}
This essentially disabled the call time resets and enforces that it is
the defaults configured with the route itself that determine what is to
be left out. As this is where the reverse mapping is defined, this would
seem the to be correct.
So the question is... is this a bug?
Col
PS I've sent a couple fairly in-depth queries to this list over the last
week or so but have not received any reply. Is this kind of enquiry too
technical for this list? If so, is there a better list I can use (a la
php-internals)?
--
Colin Guthrie
gmane(at)colin.guthr.ie
http://colin.guthr.ie/
Day Job:
Tribalogic Limited [http://www.tribalogic.net/]
Open Source:
Mandriva Linux Contributor [http://www.mandriva.com/]
PulseAudio Hacker [http://www.pulseaudio.org/]
Trac Hacker [http://trac.edgewall.org/]