2

Looking for a better Breadcrumb solution for a Zend Framework project.

Currently I have a navigation.xml like

<?xml version="1.0" encoding="UTF-8"?>
<configdata>
    <nav>
        <home>
            <label>Home</label>
            <module>default</module>
            <controller>index</controller>
            <action>index</action>
            <pages>
                <countryurl>
                    <label>Spain</label>
                    <module>default</module>
                    <controller>country</controller>
                    <action>index</action>
                    <route>country_url</route>
                    <params>
                        <country>spain</country>
                    </params>
                    <pages>
                        <provinceurl>
                            <label>Madrid</label>
                            <module>default</module>
                            <controller>country</controller>
                            <action>province</action>
                            <route>province_url</route>
                            <params>
                                <country>spain</country>
                                <province>madrid</province>
                            </params>
                            <pages>
                                <cityurl>
                                    <label>City</label>
                                    <module>default</module>
                                    <controller>country</controller>
                                    <action>city</action>
                                    <route>city_url</route>
                                    <params>
                                        <country>spain</country>
                                        <province>madrid</province>
                                        <city>madrid</city>
                                    </params>
                                    <pages>
                                        <producturl>
                                            <label>Product</label>
                                            <module>default</module>
                                            <controller>country</controller>
                                            <action>product</action>
                                            <route>product_url</route>
                                            <params>
                                                <country>spain</country>
                                                <province>madrid</province>
                                                <city>madrid</city>
                                                <product>product</product>
                                            </params>
                                        </producturl>
                                    </pages>
                                </cityurl>
                            </pages>
                        </provinceurl>
                    </pages>
                </countryurl>
            </pages>
        </home>
    </nav>
</configdata>

and routes like

$router->addRoute(
    'product_url',
    new Zend_Controller_Router_Route(':lang/:country/:province/:city/:product', array(
        'controller' => 'country',
        'action' => 'product'
    ))
);

$router->addRoute(
    'city_url',
    new Zend_Controller_Router_Route(':lang/:country/:province/:city', array(
        'controller' => 'country',
        'action' => 'city'
    ))
);

$router->addRoute(
    'province_url',
    new Zend_Controller_Router_Route(':lang/:country/:province', array(
        'controller' => 'country',
        'action' => 'province'
    ))
);

$router->addRoute(
    'country_url',
    new Zend_Controller_Router_Route(':lang/:country', array(
        'controller' => 'country',
        'action' => 'index'
    ))
);

I am facing some issues / looking for some suggestions . Creating the Breadcrumbs with the help of Zend_Navigation

$config = new Zend_Config_Xml(APPLICATION_PATH . '/configs/navigation.xml', 'nav');
$container = new Zend_Navigation($config);
$view->navigation($container);

1 ) The request for http://example.com/en/spain/madrid/madrid/product shows the breadcrumb, with the help of

$this->navigation()
    ->breadcrumbs()
    ->setMinDepth(0)
    ->setLinkLast(true)
    ->setSeparator(" > ");

as Home > Spain > Madrid > City > Product

But the links pointing at Spain , Madrid , City all are to http://example.com . Which should be http://example.com/en/spain , http://example.com/en/spain/madrid , http://example.com/en/spain/madrid/madrid respectively.

2 ) Currently when the request for http://example.com/en/spain

the breadcrumb will show Home >> Spain

<label>Spain</label>
<module>default</module>
<controller>country</controller>
<action>index</action>
<route>country_url</route>
<params>
    <country>spain</country>
</params>

But you can see the param country differs according to country. So do we want to add the labels for all countries ?

http://example.com/en/spain

Home >> Spain

http://example.com/en/india

Home >> India

I have provinces , city and product coming along, any suggestions how I can build for it ?

Also this is a multilingual website, so how can we make the necessary changes to the label? I guess if we are using Zend_Translate it will make the necessary changes.

Hari K T
  • 4,174
  • 3
  • 32
  • 51
  • First, seems like you will need dynamic navigation (init in bootstrap, get all your countries, provinces, cities; or if you are using the nav *only* for breadcrumb creation, then you could do later, after `routeShutdown()`, so you can add only the country/province/city path you need). But that still doesn't address your core problem: the nav/breadcrumbs seem to be assembling urls using the wrong route. – David Weinraub Feb 13 '12 at 04:43
  • Thank you David Weinraub, currently I am looking only for the Breadcrumb, and also the Bootstrap.php is a bit different. Its not a class at all, this is really a legacy project written in 1.6 which I just made an upgrade to 1.11 to use Breadcrumb and some stuffs. – Hari K T Feb 13 '12 at 05:00

1 Answers1

0

You can create your own page class that treats params beginning with : as dynamic. You can reference it in the nav configuration like

...
<countryurl>
    <label>:country</label> <!-- dynamic -->
    <module>default</module>
    <controller>index</controller>
    <action>index</action>
    <route>country_url</route>
    <type>DynamicNavPage</type> <!-- page classname -->
    <params>
        <country>:country</country> <!-- dynamic -->
    </params>
        <pages>
    ...

and for example

<?php

class DynamicNavPage extends Zend_Navigation_Page_Mvc {

    /**
    * Params with ":" are read from request
    * 
    * @param array $params
    * @return Zend_Navigation_Page_Mvc
    */
    public function setParams(array $params = null) {
        $requestParams = Zend_Controller_Front::getInstance()
                        ->getRequest()->getParams();

        //searching for dynamic params (begining with :)
        foreach ($params as $paramKey => $param) {
            if (substr($param, 0, 1) == ':' &&
                    array_key_exists(substr($param, 1), $requestParams)) {
                $params[$paramKey] = $requestParams[substr($param, 1)];
            }
        }

        return parent::setParams($params);
    }

    /**
    * If label begining with : manipulate (for example with Zend_Tanslate)
    */
    public function setLabel($label) {
        if (substr($label, 0, 1) == ':') {
            //label modifications go here
            //as an example reading it from page params and capitalizing
            //can use Zend_Translate here
            $requestParams = Zend_Controller_Front::getInstance()
                            ->getRequest()->getParams();
            $labelParamKey = substr($label, 1);

            if (array_key_exists($labelParamKey, $requestParams)) {
                $label = ucfirst($requestParams[$labelParamKey]);
            }
        }

        return parent::setLabel($label);
    }

}
Weltschmerz
  • 2,166
  • 1
  • 15
  • 18
  • Thank you for the answer. I need sometime to test it, busy with different stuffs. I will make it as correct if things work. I feel this should work :) . Thank you once again and for your patience. – Hari K T Feb 21 '12 at 05:43
  • the problem I am facing here is I am not getting the request object so it throws Call to a member function `getParams()` on a non-object . `$requestParams = Zend_Controller_Front::getInstance()->getRequest()->getParams()` . I wonder why its so :( , do you have any insights? The request object is null here `Zend_Controller_Front::getInstance()->getRequest()` – Hari K T Feb 24 '12 at 07:03
  • I don't know your setup, one suggestion is to override router's `route(Zend_Controller_Request_Abstract $request)` method and set what parent route() returns as a static field. That way instead of asking front controller for the request you can do: `MyRouterClass::$routedRequest->getParams();` for example: `public function route(Zend_Controller_Request_Abstract $request){ self::$routedRequest = parent::route($request); return $request; }` Try it. – Weltschmerz Feb 24 '12 at 15:19
  • I was using the same way as quick start, and was using router in Bootstrap . The routes are as http://stackoverflow.com/a/9128784/487878 . I will try out your suggestion . Thanks. – Hari K T Feb 25 '12 at 12:41
  • Alright I understand now, the problem is you're trying to setup request dependent navigation before the routing process is done - probably in the Bootstrap. Right way of doing it is to register a plugin (in the Bootstrap) and setup your navigation is routeShutdow() method. Request object is ready there for sure. My previous comment is wrong, ignore it – Weltschmerz Feb 25 '12 at 16:42