Is there a comprehensive list of all events that can be listened for?
If this list doesn't exist, what's the best method to debug to obtain all events?
You'll never find a complete list. But if you go to app/Mage.php you can put in some debug code inside of the function "dispatchEvent()" and log all of the events as you go.
$params = array();
foreach (array_keys($data) as $key) {
if (is_object($data[$key])) {
$params[] = $key.' ('.get_class($data[$key]).')';
} else {
$params[] = $key.' ('.gettype($data[$key]).')';
}
}
Mage::log('event_name:'.$name.',event_passed_keys:'.implode('|',$params),null,'events.log',true);
Then using some excel wizardry you can parse those out into a list of all of the event names and parameters being passed to it.
The problem with many of the compiled lists or even doing the grep as shown above is that many of the events are dynamically created. Which lets you discern what events there are that aren't listed.
Make sure to comment out that debug code or the events.log file will become huge after just a short time.
Take a look at a list of events #
http://www.nicksays.co.uk/magento_events_cheat_sheet/
Customize Magento using Event/Observer
or
To log all the event for a specific page in your dev environment you could add Mage::log($eventName);
in /app/code/core/Mage/Core/Model/App.php
public function dispatchEvent($eventName, $args){
Mage::log($eventName);
....
or
grep -r Mage::dispatchEvent /path/to/your/Magento/* > events.txt
Read more #
Magento which event is called? Need to build an observer
https://magento.stackexchange.com/questions/153/where-can-i-find-a-complete-list-of-magento-events
As an exercise I wrote a Bash script to generate rough list of events (it actually acts as a wrapper to grep with a few switches to provide context and available params).
I've used this script to generate events lists for default Magento installations for versions 1.3.3.0 to 1.8.0.0 version and the code is available at GitHub:
https://github.com/Marko-M/magento-events-list/
Lists of events are available here:
https://github.com/Marko-M/magento-events-list/tree/master/magento-outofthebox
and a follow up article on my blog here:
http://www.techytalk.info/bash-script-to-generate-list-of-events-for-magento-installation/
Be aware that these lists can never be complete due to many event names being generated dynamically.
As you probably have extensions on your project and they dispatch their own events, it's even better to generate this list manually trough grep or using my script.
Cheers!
a general mean is to set an observer for any specific event you are interesting in
see https://magento.stackexchange.com/questions/314/how-to-know-the-magento-event-that-we-want-to-hook
in the module Logevent, the config.xml
0.1
Maticode_Logevent_Model
<controller_action_predispatch>
<observers>
<Logevent>
<type>singleton</type>
<class>Logevent/observer</class>
<method>controller_action_predispatch</method>
</Logevent>
</observers>
</controller_action_predispatch>
and the Model/observer.php
<?php
class Maticode_Logevent_Model_Observer {
public function controller_action_predispatch($observer) {
Mage::log ( $observer->getEvent ()->getControllerAction ()->getFullActionName (),null, 'eventlog.log' );
}
}
This way , in the
var/log/eventlog.log file
u can visualize a possible hook on any tested actions (click on a button and check your log )
Related
I would assume that there is an event after every model save.
How is this formatted, and is there a way to log all of these events?
This is useful if there is not a standard event declared within the moudle you are looking to extend.
Here is what I think the best answer would be based on all of the information that you've been provided.
A model does not necessarily need to fire an event at save/edit/delete however if it extends the Mage_Core_Model_Abstract class without overriding the default methods associated with save/edit/delete the events will be fired.
In order for an event to be unique to that model $this->_eventPrefix must be unique to that model
Logging these events often does not work
To find the particular event you are looking for
If you are using an IDE this should be much easier but you can also use utilities like grep.
Make a search within the module that you are working with for "$_eventPrefix ="
Use the list below to find the appropriate event suffix
Concatenate the two together and you should have your event
_load_before
_load_after
_save_before
_save_after
_save_commit_after
_delete_before
_delete_after
_delete_commit_after
_clear
To Log all events go to app/Mage.php line 446 and add:
Mage::setIsDeveloperMode(true);
Mage::log($name);
Take a look at Mage_Core_Model_Abstract::afterCommitCallback - it has a generic event and an event dispatched by the prefix of the specific model being saved.
/**
* Callback function which called after transaction commit in resource model
*
* #return Mage_Core_Model_Abstract
*/
public function afterCommitCallback()
{
Mage::dispatchEvent('model_save_commit_after', array('object'=>$this));
Mage::dispatchEvent($this->_eventPrefix.'_save_commit_after', $this->_getEventData());
return $this;
}
Whether you want this or
/**
* Processing object after save data
*
* #return Mage_Core_Model_Abstract
*/
protected function _afterSave()
{
$this->cleanModelCache();
Mage::dispatchEvent('model_save_after', array('object'=>$this));
Mage::dispatchEvent($this->_eventPrefix.'_save_after', $this->_getEventData());
return $this;
}
depends on whether you care if the data has actually been written to the database or not when you run your event handler.
When Magento sees a call to Mage::dispatchEvent it will call any public model class registered for that specific event name. So the real place to look for events is in the config.xml for the module/models you're interested in. The xml is not likely to be programmatically generated, so you don't have to fuss around with guessing _eventPrefix values. You know the event suffix you want, so just look in configuration for events with names ending with that suffix.
If you have an installed store, you can use n98-magerun to search the config.xml. (It has a config:get command that you can use to search, but I prefer config:dump to a file, followed by using an xml parser and xpath to search through the result.)
I always put a log into app/Mage.php into dispatchEvent() method
...
Mage::log($name, array_keys($event_data));
...
Then I refresh the page in the browser where I need to apply a custom event action and then look into system.log to see what events happen on my page.
Just need to put something like below in config.xml:
<global>
<events>
<catalog_entity_attribute_save_commit_after>
<observers>
<yourextension_save_commit_after_observer>
<type>singleton</type>
<class>yourextension/save_commit_after_observer</class>
<method>yourMethod</method>
</yourextension_save_commit_after_observer>
</observers>
</catalog_entity_attribute_save_commit_after>
</events>
</global>
That's correct. There is a _save_before and _save_after events after every model save, such as catalog_product_before_save, catalog_product_after_save, customer_address_before_save, customer_address_after_save, etc.
You can refer to this link below for more complete information about how to use it and the complete list of all events in Magento.
Source: http://www.vjtemplates.com/blog/magento/events-and-observers
I'm trying to customize my Magento's log directory, by setting log_dir in the Mage::app() $options, but it's still logging to var/log/file.log.
Note: I couldn't find this information very readily on SO or the web in general, so I felt it needed to be SO'd.
So it turns out that (as of 1.6.2.0 at least), Magento doesn't actually use the Mage::getBaseDir('log') within it's log() method - weak sauce, right?
It uses Mage::getBaseDir('var') and appends log and then the file name that you pass in.
If you want to customize the directory more than that, you have to get your hands a little dirty. For example, in our case, we wanted the log directory to be:
var/username/log/file.log
So here's how you bust it. Drop this in your config.xml to tell Magento about your new logging class:
<log>
<core>
<writer_model>Name_Module_Model_Zend_Log_Writer_Stream</writer_model>
</core>
</log>
Then, create a model:
class Name_Module_Model_Zend_Log_Writer_Stream extends Zend_Log_Writer_Stream
Then, proceed to do what you needs to do. In my case, it went something like this:
public function __construct($streamOrUrl, $mode = NULL)
{
$newLogPath = $this->_workMyMagicOnLogFilePath($streamOrUrl, $mode);
return parent::__construct($newLogPath, $mode);
}
I have a simple module created with the Magento Module Creator with a couple of settings in admin->system->config.
When I go to these settings and choose the enable/disable option, the settings get saved - which is great - however, I want to run my own code after that, i.e. on the save action, once the data has been saved.
In your etc/system.xml add a backend model descended from Mage_Core_Model_Config_Data and use it's _afterSave() method to run your code.
although it isnt a good idea but you can achieve it by observers:
<controller_action_postdispatch_adminhtml_mymodule_mycontroller_myaction>
replace the my-s with module_controller_action, and most likely you want to put it in this event:
<controller_action_postdispatch_adminhtml_system_config_save>
in your config xml as follows:
<controller_action_postdispatch_adminhtml_system_config_save>
<observers><myobserver>
<type>singleton</type>
<class>mymodule/observer</class>
<method>mymethod</method>
</myobserver></observers>
</controller_action_postdispatch_adminhtml_system_config_save>
and in mymodule, as in your module have a class observer in mymodule/Model/Observer.php
and declare the observer as
class modules_mymodule_observer {
public function myfunction(Varien_Event_Observer $observer){
//do your stuffs
}
}
If I want to do something extra when a particular configuration field for my custom module is saved (over and above saving to the Magento core config table), I can just specify a backend_model for that field in my system.xml, and have that backend model class extend Mage_Core_Model_Config_Data, override _afterSave, and put my extra stuff in that method.
But what if I have several fields I want to do this for. I don't want the behaviour to be to save field1 and call my afterSave for that field, save field2 and call my afterSave for that field, etc. I'd rather that all the fields were saved to the Magento core config table, and then I do my extra stuff.
Is that possible? I thought I might be able to achieve that using event/observer. So in my config.xml, <adminhtml> section, I added an observer as follows:
<events>
<admin_system_config_changed_mysection>
<observers>
<mypfx_admin_system_config_changed_mysection>
<class>mymodule/adminhtml_system_config_backend_configSaveObserver</class>
<method>myConfigSaved</method
</mypfx_admin_system_config_changed_mysection>
</observers>
</admin_system_config_changed_mysection>
</events>
but my observer method is not called when the config is saved. Maybe I have the wrong event name? The "mysection" bit on the end of the event name I was guessing had to match the section from system.xml:
<sections>
<mysection translate="label" module="mymodule">
...
<groups>
...
</groups>
</mysection>
</sections>
Thanks.
The event you're trying to listen for doesn't exist. Here's what you want to do, and some tips for picking the right event in the future.
First, every event is fired in Magento by the Mage::dispatchEvent method. Search the core code for these calls and you'll always know the name of the event you want to listen for.
$ ack 'admin_system_config_changed_'
Adminhtml/controllers/System/ConfigController.php
136: Mage::dispatchEvent("admin_system_config_changed_section_{$section}",
From the above, you can see the name of the event vs. what you thought it was
admin_system_config_changed_section_{$section}
admin_system_config_changed_mysection
So, it looks like you're missing the section before your own section name.
Second, while working on a development box, the best way to find the event you're looking for is to log things at the source. Temporarily add some debugging code to the dispatchEvent function.
#File: app/Mage.php
public static function dispatchEvent($name, array $data = array())
{
//either one of the lines below should do it. One uses Magento's
//built in logging, the other uses something more crude
#Mage::Log($name);
#file_put_contents('/tmp/test.log',"$name\n",FILE_APPEND);
Varien_Profiler::start('DISPATCH EVENT:'.$name);
$result = self::app()->dispatchEvent($name, $data);
#$result = self::registry('events')->dispatch($name, $data);
Varien_Profiler::stop('DISPATCH EVENT:'.$name);
return $result;
}
This will dump a huge list of event names out to your log. I typically use OS X's Console.app to view the log file during the request, copy the lines out, sort and remove duplicates, and then end up with a list like this
admin_system_config_changed_section_commercebug
admin_user_load_after
admin_user_load_before
adminhtml_block_html_before
adminhtml_controller_action_predispatch_start
application_clean_cache
controller_action_layout_generate_blocks_after
controller_action_layout_generate_blocks_before
controller_action_layout_generate_xml_before
controller_action_layout_load_before
controller_action_layout_render_before
controller_action_layout_render_before_adminhtml_system_config_edit
controller_action_postdispatch
controller_action_postdispatch_adminhtml
controller_action_postdispatch_adminhtml_system_config_edit
controller_action_postdispatch_adminhtml_system_config_save
controller_action_predispatch
controller_action_predispatch_adminhtml
controller_action_predispatch_adminhtml_system_config_edit
controller_action_predispatch_adminhtml_system_config_save
controller_front_init_before
controller_front_init_routers
controller_front_send_response_after
controller_front_send_response_before
core_abstract_load_after
core_abstract_load_before
core_block_abstract_prepare_layout_after
core_block_abstract_prepare_layout_before
core_block_abstract_to_html_after
core_block_abstract_to_html_before
core_collection_abstract_load_after
core_collection_abstract_load_before
core_config_data_load_after
core_config_data_save_after
core_config_data_save_before
core_config_data_save_commit_after
core_layout_block_create_after
core_locale_set_locale
core_session_abstract_add_message
core_session_abstract_clear_messages
http_response_send_before
model_load_after
model_load_before
model_save_after
model_save_before
model_save_commit_after
resource_get_tablename
store_load_after
store_load_before
You still need to use some intelligence guessing to figure out which event you want, but they're named intuitively enough that you can usually find what you're looking for.
You need to tie your observer method to a specific Magento event (you can add your own, but need to find when you want it to be fired and add your own dispatchEvent call). If Magento has an event built in, use that event name in the config.
There's a pdf of the built in event lists on the web - google for it & you'll find it.
in a 'native' Zend Framework application I would enable the use of ezComponents by adding the autoloader of ezComponents to Zends autoloader:
$autoLoader = Zend_Loader_Autoloader::getInstance();
require_once('../library/EZComponents/Base/src/base.php');
$autoLoader->pushAutoloader(array('ezcBase', 'autoload'), 'ezc');
Now, I'm wondering how I could do the same with Magento.
Is there a way to extend Varien_Autoload (magentos autoloader) to enable easy integration of ezComponents?
OR:
Is there a way to use Zends autoloader beside the one from Magento without interfering each other?
edit:
Well, I implemented a workaround, by adding the following to function autoload() in Varien_Autoload:
if(substr($class, 0, 3) == 'ezc'){
require_once('EZComponents/Base/src/base.php');
return ezcBase::autoload($class);
}
I consider this as a very bad hack though, because it will be overwritten, when upgrading Magento. Does anyone has a better idea?
My basic approach here would be to create a custom module with an observer for the
controller_front_init_before
event. In the event observer, you'd be able to setup your autoloader however you want. There's a Magento Wiki article on Setting up Event Observers. The controller_front_init_before event is one of the first non-generic events to fire in Magento. That's why we're using it.
The big problem we need to solve is this: Magento's autoloader is on the stack first, and if it doesn't find a file (which will be the case with the EZComponent classes), its include will raise a error that will halt execution.
So, what we need to do in our event observer above is to
Remove the Varien_Autoloader from the spl_autoload stack
Register our own autoloader (we'll use Zend_Autoloader, since it ships with Magento and you seem familiar with it)
Re-add the Varien_Autoloader to the stack
There'll be a little extra jiggery-pokery we'll need to do since loading of the classes in the Zend namespace is normally handled by the autoloader we'll be removing. See comments for more details
//we need to manually include Zend_Loader, or else our zend autoloader
//will try to use it, won't find it, and then try to use Zend_Loader to
//load Zend_Loader
require_once('lib/Zend/Loader.php');
//instantiate a zend autoloader first, since we
//won't be able to do it in an unautoloader universe
$autoLoader = Zend_Loader_Autoloader::getInstance();
//get a list of call the registered autoloader callbacks
//and pull out the Varien_Autoload. It's unlikely there
//are others, but famous last words and all that
$autoloader_callbacks = spl_autoload_functions();
$original_autoload=null;
foreach($autoloader_callbacks as $callback)
{
if(is_array($callback) && $callback[0] instanceof Varien_Autoload)
{
$original_autoload = $callback;
}
}
//remove the Varien_Autoloader from the stack
spl_autoload_unregister($original_autoload);
//register our autoloader, which gets on the stack first
require_once('library/EZComponents/Base/src/base.php');
$autoLoader->pushAutoloader(array('ezcBase', 'autoload'), 'ezc');
//lets just make sure we can instantiate an EZ class
#$test = new ezcBaseFile();
#var_dump(get_class($test));
//IMPORANT: add the Varien_Autoloader back to the stack
spl_autoload_register($original_autoload);
Put the above code in an observer method and you should be good to go.
The other approach you could take, one that would fit in more with Magento patterns, would be to create a custom module that implemented an EZComponent loader.
$o = Mypackage_Mymodule_Loader::getModel('ezcBaseFile');
You'd then implement autoloader style require code in your static getModel method, and use it whenever you wanted an ezcBaseFile class. You'd probably want methods for loading a class without instantiating an object in case you wanted to call a static method on an ezcBaseFile base class.
$o = Mypackage_Mymodule_Loader::getLoadclass('ezcBaseFile');
I took a quick look at the code for Varien's autoloader and it appears to use a call to spl_autoload_register, which is a stack for performing autoloads. While I don't think you'll have much success adding to the default Magento autoloader, this means that you should be able to push another autoloader on top of Magento's.
Hope that helps!
Thanks,
Joe
I've just integrated the Sailthru_Client class into Magento, thought this might help.
I have sailthru.php, the Sailthru Client API, which contains Sailthru_Client class.
I created magentoroot/lib/Sailthru folder then copy sailthru.php into it, then renamed to Client.php making it magentoroot/lib/Sailthru/Client.php. This pattern is auto-loaded by Varien_Autoload class.