Creating canonical URLs with custom route-classes
I'm trying to implement canonical 开发者_高级运维URLs and combine it with custom route-classes.
The URL-scheme is something like this:
/category-x/article/123
/category-y/article/123
I create a custom route-class extending Zend_Controller_Router_Route_Regex
and checks that the article 123 exists and that the URL includes the correct category-name. If article 123 belongs in category-x and the user is accessing category-y I want to redirect to the correct URL.
But the routes does not have any obvious possibility to do this directly. What's the best practice approach here?
I often do this in my action controller. Something like this...
// assuming GET /category-y/article/123
// $article->url is generated, and contains /category-x/article/123
if (this->_request->getRequestUri() != $article->url) {
return $this->_helper->redirector->goToUrl($article->url);
}
In this example, $article->url would need to be generated from your database data. I often use this to verify a correct slug, when I also pull in the object id.
You could also potentially move this to your routing class, if you wanted to use a custom one instead of using Regex (you could subclass it).
I ended up with this solution:
The custom route-class creates the canonical URL in its match()-method like this:
public function match($path, $partial = false) { $match = parent::match($path, $partial); if (!empty($match)) { $article = $this->backend->getArticle($match['articleId']); if (!$article) { throw new Zend_Controller_Router_Exception('Article does not exist', 404); } $match['canonicalUrl'] = $this->assemble(array( 'title' => $article->getTitle(), 'articleId' => $article->getId() )); } return $match; }
$article is populated inside match() if the parent::match() returns array.
I've created a front controller plugin which hooks on the routeShutdown() like this:
public function routeShutdown(Zend_Controller_Request_Abstract $request) { if ($request->has('canonicalUrl')){ $canonicalUrl = $request->getBaseUrl() . '/' . $request->get('canonicalUrl'); if ($canonicalUrl != $request->getRequestUri()) { $this->getResponse()->setRedirect($canonicalUrl, 301); } } }
It simply checks if the route(custom or native Zend) created a canonical URL and if the requested URL does not match, redirect to the correct canonical URL.
精彩评论