1
votes

Last two days I was fighting with Zend Framework Router and still didn't find solution.

Existing project has 2 different modules which work with the same domain e.g. www.domain1.com:

  • default - Contains public information, can be accessed via www.domain1.com
  • admin - Administrator interface, can be accessed via www.domain1.com/admin

Project is multi-langual and to keep language code it is transmitted as first parameter of every URL, e.g. www.domain1.com/en/ www.domain1.com/en/admin

Part of code which takes care is next plugin:

class Foo_Plugin_Language extends Zend_Controller_Plugin_Abstract
{

const LANGUAGE_KEY = 'lang';

 public function routeStartup(Zend_Controller_Request_Abstract $request)
{


    $languagesRegexp = implode('|', array_map('preg_quote', $this->_bootstrap->getLanguages()));

    $routeLang = new Zend_Controller_Router_Route(
        ':' . self::LANGUAGE_KEY,
        array(self::LANGUAGE_KEY => $this->_bootstrap->getLanguage()->toString()),
        array(self::LANGUAGE_KEY => $languagesRegexp)
    );

    $router = $this->getFrontController()->getRouter();

    $router->addDefaultRoutes();

    $chainSeparator = '/';

    foreach ($router->getRoutes() as $name => $route) {

        $chain = new Zend_Controller_Router_Route_Chain();
        $chain
            ->chain($routeLang, $chainSeparator)
            ->chain($route, $chainSeparator);

        $new_name = $this->_formatLanguageRoute($name);

        $router->addRoute($new_name, $chain);
    }

    protected function _formatLanguageRoute($name)
    {
        $suffix = '_' . self::LANGUAGE_KEY;
        if (substr($name, -strlen($suffix)) == $suffix) return $name;
        return $name . '_' . self::LANGUAGE_KEY;
    }

public function routeShutdown(Zend_Controller_Request_Abstract $request)
{
    $lang = $request->getParam(self::LANGUAGE_KEY, null);

    $this->_bootstrap->setLanguage($lang);
    $actual_lang = $this->_bootstrap->getLanguage()->toString();

    $router = $this->getFrontController()->getRouter();
    $router->setGlobalParam(self::LANGUAGE_KEY, $lang);

    // Do not redirect image resize requests OR get js, css files
    if (preg_match('/.*\.(jpg|jpeg|gif|png|bmp|js|css)$/i', $request->getPathInfo())) {
        return true;
    }

    // redirect to appropriate language
    if ($lang != $actual_lang) {

        $redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');

        $params = array(self::LANGUAGE_KEY => $actual_lang);
        $route = $this->_formatLanguageRoute($router->getCurrentRouteName());

        return $redirector->gotoRouteAndExit($params, $route, false);
    }
}

}

One of the first question is what do you think about such way to provide multi-lang support. What I've noticed is that all this chains dramatically decrease operation speed of the server, response time from the server is about 4 seconds...

Main question is: Currently I have to implement such feature: I have domain www.domain2.com that should work just with single module e.g. "foobar"... and it should be available via second url... or, of course, it should work like www.domain1.com/en/foobar by default...

To provide this functionality in Bootstrap class I'be implemented such part of code

// Instantiate default module route
$routeDefault = new Zend_Controller_Router_Route_Module(
    array(),
    $front->getDispatcher(),
    $front->getRequest()
);

$foobarHostname = new Zend_Controller_Router_Route_Hostname(
        'www.domain2.com',
        array(
            'module' => 'foobar'
        )
    );

$router->addRoute("foobarHostname", $foobarHostname->chain($routeDefault));

And that is not working and as I've found routeDefault always rewrite found correct model name "foobar" with value "default"

Then I've implemented default router like this:

new Zend_Controller_Router_Route(
        ':controller/:action/*',
        array(
            'controller' => 'index',
            'action' => 'index'
        );

    );

But that still didn't work, and started work without language only when I comment "routeStartup" method in Foo_Plugin_Language BUT I need language support, I've played a lot with all possible combinations of code and in the end made this to provide language support by default:

class Project_Controller_Router_Route extends Zend_Controller_Router_Route_Module

{ /** * @param string $path * @param bool $partial * @return array */ public function match($path, $partial = false) { $result = array();

    $languageRegexp = '%^\/([a-z]{2})(/.*)%i';

    if (preg_match($languageRegexp, $path, $matches)) {
        $result['lang'] = $matches[1];
        $path = $matches[2];
    }

    $parentMatch = parent::match($path);

    if (is_array($parentMatch)) {
        $result = array_merge($result, $parentMatch);
    }

    return $result;
}

}

So language parameter was carefully extracted from path and regular processed left part as usual...

But when I did next code I was not able to get access to the foobar module via www.domain2.com url, because of module name in request was always "default"

$front = Zend_Controller_Front::getInstance();

    /** @var Zend_Controller_Router_Rewrite $router */
    $router = $front->getRouter();

    $dispatcher = $front->getDispatcher();
    $request = $front->getRequest();
    $routerDefault = new Project_Controller_Router_Route(array(), $dispatcher, $request);

    $router->removeDefaultRoutes();

    $router->addRoute('default', $routerDefault); 

    $foobarHostname = new Zend_Controller_Router_Route_Hostname(
        'www.domain2.com',
        array(
            'module' => 'foobar'
        )
    );

$router->addRoute("foobar", $foobarHostname->chain($routerDefault));

Instead of summary:

  • Problem is that I should implement feature that will provide access for the secondary domain to the specific module of ZendFramework, and I should save multi-language support. And I cannot find a way, how to manage all of this...
  • Secondary question is about performance of chain router, it makes site work very-very slow...
1
Addressing your points: 1. if you configure your vhost to route through to the project, then zend can manage the routing to a module framework.zend.com/manual/1.12/en/… , 2. You could cache the router for performance, memcache will be the fastestEddie Jaoude

1 Answers

0
votes

The way I have solved problem with multilanguage page is in this thread: Working with multilanguage routers in Zend (last post).

Ofcourse my sollution need some caching to do, but I think it will solve your problem.

Cheers.