Zend Framework 1.9 addModuleDirectory not working? - zend-framework

Ok, I'm frustrated beyond words!
I have a ZF 1.9 application. The following is in my bootstrap.php:
$front = Zend_Controller_Front::getInstance();
$front->addModuleDirectory(dirname(__FILE__).'/modules');
I've put some trace code into the ZF library files, and I can see the call to addModuleDirectory and the subsequent internal call to addControllerDirectory - it's got the right values for the module name and the path. If I dump the internal _controllerDirectory variable (this is all in Library/Controller/Dispatcher/Standard.php, by the way), I can see my module directory.
The next thing my trace shows is that the default controller directory is added for the default controller - perfect.
However, on the next call to dispatch(), I'm again dumping the _controllerDirectory variable and it's only got the default module's controller directory. WTF? I have the trace going to a file... here it is (commented by me):
-- first call, triggered by addModuleDirectory():
Adding 13:09:08
Module itemquestion
Path /Users/don/Documents/Aptana Studio Workspace/cahoots2/application/modules/itemquestion/controllers
-- You can see my dir is in here...
_controllerDirectory contains: 13:09:08
/Users/don/Documents/Aptana Studio Workspace/cahoots2/application/modules/itemquestion/controllers
-- second call, triggered internally by ZF:
Adding 13:09:08
Module default
Path /Users/don/Documents/Aptana Studio Workspace/cahoots2/application/controllers
-- Where's my directory????
_controllerDirectory contains: 13:09:08
/Users/don/Documents/Aptana Studio Workspace/cahoots2/application/controllers
What in the world am I doing wrong? Why can't I get my module's directory to stay persistent?
EDIT: Some additional detail. I added a second module to the /modules folder. Now, I can see the first module being added and showing up in the _controllerDirectory variable. Then, I can see the second added, and see BOTH of them in the variable. Then I see the default module added and after that call, it's the only thing in _controllerDirectory.

Okay, it seems the solution is to add this to the application.ini:
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
Which is kinda unintuitive and at the very least not even remotely documented in the ZF reference manual. Oy. But this seems to have solved the problem.

Well I think it depends on what part you put it on the bootstrap, because, if you put it before the Application Resource Controller then it may overwrite. To make sure the front controller is bootstrapped you can use something like this:
protected function _initFrontModules() {
$this->bootstrap('frontController');
$front = $this->getResource('frontController');
$front->addModuleDirectory('path/to/modules');
}
If you omit the bootstrap line it may execute first your method and then overwrite it with the one from the plugin.

Related

Magento - Error after disabling modules

I've disabled the Rss and Newsletter modules of my Magento 1.7 instance following the instructions of this post:
http://inchoo.net/ecommerce/magento/how-to-fully-disable-turn-off-magento-module/comment-page-1/#comment-65853
I just edited the app\etc\modules\Mage_All.xml file by changing to <active>false</active> in both Mage_Rss and Mage_Newsletter modules.
The problem is that when I try to load a customer page through admin panel, I get the following error:
Fatal error: Call to a member function loadByCustomer() on a
non-object in app\code\core\Mage\Newsletter\Model\Subscriber.php on
line 267
Why is it happening? Why is this code being executing even though I've disabled such module?
Thanks!
First step after disabling a module through its <active> entry. Always clear cache and if you use the compiler, recompile so you don't have code referencing classes in the disabled module.
Often the problem is not with code executing after the module is shut off through the app/etc/modules/mod_name.xml by setting <active> to false, but with other modules, templates or layouts attempting to call code in the disabled module.
Where issues come in are if another module lists the module just turned off in its dependency list. Always check all the other module xml files dependency lists for mention of the module you are deactivating.
Also, you have to check for template .phtml files that reference classes in the disabled module. This can throw the dreaded call to a non-object type exception errors. As an example, one module that provides custom cart attributes asks you to add entries to your cart templates. Shutting off the module does not get rid of the references.
Make sure no layouts are attempting to load anything referencing this module as well (custom layout local.xml).
You also might want to go to System Config, Advanced and shut the Newsletter module output off there in case the Magento Customer Account is depending on testing for the module being disabled by calling that entry instead of actually checking to see if the Module is loaded. Sometimes Magento programmers forget to do proper error trapping, which has thrown me for a loop before.
I believe I could solve the problem (not sure if generated any side effect):
Just edited the file app\code\core\Mage\Adminhtml\Block\Customer\Edit\Tabs.php around line 90 by adding the external if clause:
if (Mage::helper('core')->isModuleEnabled('Mage_Newsletter')) {
if (Mage::getSingleton('admin/session')->isAllowed('newsletter/subscriber')) {
$this->addTab('newsletter', array(
'label' => Mage::helper('customer')->__('Newsletter'),
'content' => $this->getLayout()->createBlock('adminhtml/customer_edit_tab_newsletter')->initForm()->toHtml()
));
}
}
+1 if I saved your day and please let me know if you noticed and possible impact :D

How does zend view render resolve path to view script

How does an action like this "customSearchAction()" map to the view script file name.
Neither of these file names work "customsearch.xml.phtml", "customSearch.xml.phtml", "custom-search.xml.phtml".
Please, note that I am using context switching view helper for xml, json. Also, the module and action are resolving properly. When I change the action name to "customsearchAction()" and name the rename the script file to "customsearch.xml.phtml", then it works.
So how is the view script file name resolved in the above case? in the Zend Framework
From documentation:
Note: Naming Conventions: Word Delimiters in Controller and Action Names
If your controller or action name is composed of several words, the dispatcher requires that these are separated on the URL by specific path and word delimiter characters. The ViewRenderer replaces any path delimiter found in the controller name with an actual path delimiter ('/'), and any word delimiter found with a dash ('-') when creating paths. Thus, a call to the action /foo.bar/baz.bat would dispatch to FooBarController::bazBatAction() in FooBarController.php, which would render foo-bar/baz-bat.phtml; a call to the action /bar_baz/baz-bat would dispatch to Bar_BazController::bazBatAction() in Bar/BazController.php (note the path separation) and render bar/baz/baz-bat.phtml.
Note that the in the second example, the module is still the default module, but that, because of the existence of a path separator, the controller receives the name Bar_BazController, in Bar/BazController.php. The ViewRenderer mimics the controller directory hierarchy.
So, from that custom-search.phtml is the right name. Now you are maybe wrong with the directory where you store it, what's the controller name (and module)? Check as well you view script is readable by apache.
Edit
In the case of ContextSwitch usage:
the initialisation is: $contextSwitch->addActionContext('custom-search', 'xml');
the view script is custom-search.xml.phtml
Just tested it on a ZF 1.6 (old but should still be valid). So maybe your initialization is wrong (used 'customSearch' instead of 'custom-search'?).

How to set up site specific configuration vs application configuration in Zend Framework?

Being fairly new to Zend Framework, I've been reading and trying out various tutorials on the web and books I've purchased. One thing all the tutorials do is hard code certain values into into the bootstrap or other code. For example, setting the title:
$this->_view->headTitle('MySite');
I realize this can be set in the application.ini file, but I don't think that is appropriate either if you are distributing the application to other sites.
I would be interested in hearing ideas where application specific settings are set in the application.ini file and loaded:
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH.'/configs/application.ini'
);
Then somewhere in the bootstrap, checking for a config.ini file and adding these to currently existing application config array, and if config.ini does not exist, retrieving such site specific configs from a database and writing the config.ini file (Obviously the file deleted and rewritten if a value is changed in the database).
I don't need to see how the file is written or what not... just a general idea of how others are handling such things. Or provide different ideas of doing this?
I would rather end up using something like this when setting various site specific configurations:
$this->_view->headTitle($config->site->title);
Hope this makes sense :-)
It depends a bit what kind of data you want in your config files, and how you are reusing your application on different sites.
Although it's normal to pass the filename to your config file as the second parameter to Zend_Application, you can also pass a Zend_Config object. Zend_Config itself makes it very easy to merge together multiple config files, so in your public/index.php you could do something like this:
$defaultConfigFilename = APPLICATION_PATH . '/configs/application.ini';
$siteConfigFilename = APPLICATION_PATH . '/configs/site.ini';
// Create config object, using site-specific data if available
$config = new Zend_Config_Ini($defaultConfigFilename, null, true);
if (file_exists($siteConfigFilename)) {
$siteConfig = new Zend_Config_Ini($siteConfigFilename);
$config->merge($siteConfig)
->setReadOnly();
}
// Create application, bootstrap, and run
$application = new Zend_Application(
APPLICATION_ENV,
$config
);
this will look for a site.ini file, and if it exists, merge it with the application ini. Then it will bootstrap the application as normal.
Another way that I've used myself recently is to just keep application.ini as minimal as possible (e.g. only bootstrap class name and location), and then have an _initSite() method in my bootstrap class that creates a Site object using data from the database. It then reads in config data from a ini file, and stores this in the Site object. I then have a site resource that I can access elsewhere in my application, for example to do $view->_headTitle($site->config->title); like in your example above.
I hope this gives you some ideas. ZF is pretty flexible!
Remember, that you may pass many config files to Zend_Application, not just application.ini,
so this might be the best in your case.
If you heavily rely on configs, you may be interested on creating additional application resources, using specific setting you provide to the Zend_Application via config.ini.
But I bet, it the future, you will store these options in the database and allow end user to modify them.
In the simplest case, solution I prefer:
// in the layout.phtml
$this->render('head.phtml');
...
$this->render('footer.phtml');
And in the footer and head configuration specific to the site.
Fast and easy to maintain.
in view_script.phtml
$this->headTitle()->prepend($config->site_title);
where the trouble is?

Joomla template parameters and params.ini - file becomes unwritable after save

I am using wamp on Win XP SP3 and creating a Joomla template with changeable parameters.
initially the message is
The parameter file \templates\ssc_2010\params.ini is
writable!
once I make changes everything works as expected, except now i get the message:
The parameter file \templates\ssc_2010\params.ini is
unwritable!
One solution is to brows to the directory, right click the file, select properties, and uncheck read-only. Again the file is writable but once I modify the parameters again it becomes read only again. I'm quite lazy and would like to prevent this from happening again, I've notice this happening in past projects, but now I have to work a lot with parameters so it becomes quite boring doing manual labor like that :P
There is a bug in Joomla 1.5 that causes the message to be displayed.
A security feature was added that makes the template files unwritable until just before save, where they are made writable, saved, then made unwritable again.
Try to make a change, then go back and check the preview. You will see that the change was actually made.
If you want to fix the annoying unwritable message, add the following code to
administrator/components/controller.php around line 179, just after setting the FTP credentials:
$file = $client->path.DS.'templates'.DS.$template.DS.'params.ini';
// Try to make the params file writeable
if (!$ftp['enabled'] && JPath::isOwner($file) && !JPath::setPermissions($file, '0755')) {
JError::raiseNotice('SOME_ERROR_CODE', JText::_('Could not make the template parameter file writable'));
}
This will make the file writable during the edit load process, and before the file's status is posted in the template.
Then for security, in case the edit screen is closed without saving, search for the following lines:
require_once (JPATH_COMPONENT.DS.'admin.templates.html.php');
TemplatesView::editTemplate($row, $lists, $params, $option, $client, $ftp, $template);
and paste the following code just AFTER these lines but before the closing brace:
// Try to make the params file unwriteable
if (!$ftp['enabled'] && JPath::isOwner($file) && !JPath::setPermissions($file, '0555')) {
JError::raiseNotice('SOME_ERROR_CODE', JText::_('Could not make the template parameter file unwritable'));
}
That will make the file unwritable again.
This is the same code that is used in the saveTemplate() function. We are just doing it again before we display the status of the file on the edit screen. If the process fails because of your web server's configuration, you will get warning messages, BEFORE you've made a bunch of changes to your template. :)
P.S. Remember to save a copy of this file separately, so that you can redo the changes when you upgrade Joomla! (if they haven't fixed this themselves yet.)
This sounds like a user rights problem within Windows - have a look a the security permissions for the directory in which the file you are editing is located, and check that the user "IUSR_xxx" (where xxx is the name of your computer) has full control.
If this doesn't work, then can you tell us what version of Windows you are running as this may help...
Matt

Opcode (APC/XCache), Zend, Doctrine, and Autoloaders

I am trying to use either APC or XCache as an opcode to cache my php pages. I am using it with Zend and Doctrine and it's having a problem with the autoloader.
If I try with APC, I get the following:
Fatal error: spl_autoload() [<a href='function.spl-autoload'>function.spl-autoload</a>]:
Class Doctrine_Event could not be loaded in
C:\\[mydir]\\library\\doctrine\\Doctrine\\Record.php on line 777
If I try with XCache I get the following:
PHP Fatal error: Cannot redeclare class Zend_Registry in
C:\\[mydir]\\library\\zendframework\\Zend\\Registry.php on line 0
I'm running Zend 1.9.1, Doctrine 1.1 on a windows box.
My bootstrap is as follows:
set_include_path(dirname(__FILE__).'/../library/zendframework'
. PATH_SEPARATOR . dirname(__FILE__).'/../library/doctrine'.....
require 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
$loader->suppressNotFoundWarnings(false);
$loader->setFallbackAutoloader(true);
From what I've read, using APC or xcache is almost a must for performance, but I can't seem to get it working. Any ideas?
You could put a "Zend_Session::writeClose(true);" at the end of your index.php.
This will write the session into a persistent state before necessary Objects (Zend_Loader etc.) get destructed.
Better: Register it as shutdown function.
So it will be executed even if you use exit(), die() or a fatal error occures:
register_shutdown_function(array('Zend_Session', 'writeClose'), true);
It is probably similar to the problem with custom session handling and APC-cache. If you have assigned a custom session handler it is registered with RSHUTDOWN in PHP. It is the same routine that APC uses and will therefor create an internal conflict in PHP and your custom session handler will not close in all situations.
So you will have to make sure you manually close the custom session handler at shutdown
Putting a "Zend_Session::writeClose(true);" at the end of your index.php is not the best way to do that in case you have any exit; calls in your scripts anywhere.
It is better to register a shutdown handler in this way:
function shutdown()
{
Zend_Session::writeClose(true);
}
register_shutdown_function('shutdown');
Put that in top of your index.php file to make sure that the shutdown procedure is registered before any other scripts are run.
Is there something else mucking the include path? Maybe try to log out the include path right before that line in your first APC example.
The XCache one is really weird. That project is pretty dead though, and I'd not trust it on PHP 5.2+. Try eaccelerator instead? We've had the best luck with it.
Benjamin Cremer, you're a life saver. While the above (original) problem is a special case of autoloading with sessions, closing the session seems to be a general solution for such cases. A note though:
Placing Zend_Session::writeClose(true); at the end of your scripts may not always cut it, since you may have exit;'s, die();'s, etc in your code. In this case, you can use
register_shutdown_function(array('Zend_Session', 'writeClose'), true);
or, simply
register_shutdown_function('session_write_close');
if you do not use Zend for sessions.