Routing custom URLs in Zend Framework for dynamic CMS pages

Zend’s standard routing functionality already creates URLs that keep search engines happy, processing the URI request through /controller/view/key/value allowing you to create URLs like:

http://www.awesomesite.com/portfolio/recent/category/artwork

Note this article was created for Zend Framework 1.

If we don’t want to strictly follow the setup of the controller name, Zend Router provides a nice and easy way of adding specific routes which you can read about here.

But what about if we didn’t know what the URL was going to be? I.e. let’s suppose we want to give the site admin the ability to add new pages in a content management system (CMS), where they input the page content in an editor like tinyMCE which then stores all the HTML inside your database. What if for the new pages we want the site admin to be able to choose what the URL is going to be? This would provide them with more flexibility to create slugs that are better for search engine optimisation (SEO) unique to the specific page.

Custom Page Controller

At a very simple level, we could just create a controller that handles custom links, say the ‘pageController’ and give the admin user control over anything after that controller name:

http://www.awesomesite.com/page/whatever/they/want

This can easily be achieved by adding a new route into your bootstrap that tells the routing system that any URLs starting with /page/ should redirect to the pageController and not worry about the rest (achieved with /*)

protected function _initRoutes()
    {
        $custom = new Zend_Controller_Router_Route(
            'page/*',
            array(
                'action'     => 'index',
                'controller' => 'page',
                'module'     => 'site',
            )
        );

        $router->addRoute('custom', $custom);
    }

All we need to do next is create the pageController and inside we can aquire the requested URI via the request object. From there you can use this 'slug' to query your database and find the custom page being requested.

class Site_PageController extends Resources_Controllers_BaseController
{
    public function indexAction()
    {             
        // Get the requested uri
        $request = $this->getRequest();
        $requestedUri = $request->getRequestUri();         
        
        // Query the database for requested uri and pass the page content back to the view         
        // !Replace below with whichever method you use to query your database!
        $pageService = new Service_Page();
        $this->view->page = $pageService->getPageBySlug($requestedUri);      
    } 
}

But ‘Page’ isn’t good for SEO!

Of course, you don’t have to use the word 'page' but still, we’re enforcing part of the URL on the admin user by making them have to use ‘Page’ or whichever word you choose in front of the slug they really want.

So let’s see if we can go one step further and give complete control over everything after the domain...

Register a Plugin

If even the controller doesn't exists (or at least isn't referenced in the URI), then we need to catch the routing system before it throws an error and sends the user to a 404 page. To do this we need to register a plugin in the bootstrap:

protected function _initRoutes()
{
    $this->frontController->registerPlugin(new Resources_Plugins_RoutingCustomPages());
}

Next we create the plugin (note that mine is stored in the library / resources / plugins folder).

class Resources_Plugins_RoutingCustomPages extends \Zend_Controller_Plugin_Abstract 
{ 
    public function preDispatch(\Zend_Controller_Request_Abstract $request) 
    {
        $front = Zend_Controller_Front::getInstance(); 
        $dispatcher = $front->getDispatcher(); 

        if (!$dispatcher->isDispatchable($request)) 
        { 
            $pageService = new Service_Page(); 
            $requestedUri = $request->getRequestUri(); 
            $pageExists = $pageService->checkPageExists($requestedUri); 

            if($pageExists) 
            { 
                $front = Zend_Controller_Front::getInstance(); 
                $request->setControllerName('page') ->setActionName('index'); 
            } 
        }
    } 
}

This is where the magic happens so let’s break this down.

First we get an instance of the front controller and the dispatcher, and then we check if the request that has been made is ‘dispatchable’, i.e. does the controller and view requested actually exist. If it doesn’t then we’re left with one of two scenarios; either it's an invalid url, or it’s one of our custom pages.

So the next step is to check if the page exists. In my instance I use a service layer (Service_Page) which connects to the database, so you can replace this part with however you want to query your database. Essentially we just need to return if the requested slug exists or not. If if does then we simply set the controller to our ‘pageController’ we setup earlier and default to the index view. If the slug doesn’t exist we let the routing fall back to directing to a 404 page.

That’s basically it, all you need to do now is build the functionality into your CMS to allow the admin user to create custom pages and slugs, and pull back the specific page content in the pageController to use in the index view.

 

Sign Up

NEXT: Getting started with Zend 2

This article provides you with an introduction to Zend 2, the changes from Zend 1 and a step-by-step tutorial on creating a hello world module.

comments powered by Disqus
Sign Up

Popular Tags

350x250

Need a web developer?

If you'd like to work with code synthesis on your next project get in touch via the contact page.