Una de las formas más interesantes de modificar el comportamiento de tu Magento es utilizar los eventos. Se ejecutan en cada click del navegador, cuando un visitante se registra, cuando se añade un producto al comparador, cuando se crea un pedido, cuando se visita una página, una categoría, un producto, cuando un visitante entra a su zona de usuario, edita sus datos, busca contenidos.. es ingente la cantidad de eventos. Es decir, que contínuamente se están disparando una tonelada de eventos mientras que se ejecuta Magento.
Cuando empiezas a programar nuevos comportamientos, puedes buscar en StackOverflow o Googleando. A ver cuál es el evento que necesitas. Con la esperanza de que alguien haya compartido ya algo sobre esto..
Por ejemplo
Si necesitas comprobar ciertos datos de un pedido cuando se está haciendo en el front, puedes ponerte a observar los eventos siguientes:
sales_order_address_collection_load_after sales_order_address_collection_load_before sales_order_address_collection_set_sales_order sales_order_address_save_after sales_order_address_save_before sales_order_address_save_commit_after sales_order_collection_load_after sales_order_collection_load_before sales_order_creditmemo_resource_init_virtual_grid_columns sales_order_invoice_resource_init_virtual_grid_columns sales_order_item_collection_load_after sales_order_item_collection_load_before sales_order_item_collection_set_sales_order sales_order_item_load_after sales_order_item_load_before sales_order_item_save_after sales_order_item_save_before sales_order_item_save_commit_after sales_order_load_after sales_order_load_before sales_order_payment_collection_load_after sales_order_payment_collection_load_before sales_order_payment_collection_set_sales_order sales_order_payment_place_end sales_order_payment_place_start sales_order_payment_save_after sales_order_payment_save_before sales_order_payment_save_commit_after sales_order_place_after sales_order_place_before sales_order_resource_init_virtual_grid_columns sales_order_resource_save_attribute_after sales_order_resource_save_attribute_before sales_order_resource_update_grid_records sales_order_save_after sales_order_save_before sales_order_save_commit_after sales_order_shipment_collection_load_before sales_order_shipment_collection_set_sales_order sales_order_shipment_load_after sales_order_shipment_load_before sales_order_shipment_resource_init_virtual_grid_columns sales_order_shipment_track_collection_load_after sales_order_shipment_track_collection_load_before sales_order_status_history_collection_load_after sales_order_status_history_collection_load_before sales_order_status_history_collection_set_sales_order sales_order_status_history_save_after sales_order_status_history_save_before sales_order_status_history_save_commit_after
Como es habitual, los programadores solemos compartir conocimientos por Internete. Así que una solución para ponerse a programar estas modificaciones es esta. Al principio es más que suficiente, pero cuanto más raro es el comportamiento que necesitas, más difícil va a ser que encuentres a alguien compartiendo la información.
Así que por esto que estoy compartiendo este post.. 😉 con esto ya podrás encontrar cualquier evento de Magento.
Un poco de teoría
Los eventos, listeners, observers.. son conceptos relacionados con los Patrones de Diseño de Software. No voy a entrar al detalle, ya que con esto se podría escribir otro post completo, con cada patrón.. Pero lo principal que hay que saber, es que podemos crear observadores que esperan a que ocurran ciertos eventos. Así que cuando ocurran esos eventos, podremos ejecutar las rutinas que queramos.
Por ejemplo, imagina que queremos decirle al usuario algo cuando ha puesto su NIF en el carrito de la compra. Podemos hacerlo con esto. Imagina que queremos comprobar si un pedido es de cierto grupo de clientes, y en ese caso moverlo a otro estado. También se puede hacer con esto.
Dichos eventos están predefinidos en el software. De forma que cuando ocurren estos eventos, el software busca qué observadores están enganchados, y los ejecuta.
Cómo se definen los eventos
En Magento, para definir un evento basta con escribir algo tal que así:
Mage::dispatchEvent('my_event', $data_array);
..con esto ya hemos creado un evento llamado my_event al cual se pueden enganchar observadores. Dicho evento se disparará en todos los lugares donde lo hayas escrito. Por ejemplo, puedes crearlo en tus controladores, o cuando ocurren ciertas acciones en los modelos. Además, dichos eventos recibirán los datos que le hayas pasado.
Bien, ahora cómo encuentro todos los eventos definidos
Una forma sería entonces buscar la cadena dispatchEvent() en el código fuente, pero nos encontramos algo tal que así:
Ahora es cuando te echas las manos a la cabeza al ver que muchos eventos no tienen un nombre fijo, sino que se generan dichos nombres al vuelo. Y además, luego se van a disparar dichos eventos al vuelo según se usen. Esto es un ejemplo de la brillante estructura interna que puede alcanzar un módulo. Si te fijas en el AEO Scheduler, este módulo, genera eventos para cada tarea programada de Magento. Así podrás modificar el comportamiento de cualquier tarea programada antes o después de su ejecución, cuando ha fallado, cuando no ha fallado..
Algo escribí sobre cómo crear tareas programadas de Magento aquí.
Entonces, cómo listo todos los eventos disponibles?
Podemos hacer un pequeño arreglo para encontrar todos los eventos relacionados con ciertos comportamiento. No hay más que poner esto en la función del core de Magento que dispara los eventos. En directorio del core de Magento está la función dispatchEvent(). Si ponemos lo siguiente en el fichero app/code/core/Mage/Core/Model/App.php:
... public function dispatchEvent($eventName, $args) { if(!empty($eventName)) Mage::log($eventName, Zend_Log::INFO, 'availableEvents.log', false); $eventName = strtolower($eventName); foreach ($this->_events as $area=>$events) { ...
..estaremos guardando en el fichero availableEvents.log todos los nombres de eventos. Serán muchos y se generará un fichero bien grande mientras que usamos en local Magento. ¡NO HACER ESTO EN PRODUCCIÓN!
Con esto guardando los nombres de eventos, he arrancado en local el proyecto, y he hecho un pedido de prueba. De ahí ha salido el listado de arriba de eventos.
Solo queda poner bonito el listado de eventos
Por si sirve de ayuda, con este sencillo script que he hecho se pueden ordenar y eliminar los duplicados que tendremos en el fichero availableEvents.log:
<?php /** * LOOK AT app/code/core/Mage/Core/Model/App.php FOR dispatchEvent FUNCTION AND: * var/log/availableEvents.log FOR GETTING ALL EVENT NAMES. */ $events = file(__DIR__.'/../web/var/log/availableEvents.log'); echo 'Loaded '.count($events).' event names.'.PHP_EOL; $names = array(); foreach ($events as $key => $value) { $events[$key] = preg_replace("/.* INFO \(6\): /", '', $value); $names[] = $events[$key]; //echo $events[$key]; } $names = array_unique($names); sort($names); echo 'Finally '.count($names).' event names.'.PHP_EOL; foreach ($names as $name) { echo $name; }
Terminando
Para hacernos una idea, en pocos segundos, en una visita rápida para hacer un pedido en el front de un proyecto. Se han disparado 400 eventos, con un total de 80 000 veces, ¿brutal el potencial que tiene esto verdad?
Loaded 80357 event names. Finally 418 event names. admin_session_user_login_failed admin_session_user_login_success admin_user_authenticate_after admin_user_authenticate_before admin_user_load_after admin_user_load_before adminhtml_block_html_before adminhtml_controller_action_predispatch_start advancedstock_order_considered_by_cron advancedstock_order_item_preparation_warehouse_changed advancedstock_order_item_reserved_qty_changed advancedstock_stock_aftersave always aoe_scheduler_job_load_after aoe_scheduler_job_load_before aoe_scheduler_schedule_collection_load_after aoe_scheduler_schedule_collection_load_before aoe_scheduler_schedule_delete_after aoe_scheduler_schedule_delete_before aoe_scheduler_schedule_delete_commit_after aoe_scheduler_schedule_save_after aoe_scheduler_schedule_save_before aoe_scheduler_schedule_save_commit_after application_clean_cache aschroder_smtppro_after_send aschroder_smtppro_template_before_send catalog_block_product_list_collection catalog_category_collection_load_after catalog_category_collection_load_before catalog_category_flat_loadnodes_before catalog_category_load_after catalog_category_load_before catalog_category_tree_init_inactive_category_ids catalog_compare_item_save_after catalog_compare_item_save_before catalog_compare_item_save_commit_after catalog_controller_category_init_after catalog_controller_category_init_before catalog_entity_attribute_load_after catalog_helper_output_construct catalog_prepare_price_select catalog_product_attribute_backend_media_load_gallery_before catalog_product_collection_apply_limitations_after catalog_product_collection_apply_limitations_before catalog_product_collection_before_add_count_to_categories catalog_product_collection_load_after catalog_product_collection_load_before catalog_product_compare_add_product catalog_product_get_final_price catalog_product_is_salable_after catalog_product_is_salable_before catalog_product_load_after catalog_product_load_before catalog_product_type_prepare_full_options cataloginventory_stock_item_save_after cataloginventory_stock_item_save_before cataloginventory_stock_item_save_commit_after catalogsearch_query_load_after catalogsearch_query_save_after catalogsearch_query_save_before catalogsearch_query_save_commit_after checkout_allow_guest checkout_block_cart_sidebar_aftertohtml checkout_cart_add_product_complete checkout_cart_product_add_after checkout_cart_save_after checkout_cart_save_before checkout_controller_onepage_save_shipping_method checkout_onepage_controller_success_action checkout_quote_destroy checkout_quote_init checkout_submit_all_after checkout_type_onepage_save_order checkout_type_onepage_save_order_after cms_page_load_after cms_page_load_before cms_page_render 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_dashboard_index controller_action_layout_render_before_adminhtml_index_login controller_action_layout_render_before_catalog_category_view controller_action_layout_render_before_catalogsearch_result_index controller_action_layout_render_before_checkout_cart_index controller_action_layout_render_before_checkout_onepage_success controller_action_layout_render_before_cms_index_index controller_action_layout_render_before_cms_index_noRoute controller_action_layout_render_before_customer_account_login controller_action_layout_render_before_opc_index_index controller_action_noroute controller_action_postdispatch controller_action_postdispatch_adminhtml controller_action_postdispatch_adminhtml_dashboard_index controller_action_postdispatch_adminhtml_dashboard_tunnel controller_action_postdispatch_adminhtml_index_index controller_action_postdispatch_adminhtml_index_login controller_action_postdispatch_adminhtml_zendesk_ticketsAll controller_action_postdispatch_ajaxcart controller_action_postdispatch_ajaxcart_index_add controller_action_postdispatch_ajaxcart_whishlist_compare controller_action_postdispatch_catalog controller_action_postdispatch_catalog_category_noRoute controller_action_postdispatch_catalog_category_view controller_action_postdispatch_catalog_index_noRoute controller_action_postdispatch_catalogsearch controller_action_postdispatch_catalogsearch_result_index controller_action_postdispatch_checkout controller_action_postdispatch_checkout_cart_index controller_action_postdispatch_checkout_onepage_success controller_action_postdispatch_cms controller_action_postdispatch_cms_index_index controller_action_postdispatch_cms_index_noRoute controller_action_postdispatch_customer controller_action_postdispatch_customer_account_login controller_action_postdispatch_m_searchautocomplete controller_action_postdispatch_m_searchautocomplete_ajax_get controller_action_postdispatch_opc controller_action_postdispatch_opc_index_index controller_action_postdispatch_opc_json_comment controller_action_postdispatch_opc_json_payments controller_action_postdispatch_opc_json_reloadShippingsPayments controller_action_postdispatch_opc_json_review controller_action_postdispatch_opc_json_saveBilling controller_action_postdispatch_opc_json_saveOrder controller_action_postdispatch_opc_json_savePayment controller_action_postdispatch_opc_json_saveShippingMethod controller_action_predispatch controller_action_predispatch_adminhtml controller_action_predispatch_adminhtml_dashboard_index controller_action_predispatch_adminhtml_dashboard_tunnel controller_action_predispatch_adminhtml_index_index controller_action_predispatch_adminhtml_index_login controller_action_predispatch_adminhtml_zendesk_ticketsAll controller_action_predispatch_ajaxcart controller_action_predispatch_ajaxcart_index_add controller_action_predispatch_ajaxcart_whishlist_compare controller_action_predispatch_catalog controller_action_predispatch_catalog_category_noRoute controller_action_predispatch_catalog_category_view controller_action_predispatch_catalogsearch controller_action_predispatch_catalogsearch_result_index controller_action_predispatch_checkout controller_action_predispatch_checkout_cart_index controller_action_predispatch_checkout_onepage_success controller_action_predispatch_cms controller_action_predispatch_cms_index_index controller_action_predispatch_cms_index_noRoute controller_action_predispatch_customer controller_action_predispatch_customer_account_index controller_action_predispatch_customer_account_login controller_action_predispatch_m_searchautocomplete controller_action_predispatch_m_searchautocomplete_ajax_get controller_action_predispatch_opc controller_action_predispatch_opc_index_index controller_action_predispatch_opc_json_comment controller_action_predispatch_opc_json_payments controller_action_predispatch_opc_json_reloadShippingsPayments controller_action_predispatch_opc_json_review controller_action_predispatch_opc_json_saveBilling controller_action_predispatch_opc_json_saveOrder controller_action_predispatch_opc_json_savePayment controller_action_predispatch_opc_json_saveShippingMethod controller_front_init_before controller_front_init_routers controller_front_send_response_after controller_front_send_response_before controller_response_redirect core_abstract_delete_after core_abstract_delete_before core_abstract_delete_commit_after core_abstract_load_after core_abstract_load_before core_abstract_save_after core_abstract_save_before core_abstract_save_commit_after 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_copy_fieldset_customer_account_to_quote core_copy_fieldset_sales_convert_quote_address_to_order core_copy_fieldset_sales_convert_quote_address_to_order_address core_copy_fieldset_sales_convert_quote_item_to_order_item core_copy_fieldset_sales_convert_quote_item_to_order_item_discount core_copy_fieldset_sales_convert_quote_payment_to_order_payment core_copy_fieldset_sales_convert_quote_to_order core_layout_block_create_after core_layout_update_updates_get_after core_locale_set_locale core_session_abstract_add_message core_session_abstract_clear_messages cron_after cron_after_success cron_aoescheduler_heartbeat_after cron_aoescheduler_heartbeat_after_success cron_aoescheduler_heartbeat_before cron_before cron_captcha_delete_expired_images_after cron_captcha_delete_expired_images_after_success cron_captcha_delete_expired_images_before cron_captcha_delete_old_attempts_after cron_captcha_delete_old_attempts_after_success cron_captcha_delete_old_attempts_before cron_continuegenerating_after cron_continuegenerating_after_success cron_continuegenerating_before cron_core_email_queue_send_all_after cron_core_email_queue_send_all_after_success cron_core_email_queue_send_all_before cron_doofinder_feed_generate_after cron_doofinder_feed_generate_after_success cron_doofinder_feed_generate_before cron_ebizmarts_abandoned_cart_after cron_ebizmarts_abandoned_cart_after_success cron_ebizmarts_abandoned_cart_before cron_ebizmarts_autoresponder_after cron_ebizmarts_autoresponder_after_success cron_ebizmarts_autoresponder_before cron_exception cron_execute_tasks_after cron_execute_tasks_after_success cron_execute_tasks_before cron_export_shipments_shoppingflux_before cron_export_update_stock_shoppingflux_after cron_export_update_stock_shoppingflux_after_success cron_export_update_stock_shoppingflux_before cron_generatefeed_after cron_generatefeed_after_success cron_generatefeed_before cron_import_pricing_after cron_import_pricing_after_success cron_import_pricing_before cron_magemonkey_sendorders_asynch_after cron_magemonkey_sendorders_asynch_after_success cron_magemonkey_sendorders_asynch_before cron_magemonkey_sendsubscribers_asynch_after cron_magemonkey_sendsubscribers_asynch_after_success cron_magemonkey_sendsubscribers_asynch_before cron_magemonkey_webhooks_asynch_before cron_magemonkey_webhooks_asynch_exception cron_newsletter_send_all_after cron_newsletter_send_all_after_success cron_newsletter_send_all_before cron_pagantis_pagantiseom_after cron_pagantis_pagantiseom_after_success cron_pagantis_pagantiseom_before cron_realex_expiredcards_after cron_realex_expiredcards_after_success cron_realex_expiredcards_before cron_realex_ordercleanup_after cron_realex_ordercleanup_after_success cron_realex_ordercleanup_before cron_run_queue_after cron_run_queue_after_success cron_run_queue_before cron_searchsphinx_check_daemon_after cron_searchsphinx_check_daemon_after_success cron_searchsphinx_check_daemon_before cron_searchsphinx_reindex_delta_job_after cron_searchsphinx_reindex_delta_job_after_success cron_searchsphinx_reindex_delta_job_before cron_turpentine_crawl_urls_after cron_turpentine_crawl_urls_after_success cron_turpentine_crawl_urls_before cron_update_availability_status_after cron_update_availability_status_after_success cron_update_availability_status_before cron_update_stocks_after cron_update_stocks_after_success cron_update_stocks_before currency_display_options_forming custom_quote_process customer_address_format customer_address_validation_after customer_entity_attribute_load_after customer_group_load_after customer_group_load_before customer_load_after customer_load_before customer_session_init default eav_collection_abstract_load_before gift_options_prepare_items http_response_send_before model_delete_after model_delete_before model_delete_commit_after model_load_after model_load_before model_save_after model_save_before model_save_commit_after opc_saveGiftMessage orderpreparartion_after_dispatch_order payment_method_is_active persistent_session_expired prepare_catalog_product_collection_prices process_collection_load_after process_collection_load_before resource_get_tablename sales_convert_quote_address_to_order sales_convert_quote_address_to_order_address sales_convert_quote_item_to_order_item sales_convert_quote_payment_to_order_payment sales_convert_quote_to_order sales_model_service_quote_submit_after sales_model_service_quote_submit_before sales_model_service_quote_submit_success sales_order_address_collection_load_after sales_order_address_collection_load_before sales_order_address_collection_set_sales_order sales_order_address_save_after sales_order_address_save_before sales_order_address_save_commit_after sales_order_collection_load_after sales_order_collection_load_before sales_order_creditmemo_resource_init_virtual_grid_columns sales_order_invoice_resource_init_virtual_grid_columns sales_order_item_collection_load_after sales_order_item_collection_load_before sales_order_item_collection_set_sales_order sales_order_item_load_after sales_order_item_load_before sales_order_item_save_after sales_order_item_save_before sales_order_item_save_commit_after sales_order_load_after sales_order_load_before sales_order_payment_collection_load_after sales_order_payment_collection_load_before sales_order_payment_collection_set_sales_order sales_order_payment_place_end sales_order_payment_place_start sales_order_payment_save_after sales_order_payment_save_before sales_order_payment_save_commit_after sales_order_place_after sales_order_place_before sales_order_resource_init_virtual_grid_columns sales_order_resource_save_attribute_after sales_order_resource_save_attribute_before sales_order_resource_update_grid_records sales_order_save_after sales_order_save_before sales_order_save_commit_after sales_order_shipment_collection_load_before sales_order_shipment_collection_set_sales_order sales_order_shipment_load_after sales_order_shipment_load_before sales_order_shipment_resource_init_virtual_grid_columns sales_order_shipment_track_collection_load_after sales_order_shipment_track_collection_load_before sales_order_status_history_collection_load_after sales_order_status_history_collection_load_before sales_order_status_history_collection_set_sales_order sales_order_status_history_save_after sales_order_status_history_save_before sales_order_status_history_save_commit_after sales_prepare_amount_expression sales_quote_add_item sales_quote_address_collect_totals_after sales_quote_address_collect_totals_before sales_quote_address_collection_load_after sales_quote_address_collection_load_before sales_quote_address_discount_item sales_quote_address_save_after sales_quote_address_save_before sales_quote_address_save_commit_after sales_quote_collect_totals_after sales_quote_collect_totals_before sales_quote_config_get_product_attributes sales_quote_item_collection_products_after_load sales_quote_item_qty_set_after sales_quote_item_save_after sales_quote_item_save_before sales_quote_item_save_commit_after sales_quote_item_set_product sales_quote_load_after sales_quote_load_before sales_quote_payment_delete_after sales_quote_payment_delete_before sales_quote_payment_delete_commit_after sales_quote_payment_import_data_before sales_quote_payment_save_after sales_quote_payment_save_before sales_quote_payment_save_commit_after sales_quote_product_add_after sales_quote_save_after sales_quote_save_before sales_quote_save_commit_after salesorder_aftersave salesorder_beforesave salesorderitem_aftersave salesorderplanning_productavailabilitystatus_aftersave store_group_load_after store_group_load_before store_load_after store_load_before tax_rate_data_fetch turpentine_session_init visitor_init