Zend Framework - modular layout questions

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Zend Framework - modular layout questions

Post by Luke »

I have set up my Zend Framework application in such a way that (according to the Zend Framework manual) allows for modularity. What I mean by this is that my application can be split up into directories containing modules that each do something related to my application. Supposedly if you have a blog, a sales management console, and an admin system, your directory structure would look something like:

Code: Select all

/myapp
    /default (module)
        /controllers
        /models
        /views
            /filters
            /helpers
            /scripts
    /blog (module)
        /controllers
        /models
        /views
            /filters
            /helpers
            /scripts
    /sales (module)
        /controllers
        /models
        /views
            /filters
            /helpers
            /scripts
    /admin (module)
        /controllers
        /models
        /views
            /filters
            /helpers
            /scripts
The problem is that generally my view helpers are going to be (for the most part) all in one central directory. Only when there is some specific functionality that could only possibly EVER be needed within a certain module would I put it in that specific module's /views/helpers/ directory. The same goes for a lot of the actual templates and filters, along with possibly models, just about everything. Is there some sort of convention on how to assemble a modular directory structure so that all of this stuff can be shared? The manual is pretty vague on this subject... at least what I've found on it.
Begby
Forum Regular
Posts: 575
Joined: Wed Dec 13, 2006 10:28 am

Post by Begby »

It is pretty flexible. You can play with the view object and the view renderer helper in your bootstrap to get it how you want it.

Key methods for the view are setScriptPath(), setFilterPath() and setHelperPath() (they all have an add equivelant as well).

For the ViewRenderer check out setViewScriptPathSpec().


My structure looks like this

Code: Select all

/controllers
 /clients
   ManageController.php
 /system
  AuthController.php
  someOtherSystemsController.php
 /default
  defaultController.php
  errorController.php

/views
 /_helpers
 /_filters
 /_layouts
 /clients
   /manage
    form.phtml
    index.phtml
 /default
  /error
    error.phtml
  /index
   index.html

etc. etc.
Begby
Forum Regular
Posts: 575
Joined: Wed Dec 13, 2006 10:28 am

Post by Begby »

Here are the relevant portions of my bootstrap. I am using an extended view class, but it uses Zend_View as the base so it should apply to yours except for the setLayout() method.

Code: Select all

/**
	 * Setup the view and view renderer
	 */
	$view = new zFCP_View_Layout() ;
	$view
		->setLayout('main.phtml')
		->strictVars((bool) $config->bootstrap->strictviewvars) 
		->setScriptPath(APPLICATION_ROOT.DIRECTORY_SEPARATOR.'app_admin/views/_layouts') 
		->addScriptPath(APPLICATION_ROOT.DIRECTORY_SEPARATOR.'app_admin/views')
		->setFilterPath(APPLICATION_ROOT.DIRECTORY_SEPARATOR.'app_admin/views/_filters') 
		->setHelperPath(APPLICATION_ROOT.DIRECTORY_SEPARATOR.'app_admin/views/_helpers', 'FCP_View_Helper_');
	
	$renderer = new Zend_Controller_Action_Helper_ViewRenderer( $view ) ;
	$renderer->setViewScriptPathSpec(':module/:controller/:action.:suffix') ;
	Zend_Controller_Action_HelperBroker::addHelper($renderer);
	
	/**
	 * Configure and run the front cotroller
	 */
	$front = Zend_Controller_Front::getInstance() ;
	
	$front
		->setParam							( 'registry', Zend_Registry::getInstance() )
		->throwExceptions					( (bool) $config->bootstrap->throwexceptions )
		->setBaseUrl						( FCP_BASE_URL )
		->setModuleControllerDirectoryName	( '' )
		// This plugin handles login authentication
		->registerPlugin					( new zFCP_Controller_Plugin_AdminAuth(zFCP_Auth::getInstance()) )
		->addModuleDirectory				( APPLICATION_ROOT.$config->bootstrap->modulepath ) ;
	
	$front->dispatch() ;
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

I'm having some trouble here. I changed my directory to look like this:

Code: Select all

/app
    /models
    /modules
        /default
            IndexController.php
            ErrorController.php
        /vendors
            IndexController.php
    /views
        /_elements (basically the same as your layout dir)
        /_filters
        /_helpers
        /default
            /index
                index.phtml
            /error
                error.phtml
        /vendors
    config.php
Then the relevant bootstrap code:

Code: Select all

/**
         * Now we set up the front controller to accept multiple modules. This is 
         * a modular front controller set up.
         */
        $front->addModuleDirectory(MC2_Bag::getBaseDir() . DS . 'modules');
        $front->setModuleControllerDirectoryName('controllers');
        
        // @todo: find out what this actually does and possibly just enable it when debug is on
        $front->throwExceptions( (bool) $config->throwexceptions );

        $this->view->setScriptPath(MC2_Bag::getBaseDir() . DS . 'views/')
                   ->addScriptPath(MC2_Bag::getBaseDir() . DS . 'views/_elements')
                   ->setHelperPath(MC2_Bag::getBaseDir() . DS . 'views/_helpers')
                   ->setFilterPath(MC2_Bag::getBaseDir() . DS . 'views/_filters');
It keeps giving me errors like this:
Fatal error: Uncaught exception 'Zend_View_Exception' with message 'script 'index/index.phtml' not found in path (C:\htdocs\bagselect\po\app\views\_elements\;C:\htdocs\bagselect\po\app\views\)' in C:\htdocs\bagselect\po\library\Zend\View\Abstract.php:856 Stack trace: #0 C:\htdocs\bagselect\po\library\Zend\View\Abstract.php(764): Zend_View_Abstract->_script('index/index.pht...') #1 C:\htdocs\bagselect\po\library\Zend\Controller\Action\Helper\ViewRenderer.php(742): Zend_View_Abstract->render('index/index.pht...') #2 C:\htdocs\bagselect\po\library\Zend\Controller\Action\Helper\ViewRenderer.php(763): Zend_Controller_Action_Helper_ViewRenderer->renderScript('index/index.pht...', NULL) #3 C:\htdocs\bagselect\po\library\Zend\Controller\Action\Helper\ViewRenderer.php(810): Zend_Controller_Action_Helper_ViewRenderer->render() #4 C:\htdocs\bagselect\po\library\Zend\Controller\Action\HelperBroker.php(160): Zend_Controller_Action_Helper_ViewRenderer->postDispatch() #5 C:\htdocs\bagselect\po\library\Zend\Controller\Action.php(504): Ze in C:\htdocs\bagselect\po\library\Zend\View\Abstract.php on line 856
It seems as though I am unable to get it to recognize my module paths correctly. What am I doing wrong? :(
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

In your directory tree you don't have 'controllers' directories in each module.

ZF has grown one ugly, tacked on module system...
(#10850)
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

I just added a controllers directory to each and dropped the controllers into them. It says the same thing. Nothing I'm doing seems to work. Are there bugs in the module system or something? This is lame. :(
Begby
Forum Regular
Posts: 575
Joined: Wed Dec 13, 2006 10:28 am

Post by Begby »

make the moduleControllersDirectoryName be '' like in my example
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

OK, well it seems to be finding my controllers now, but it can't seem to find the views. (index/index.html doesn't exist)

If I add views/default to the view script path, it works fine, but only for the default module. Why can't it find the right module's files?
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Post by Maugrim_The_Reaper »

Hi Ninja,

You need to do two things:

1. Configure a custom Zend_View instance for your common paths (only the common ones!)
2. Configure the ViewRenderer Action helper for the location of Module specific templates/helpers/filters

You almost have the first right - but you probably only need to "addScriptPath()" for _Elements. Adding a Module specific script path in the bootstrap won't help unless you add all Modules, and that of course is going to result in template name collisions down the line.

The trick is in 2. - configure the ViewRenderer to dynamically add a Module's view directory at runtime. Something like what Begby suggested is pretty standard:

Code: Select all

require_once 'Zend/View.php';
require_once 'Zend/Controller/Action/HelperBroker.php';
require_once 'Zend/Controller/Action/Helper/ViewRenderer.php';

$view = new Zend_View;
// add common directories for all Views; always "add", never "set"
$this->view->addScriptPath(MC2_Bag::getBaseDir() . DS . 'views/_elements')
           ->addHelperPath(MC2_Bag::getBaseDir() . DS . 'views/_helpers')
           ->addFilterPath(MC2_Bag::getBaseDir() . DS . 'views/_filters');

$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer;
$viewRenderer->setView($view);

// set the Module specific ScriptPath syntax; The Module name is substituted and add to
// as an additional View ScriptPath when a Controller is executed
$viewRenderer->setViewBasePathSpec(MC2_Bag::getBaseDir() . DS . 'views/:moduleDir');

Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
I can't test this right now, but this should be workable. It's unavoidable that ViewRenderer will also add extra Module specific filter/helper locations based on the ViewBasePathSpec - I don't think this causes a problem really, and if it does you can subclass ViewRenderer's initView() method to fix fairly simply.
Begby
Forum Regular
Posts: 575
Joined: Wed Dec 13, 2006 10:28 am

Post by Begby »

I think someone needs to rewrite the zend view/module stuff. It's total <span style='color:blue' title='I&#39;m naughty, are you naughty?'>smurf</span> that it is so hard to configure and setup custom modules and stuff. I spent days trying to get my bootstrap as above then several more days to extend the view to do layouts.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Maugrim had a go recently at trying to get them to clean the View up. Ask him about his experiences ...
(#10850)
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Post by Maugrim_The_Reaper »

You can disable ViewRenderer. A lot of folk are doing that and reverting back to controlling View with a more hands-on approach that makes no assumptions. The current system is here to stay though - I've managed to get most of my Zend_View Enhanced proposals accepted apart from layouts which will use Zend_Layout (and ViewRenderer).

The bootstrap is so much bigger than I remember from ZF 0.6 ;). Those were the simple days...
wei
Forum Contributor
Posts: 140
Joined: Wed Jul 12, 2006 12:18 am

Post by wei »

i think it may be a case of "http://en.wikipedia.org/wiki/Design_by_committee", frameworks should be designed under a dictatorship
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

For some reason I'm having issues with the module layout again. The only way to get it to work was to define the default directory explicitly. I don't want to define all modules explicitly. Here is the relevant code. If I uncomment the commented lines, it doesn't work anymore.

Code: Select all

/**
         * Now we set up the front controller to accept multiple modules. This is 
         * a modular front controller set up.
         */
        $front->addControllerDirectory(self::getBaseDir() . DS . 'modules' . DS . 'default', 'default');
        //$front->addModuleDirectory(self::getBaseDir() . DS . 'modules');
        //$front->setModuleControllerDirectoryName('');

        $front->dispatch();
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

switching the order of the two method calls fixed the problem... :? :roll:
Post Reply