I have a CMS where the admin builds its own recursive page structure. Every page has its own "url-key". Next the url-key is used in combination with the page structure to build the URL structure so you get the following structure:
{rootpage url-key}/{subpage url-key}
Optionally, multilanguage supporst is on and you also get a language prefix:
{language code}/{rootpage url-key}/{subpage url-key}
I almost got the above working by providing each page with its own static route and then chaining them together.
/**
* Initializes the sites navigation.
*
* @param array $pages An array with the cms pages to initialize
*/
protected function _initNavigation(array $pages = null)
{
$root = true;
if ($pages === null) {
$pages = Sjr_App::get()->getModel('page')->getTree();
$root = true;
}
$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter();
foreach ($pages as $page) {
$router->addRoute($page->getRouteName(), $page->getRoute());
if ($page->children) {
$this->_initNavigation($page->children);
}
}
}
$page->getRoute():
/**
* Gets the routing for the page.
*
* @return Zend_Controller_Router_Route_Abstract
*/
public function getRoute()
{
if ($this->_route === null) {
$this->_route = new Zend_Controller_Router_Route_Static($this->url_key,
$this->getNavigationData()
);
if ($this->parent) {
$parentRoute = $this->parent->getRoute();
$this->_route = $parentRoute->chain($this->_route);
}
}
return $this->_route;
}
Next, if multilanguage is supported, i prepend all the routes with the language route:
foreach ($front->getRouter()->getRoutes() as $routeName => $route) {
if ($routeName != 'lang') {
$front->getRouter()->addRoute($routeName, $this->_languageRoute->chain($route));
}
}
All the routes are assembled correctly. But once a page has and/or is a child the routes arent matched.
But aside from it not working yet, im also wondering if this is the best approach. The page structure could get pretty big, meaning it would also create alot of route objects. I'm not sure what effect this has on performance.
Alternatively i was thinking about writing a custom router/route to handle all the cms-routes in 1 route. This would also make it easier to assemble cms-urls.
I hope someone can give me some advice on this issue.
I think your approach should work (in principle). One thing that bit me when I was working on something similar was that you can't use route chains as a 'tree', where you have one top level route with multiple route options under it.
So if you have:
these need to be three completely separate routes. You can't have one route object for /something which you reuse by adding /foo and /bar to, expecting the router to be able to work out which one to use. If your $this->parent method is reusing pages this might be where your problem is.
However, I think you are right to wonder whether this is the best approach. It should work for small sites, but as routes are checked in a loop until a match is found, if a site had 10,000 pages then this would be a pretty slow routing process, and the router would be doing a lot of repetitive tasks.
An alternative would be to use a custom route class which is able to check the relevant route part against the keys in the database. This way you should be able to do it all with just one route, which would be considerably faster.
I put up a blog post a while back with some code examples of how do vanity URLs in this way, so although this is a different problem the solution is the same (custom route class), so it might point you in the right direction.