views:

121

answers:

1

I'm trying to match URLs without a trailing slash to one router and want those with the trailing slash behave the normal way. I've tried:

$route = new Zend_Controller_Router_Route(
      ':redirectid',
      array(
       'redirectid' => false,
       'controller' => 'redirect',
       'action' => 'redirect'
      ),
      array('redirectid' => '[a-z0-9]*')
     );

and

$route = new Zend_Controller_Router_Route_Regex(
      '([a-z0-9]*)',
      array(
       'controller' => 'redirect',
       'action'     => 'redirect'
      )
     );

and both behave exactly how I want for urls without trailing slash, yet they still match for urls with a trailing slash, too. Is there any way around this?

+2  A: 

DISCLAIMER: I would highly suggest against making http://somesite.com/page and http://somesite.com/page/ being different pages- it will become confusing for you and for your visitors.

If you're truly dedicated to this plan you can create your own router you can that handles this by creating your own match() and assemble() functions that don't trim() the path based on trailing slashes.

class My_Route_Redirector implements Zend_Controller_Router_Route_Interface {
   protected $_defaults;

   public static function getInstance(Zend_Config $config) {
     $defs = ($config->defaults instanceof Zend_Config) ? $config->defaults->toArray() : array();
     return new self($defs);
   }

   public function __construct($defaults=array()) {
     $this->_defaults = $defaults;
   }

   public function match($path, $partial = false) {
     if (preg_match("#^/?([a-z0-9]+)$#i", $path, $matches)) {
       // this is just an idea but what about if you had this test
       // $matches[1] versus the database of redirectors?  and only return true
       // when it found a valid redirector?

       return array('redirectid' => $matches[1]) + $this->_defaults;
     } else {
       return false;
     }
   }

    public function assemble($data = array(), $reset = false, $encode = false, $partial = false)
    {
      if (!isset($data['redirectid'])) return '';
      return $data['redirectid'];
    }
}

That was air coded so it may have a bug or two to work out - it should work like this:

$route = new My_Route_Redirector(
                array(
                        'controller' => 'redirect',
                        'action'     => 'redirect'
                )
        );
gnarf
+1 for the "don't do it" advice
Pascal MARTIN
Thank you very much! It's working fine, except that the $path still includes the beginning /, "#^/([a-z0-9]+)$#i" makes it work. I actually do fight with myself over the do it/don't it - it's for a tinyurl-like redirector and I didn't just want to match everything, so I can still have /admin/ or /stats/ etc. Having specific routes for those might be preferable, I'll have to sleep over that one.
Dominik
You could just fall down to /admin/index/ for your basic :controller/:action route right?
gnarf
Yeah, that's what I ended up doing - basically I route those routes that I need with just one parameter (/admin/) with a static route, those with more than one (/admin/options/) will use the adminController anyway.
Dominik
I just had an idea looking at this again - you could have this custom route only return the values when it finds something that matches against your DB rows - It could even set the "redirectTo" param. Then /admin would still be a "default" route - and you wouldn't need special case statics.
gnarf
Hm, I like that idea - even though it would take out all the logic out of the redirectController, after all, if I query the db anyway, I could just redirect right there in the router.
Dominik