Working with prefixes and Zend_Controller_Router_Route
Asked Answered
G

2

14

On an existing Zend Framework website with few controllers and no modules I need to add some prefixes to the default routes.

For example, I currently have :

/products
/products/id/1
/training
/commonpage

I want to add a product line level, without duplicating my controllers in x modules (I'll just request the right product line inside my controllers with _getParam ).

So my new paths will be :

/line1/products
/line1/products/id/1
/line2/training
/commonpage

What I tried so far is this route (located in my Bootstrap file) :

protected function _initRoutes()
{
    $router = Zend_Controller_Front::getInstance()->getRouter();
    $router->addRoute('productLineRoute', new Zend_Controller_Router_Route(
        ':line/:controller/:action',
        array('module' => 'default'),
        array('line' => '(' . implode('|', Zend_Registry::getInstance()->constants->lines) . ')')
    ));
}

But without any success (it gives me a 404). How can I build a single route that match all uri under those conditions :

  • The prefix of the uri match a value in my product lines array
  • The route is valid only if the controller requested is allowed to be accessed in a "product line way" - by an array containing the names of my controllers for example

UPDATE

Ok I managed to get really close of what I'm trying to do with this code :

protected function _initConstants()
{
    $registry = Zend_Registry::getInstance();
    $registry->constants = new Zend_Config( $this->getApplication()->getOption('constants') );
    $uri = ltrim($_SERVER['REQUEST_URI'], '/');
    $product_line = substr($uri, 0, strpos($uri, '/'));
    if(!empty($product_line) && in_array($product_line, Zend_Registry::getInstance()->constants->lines->toArray()) &&
       $product_line != Zend_Registry::getInstance()->constants->lines->get(0)) {
        $registry->product_line = $product_line;
    } elseif(!isset($registry->gamme)) {
        $registry->product_line = Zend_Registry::getInstance()->constants->lines->get(0);
    }
}

protected function _initRoutes()
{
    $router = Zend_Controller_Front::getInstance()->getRouter();
    $registry = Zend_Registry::getInstance();
    $router->addRoute('productLineRoute', new Zend_Controller_Router_Route(
        ':line/:controller/:action/*',
        array(
            'module' => 'default', 'action' => 'index',
            'line'  => (isset($registry->product_line)) ? $registry->product_line : Zend_Registry::getInstance()->constants->lines->get(0)
        ),
        array(
            'line'      => '(' . implode('|', Zend_Registry::getInstance()->constants->lines->toArray()) . ')',
            'controller' => '(' . implode('|', array('products', 'training')) . ')'
        )
    ));
}

With that I can access /line1/products but not /line1/commonpage, which is what I want - so the controller constraint is working great. As you can see I add the product line name in the Zend Registry, so it is saved when I use the URL View Helper in templates (that way I don't have to edit all my templates to add the product line parameter in my helper calls).

The problem I have now is about this helper : it seems that my controller constraint is just get ignored. When I do this in my template:

<a href="<?php echo $this->url(array('controller'=> 'commonpage', 'action'=>'index'),null, true) ; ?>">My link</a>

I end up with this :

<a href="/line1/commonpage">My link</a>

So the product line is added, despite of the fact that this is not allowed by the controller constraint of my route.

Galba answered 5/5, 2015 at 10:3 Comment(3)
One route to rule em all is deprecated. It is not so hard to google few articles why routing in zf2 as zf1 successor changed. Long story short - do for every controller its own route.Oeo
@Oeo Did you read the updated part of the question?Galba
@Oeo And "It is not so hard to google few articles", why being aggressive like that? What's the point? Guess what I just tried "routing zend framework 2 vs zend framework 1" in Google and didn't find anything relevant.Galba
G
1

Ok I found a solution : I changed the URL Helper to add the controller constraint inside it. If the controller doesn't match the "product lines controllers" array, it force assemble to use the default route (not perfect, but it works for me):

public function url(array $urlOptions = array(), $name = null, $reset = false, $encode = true, $default = false)
    {
        $router = Zend_Controller_Front::getInstance()->getRouter();
        if(isset($urlOptions['controller']) && !in_array($urlOptions['controller'], array('products', 'training'))) {
            $name = 'default';
        }
        return $router->assemble($urlOptions, $name, $reset, $encode);
    }
Galba answered 17/6, 2015 at 9:27 Comment(0)
S
0

you can add / modify specific route with ini params file :

resources.router.routes.job_en.route               = "/prefix/:request-offer"
resources.router.routes.job_en.defaults.module     = "core"
resources.router.routes.job_en.defaults.controller = "engine"
resources.router.routes.job_en.defaults.action     = "main"

where job_en is the name of my route and request-offer the param name

Surely answered 5/5, 2015 at 10:41 Comment(3)
It works but what I'm trying to achieve is to have one route to route them all ;) I can of course write one route per controller + action, but I would have to do like 100 routes, and will probably forget some specific routes with parameters. I'm sure there should be a better way to handle prefixes.Galba
In this case, the simpliest is to use the regexp router Zend_Controller_Router_Route_Regex framework.zend.com/manual/1.12/en/… and in your config file specify type of router: resources.router.routes.job_en.type = "Zend_Controller_Router_Route_Regex" resources.router.routes.job_en.route = "/?([a-zA-Z0-9_-]+)?/?([a-zA-Z0-9_-]+)?/?([a-zA-Z0-9_-]+)?/?([a-zA-Z0-9_-]+)?"Surely
I finally get it work with Zend_Controller_Router_Route (see updated question), the problem I have now is with the URL View Helper.Galba

© 2022 - 2024 — McMap. All rights reserved.