ZF-12350: Function preDispatch called twice in case of module specific bootstrap
Description
This bug occures while using modular ZF1 structure and module specific Bootstrap class. To reproduce this bug:
- Create empty ZF1 project (I was using ZF Tool) and make it default modular structure.
- Add following settings into application.ini:
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules" resources.modules[] =
- Add to default module empty boostrap class:
<?php
class Default_Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
}
- Create any FrontController Plugin with preDispatch method and add it using application.ini for e.g.:
resources.frontController.plugins.dispatchTest = "Test_Controller_Plugin_DispatchTest"
From now on preDispatch method will be called more than once. This leads to confusion.
To fix this behaviour it's needed to remove module specific Bootstrap.
Expected behaviour:
PreDispatch called only once.
Comments
Posted by Ryan Mauger (bittarman) on 2012-07-27T09:43:59.000+0000
This sounds more like the common problem of not having a favicon.ico, or another missing file which is referenced in the output html (like a link to a stylesheet which is broken).
Could you clarify how you are determining that preDispatch is called twice?
Please also note, that preDispatch will also be called more than once on requests involving the error controller, or any use of _forward in a controller, or if you change the requested controller / action, as all of these methods involve running a second iteration of the dispatch loop.
I'm going to close this issue as preDispatch being called more than once is expected behaviour in many circumstances.
Please provide a clear, reproduce case, and documentation of how you are observing preDispatch being called more than once if you wish to re-open, so that we can rule out all of the legitimate use cases where this is normal behaviour.
Posted by Piotr Deszyński (piteer1) on 2012-07-27T13:45:02.000+0000
I tried this while using curl instead of a browser (so this shouldn't make favicon.ico request). Additionally it's like I wrote: when you remove module specific Bootstrap, everything behaves like it should. There is no _forward call, there is no error either.
I will write again how to reproduce this bug:
<?php class Test_Controller_Plugin_Test extends Zend_Controller_Plugin_Abstract { public function preDispatch(Zend_Controller_Request_Abstract $request) { var_dump('pre dispatch'); } }and put it into file 'library/Test/Controller/Plugin/Test.php'
<?php class Default_Bootstrap extends Zend_Application_Bootstrap_Bootstrap { }and put this code into 'application/modules/default/Bootstrap.php'
Posted by Piotr Deszyński (piteer1) on 2012-07-27T14:00:11.000+0000
Additionally you can change Plugin class to:
<?php class Test_Controller_Plugin_Test extends Zend_Controller_Plugin_Abstract { private static $_preDispatchCalled = 0; public function preDispatch(Zend_Controller_Request_Abstract $request) { self::$_preDispatchCalled++; } public static function getDispatchCalled() { return self::$_preDispatchCalled; } }And run a test:
<?php class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase { public function setUp() { $this->bootstrap = new Zend_Application(APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini'); parent::setUp(); } public function testPreDispatchOnce() { $this->dispatch('/'); $this->assertTrue(Test_Controller_Plugin_Test::getDispatchCalled() === 1); } }This test will fail whether it shoulnd't have
Posted by Ryan Mauger (bittarman) on 2012-07-27T14:22:26.000+0000
Given the steps you outlined, there are no controllers in your new 'default' module, so there would have been a controller not found exception, looping the request to the error controller. try creating application/modules/default/controllers/IndexController.php and in it put:
This should make your test pass (it does for me). Also, this is expected behaviour.
Posted by Ryan Mauger (bittarman) on 2012-07-27T14:36:47.000+0000
Additionally, I've just noticed I did one thing different from you when creating the test, I used Zend_Application_Module_Bootstap as the bootstrap for the 'default' module as it is a module bootstrap the way you have used it. Having two or more Zend_Application_Bootstrap_Bootstrap bootstraps will cause unexpected problems also, as this is not its intended use.
You would save yourself some pain by not having a 'default' module in the modules directory, as this really isn't the way that your application will behave anyway.
Posted by Piotr Deszyński (piteer1) on 2012-07-27T16:05:43.000+0000
Yes, thank you. probably that was the cause. Sorry for the problem.