views:

291

answers:

2

I am using both Zend framework and Django, and they both have they strengths and weakness, but they are both good framworks in their own way.

I do want to create a highly modular web application, like this example:

  • modules:
    • Admin
      • cms
        • articles
        • sections
      • ...
        • ...
          • ...

I also want all modules to be self contained with all confid and template files.

I have been looking into a way to solve this is zend the last days, but adding one omer level to the module setup doesn't feel right. I am sure this could be done, but should I? I have also included Doctrine to my zend application that could give me even more problems in my module setup!

When we are talking about Django this is easy to implement (Easy as in concept, not in implementation time or whatever) and a great way to create web apps. But one of the downsides of Django is the web hosing part. There are some web hosts offering Django support, but not that many..

So then I guess the question is what have the most value; rapid modular development versus hosting options!

Well, comments are welcome!

Thanks

+2  A: 

You can implement sub-modules with relatively little effort in ZF. Let's say you have directory structure such as:

application/
  modules/
    admin/
      cms/
        controllers/
        views/
      controllers/
      views/

You'd register the modules like this in your bootstrap (sub-modules use _ to separate the sub-module from the main module):

$frontController->setControllerDirectory(array(
    'default'   => APPLICATION_PATH . '/modules/default/controllers',
    'admin'     => APPLICATION_PATH . '/modules/admin/controllers',
    'admin_cms' => APPLICATION_PATH . '/modules/admin/cms/controllers'
));

The issue with this is that it would actually use an underline in the URL instead of a slash, so eg: "admin_cms/conteroller/action" instead of "admin/cms/controller/action". While this "works", it's not pretty. One way to solve the issue is to provide your own route for the default route. Since the default Zend_Controller_Router_Route_Module does it almost right, you can simply extend from it and add the wanted behavior:

<?php

class App_Router_Route_Module extends Zend_Controller_Router_Route_Module
{
    public function __construct()
    {
     $frontController = Zend_Controller_Front::getInstance();
     $dispatcher = $frontController->getDispatcher();
     $request = $frontController->getRequest();
     parent::__construct(array(), $dispatcher, $request);
    }

    public function match($path)
    {
     // Get front controller instance
     $frontController = Zend_Controller_Front::getInstance();

     // Parse path parts
     $parts = explode('/', $path);

     // Get all registered modules
     $modules = $frontController->getControllerDirectory();

     // Check if we're in default module
     if (count($parts) == 0 || !isset($modules[$parts[0]]))
      array_unshift($parts, $frontController->getDefaultModule());

     // Module name
     $module = $parts[0];

     // While there are more parts to parse
     while (isset($parts[1])) {
      // Construct new module name
      $module .= '_' . $parts[1];

      // If module doesn't exist, stop processing
      if (!isset($modules[$module]))
       break;

      // Replace the parts with the new module name
      array_splice($parts, 0, 2, $module);
     }

     // Put path back together
     $path = implode('/', $parts);

     // Let Zend's module router deal with the rest
     return parent::match($path);
    }
}

And in your bootstrap:

$router = Zend_Controller_Front::getInstance()->getRouter();
$router->addRoute('default', new App_Router_Route_Module);

What this does is traverse the path as long as it finds a module, and transparently rewrites the path so that the default Zend_Controller_Router_Route_Module can do the real work. For example the following path: "/admin/cms/article/edit" will be transformed into "/admin_cms/article/edit", which allows the standard convention of the ZF's ":module/:controller/:action" do the magic.

This allows you to have nice modular structure with self-contained modules, while still use pretty, logical URLs. One thing you want to make note of is that if you use Zend_Navigation and specify the navigation items using module/controller/action parameters, you need to tell ZF how to correctly build the URL using "/" instead of "_" in module names (by default ZF uses the :module/:controller/:action spec when it builds the URLs). You can do this by implementing your own Zend_Controller_Action_Helper_Url, like this:

<?php

class App_Router_Helper_Url extends Zend_Controller_Action_Helper_Url
{
    public function url($urlOptions = array(), $name = null, $reset = false, $encode = false)
    {
     // Replace the _ with / in the module name
     $urlOptions['module'] = str_replace('_', '/', $urlOptions['module']);

     // Let the router do rest of the work
     return $this->getFrontController()->getRouter()->assemble($urlOptions, $name, $reset, $encode);
    }
}

And in your bootstrap:

Zend_Controller_Action_HelperBroker::addHelper(new App_Router_Helper_Url);

Now Zend_Navigation works nicely with your sub-module support as well.

reko_t
Thanks.I do see this as one possible way to solve it, but still i find it a little bit hard to convince myself to use zend because it forces me to write custom code to something that should be a fairly simple task. But this is also what makes Zend a great framework; you are not forced to do things in a spesific way...I am still leaning towards Django, but making this desition is fairly hard..But thanks for the great example
dr. squid
+3  A: 

I (despite of being happy ZF user) would go for Django. In ZF the "fully-modular" application is kind of holly grail. It's nearly impossible (or at least without extreme effort) to create selfcontained modules, instalable like "copy this folder into your modules directory" :) Not sure about Django, but from what I head it's simplier there...

Tomáš Fejfar
Tkanks, this is exactly my impression, too
dr. squid