2

I'm building a multi-site Zend Framework application using modules, sort of in the following structure:

|Project
    |-Application
        |-configs
        |-modules
            |-core
                |-controllers
                |-models
                |-views
                |-Bootstrap.php
            |-site1
                |-controllers
                |-models
                |-views
                |-Bootstrap.php
            |-site2
            |-site3
        |-Bootstrap.php
    |-Docs
    |-Library
    |-Public
    |-.zfproject.xml

Each module extends Core module.

I have the following in my module:

resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
resources.modules[] = ""

What's the best way to Boostrap /application/modules/core/bootstrap.php and /application/modules/xxx/bootstrap.php where 'xxx' is the name of the module being loaded?

I could do it with a check at the top of every single Bootstrap method?

Or, should I be only adding the Module for the site I'm requesting alongside Core, and thus only two Bootstrap.php files would ever be loaded?

EDIT

If I remove the resources.modules[] = "" from my application.ini, and use the following code in my main Bootstrap.php to add a module, it appears to add the Controllers but not actually fire the Bootstrap.php located within the module?

$frontController = $this->getResource('frontController');
$frontController->addControllerDirectory(APPLICATION_PATH . '/modules/site1/controllers', 'site1');
Sjwdavies
  • 4,079
  • 7
  • 38
  • 43
  • See [this post by MWOP](http://mwop.net/blog/234-Module-Bootstraps-in-Zend-Framework-Dos-and-Donts). In particular, note that he recommends front-controller plugins that fire after routing is completed, check for the right module, and bail early otherwise. – David Weinraub Mar 01 '12 at 01:47
  • David, please can you post this as an additional answer to this question? – Sjwdavies Mar 01 '12 at 10:12
  • @Sjwdavies: I'm also in need of core modules which are extended per site , just as your example. How did you do the routing to the correct site folder? – acme Apr 08 '15 at 07:58

3 Answers3

3

See the post by Matthew Weier O'Phinney:

Module Bootstraps in Zend Framework: Do's and Don'ts

In particular, note that he recommends front-controller plugins that fire after routing is completed, check for the right module, and bail early otherwise.

David Weinraub
  • 14,144
  • 4
  • 42
  • 64
  • This absolutely is the best answer. I have, instead, based on the link in your answer, created seperate FrontController plugins - one for each module and they are all included in Bootstrap.ini. These will spearhead the Facade pattern custom loading MWOP speaks of. I like this quote in particular from that post `To re-iterate: if you have initialization tasks that should only be done if the module is the one being executed, do it in a front controller plugin or action helper.`! – Sjwdavies Mar 02 '12 at 16:52
  • Yep, that post helped me a lot with my module-based apps. Thanks. – David Weinraub Mar 02 '12 at 17:38
  • ...and the post is gone. This is why it really isn't a good idea to just link to another page, put the answer here in SO for posterity. – Chris Matta Dec 19 '13 at 17:17
  • That's why I added the general upshot - use front-controller plugins that fire after bootstrap. But your point is well taken. A more detailed summary would have been better. Updated the link which I found with a Google search. – David Weinraub Dec 20 '13 at 16:30
1

The purpose of the bootstrap is to initialise the application. So all module bootstraps will always be initialised on every request, along with the main application one. If you want to perform an operation depending on the module that was loaded the easiest way to do this is in a controller plugin. Inside the plugin you can check to see what the current module is and then run what you need to.

Alternatively, instead of adding the resources.modules[] = "" line in the config (which will automatically scan the modules directory adding all modules), you could manually add individual modules in the application bootstrap. This would allow you do add just the core one and the path related to whichever site is being viewed. I'm not sure if this is a good fit for what modules were designed for though.

You need to fire the module bootstraps manually as well:

require_once APPLICATION_PATH.'/modules/site1/Bootstrap.php';
$className = 'Site1_Bootstrap';
$moduleBootstrap = new $className($this);
$moduleBootstrap->bootstrap();
Tim Fountain
  • 33,093
  • 5
  • 41
  • 69
  • Thanks Tim. One of the reasons for using this is to check if a user is logged in. I considered the idea of using a Controller Plugin but thought it might be best for future-proofing to only load the relevant bootstrap files and move this method here. – Sjwdavies Feb 29 '12 at 16:57
  • Checking if the user is logged in definitely sounds like it would be better in a controller plugin than the bootstrap. In a plugin you can change the request params (to send the user to a login page for example). – Tim Fountain Feb 29 '12 at 17:09
  • Updated my answer with some code for the module bootstraps as well. – Tim Fountain Feb 29 '12 at 17:12
  • Thanks Tim. I've created a 'Check If Module/Class/Action' exists plugin that does similar to set the Request and Dispatch module values to the appropriate modules if the requested module/controller/action doesn't exist. I think on this occasion I may be best using a Controller Plugin. However, I'd still like to be able to specify a single module in application.ini, then load the module bootstrap thats required.. – Sjwdavies Feb 29 '12 at 17:16
  • Thanks Tim. I employed your script in an _initFrontModules() method in my Bootstrap.php. I feel dirty using the Bootstrapper in this way TBH. Also, a point to note is that using the above method fires the 'sub-loaded' module Bootstrap.php before the main `application/bootstrap.php` – Sjwdavies Feb 29 '12 at 17:26
0
protected function _initAutoload(){

    $front = Zend_Controller_Front::getInstance();
    $front->setControllerDirectory(array( 'Default' => APPLICATION_PATH.'/modules/default/controllers', 'Other' => APPLICATION_PATH.'/modules/other/controllers' ));
    $front->setParam('useDefaultControllerAlways', true);
    $modules = $front->getControllerDirectory();
    $default = $front->getDefaultModule();

    $router = new Zend_Controller_Router_Rewrite();
    $request =  new Zend_Controller_Request_Http();
    $router->route($request);
    $current_module = ucfirst($request->getModuleName());

    foreach (array_keys($modules) as $module) {

        if ($module == $current_module) {
            $modelLoader = new Zend_Application_Module_Autoloader(array( 'namespace' => $module, 'basePath'  => $front->getModuleDirectory($module)));

            require_once $front->getModuleDirectory($module).'/Bootstrap.php';
            $className = $module.'_Bootstrap';
            $moduleBootstrap = new $className($this);
            $moduleBootstrap->bootstrap();
        }
    }

    return $modelLoader;
}
KhaliD
  • 1