phpzend-frameworkrouteszend-controller-router

Zend Framework Router dynamic routes


I bumped into a problem and I can't seem to find a good solution to make it work. I have to make some dynamic routes into a Zend Framework project. I'll explain shortly what my problem is:

I need to have dynamic custom routes that "extend" the default route (module/controller/action/params). The project I'm working for has several partners and the routes have to work with those. To store the partners I've made a static class and it looks like this.

<?php
    class App_Partner
    {
        static public $partners = array(
            array(
                'name' => 'partner1',
                'picture' => 'partner1.jpg'
            ),
            array(
                'name' => 'partner2',
                'picture' => 'partner2.jpg'
            ),
            array(
                'name' => 'partner3',
                'picture' => 'partner3.jpg'
            )
        );
        static public function routePartners() {
            $partners = array();

            foreach(self::$partners as $partner) {
                array_push($partners, strtolower($partner['name']));
            }
            $regex = '(' . implode('|', $partners) . ')';

            return $regex;
        }
    }

So App_Partner::routePartners() return me a string like (partner1|partner2|partner3) which I use to create the right routes. My goal is to have the custom routes for each partner for every route I have set in the Bootstrap. So if I have a route add-product.html set I want it to work for each partner as partner1/add-product.html, partner2/add-product.html and partner3/add-product.html. Also, partner1/, partner2/, partner3 should route to default/index/index.

In fact, I made this thing to work using routes like the one below.

<?php
$routeProposal = new Zend_Controller_Router_Route_Regex(
    App_Partner::routePartners() . '?/?proposals.html',
    array(
        'module' => 'default',
        'controller' => 'proposal',
        'action' => 'index',
        'page' => 1
    ),
    array( 1 => 'partner'),
    "%s/proposals.html"
);
$router->addRoute('proposal', $routeProposal);

The problem

The above route works fine if I use a partner in the request URI, but if I don't, I get double slashes like public//proposals.html because of the reverse route set in the route above to be "%s/proposals.html". I can't seem to find a way to avoid this reverse route because I build my urls using the url view helper and if the reverse route isn't set I get an exception stating this.

I also need the routes to work without a partner set, which will be the default way (add-product.html, proposals.html etc).


Solution

  • From your description, it seems like you're looking for a zend router chain, where your partner is an optional chain.

    Here's a similar question, but using a hostname route : Zend Framework: get subdomain parameter from route. I adapted it to solve your problem, just put the following in your Bootstrap.php to initialize the routing :

    protected function _initRoute()
    {
        $this->bootstrap('FrontController');
        $router = $this->getResource('FrontController')->getRouter();
    
        // Default route
        $router->removeDefaultRoutes();
        $defaultRoute = new Zend_Controller_Router_Route(
                        ':controller/:action/*',
                        array(
                            'module' => 'default',
                            'controller' => 'index',
                            'action' => 'index',
                        )
        );
        $router->addRoute('default', $defaultRoute);
    
        $partnerRoute = new Zend_Controller_Router_Route(
            ':partner',
            array('partner' => 'none'),
            array('partner' => '^(partner1|partner2|partner3)$')
        );
        $router->addRoute('partner', $partnerRoute->chain($defaultRoute));
    }
    

    Change as you see fit. In your controllers you will only get a value for the partner parameter if it was actually specified AND valid (you will get a routing error if the partner doesn't exist)...