¿Cuál es la forma correcta de detener una salida de un observador de eventos en Magento?

Estoy verificando las cotizaciones de envío durante el evento checkout_controller_onepage_save_shipping_method y si la verificación falla, quiero enviar al usuario a la selección del método de envío, pero también me gustaría mostrar un mensaje que explique por qué falló. ¿Magento tiene una forma de hacer esto integrado?

Ya estoy verificando los datos, solo me falta la redirección a los métodos de envío y la forma de mostrar un mensaje.

La respuesta de Alan Storm es, como siempre, informativa e iluminadora. Pero en esta situación, el pago y envío de Onepage es principalmente AJAX que ignora el mensaje de error de la sesión, no lo verá hasta que salga de la página de pago.

En saveShippingMethodAction hay la siguiente línea:

 $result = $this->getOnepage()->saveShippingMethod($data); 

… y luego $ result está codificado en JSON. Si reemplaza Mage_Checkout_Model_Type_Onepage::saveShippingMethod para realizar su verificación y luego controla lo que se devuelve, puede insertar un mensaje de error que se devolverá al navegador y se le mostrará al usuario en una ventana emergente.

Su anulación puede verse más o menos así:

 public function saveShippingMethod($shippingMethod) { if ($this->doesntApplyHere()) { return array('error' => -1, 'message' => $this->_helper->__('Explain the problem here.')); } return parent::saveShippingMethod($shippingMethod); } 

(Nada de esto es código probado, pero los conceptos deben llevarlo a donde necesita ir)

Magento es un proyecto dirigido por un grupo de ingenieros de software. Cuando trabajas con un grupo de ingenieros de software, la documentación es el código.

es decir, siempre que necesite hacer algo en común con Magento, observe cómo lo ha hecho el equipo central, teniendo en cuenta que debe limitarse a observadores, anulaciones y nuevos códigos, ya que no puede discutir sus cambios con dicho equipo central.

Eche un vistazo al método IndexAction del controlador de pago de una página.

 app/code/core/Mage/Checkout/controllers/OnepageController.php public function indexAction() { if (!Mage::helper('checkout')->canOnepageCheckout()) { Mage::getSingleton('checkout/session')->addError($this->__('The onepage checkout is disabled.')); $this->_redirect('checkout/cart'); return; } ... 

Magento le permite agregar errores al objeto de sesión, que será procesado por el bloque de mensajes en la próxima solicitud.

 Mage::getSingleton('checkout/session')->addError($this->__('The onepage checkout is disabled.')); 

Eso eso maneja un error. Luego, está el redireccionamiento. Esto sucede aquí

 $this->_redirect('checkout/cart'); 

Como está llamando a este código de un observador, no tendrá acceso a este método. Sin embargo, si examina el controlador

 /** * Retrieve request object * * @return Mage_Core_Controller_Request_Http */ public function getRequest() { return $this->_request; } ... protected function _redirect($path, $arguments=array()) { $this->getResponse()->setRedirect(Mage::getUrl($path, $arguments)); return $this; } 

Puedes ver que está usando el objeto de respuesta. Magento usa un objeto de respuesta global (similar a Zend y otros marcos web) para manejar lo que se envía de vuelta al navegador (es decir, redirigir los encabezados). Puede obtener una referencia al mismo objeto a través de

 Mage::app()->getResponse() 

y podría realizar una redirección con algo como

 Mage::app()->getResponse()->setRedirect(Mage::getUrl('checkout/cart')); 

Se me ocurrió un enfoque diferente para esto, sin tener que anular el controlador. Básicamente hago lo mismo pero solo en métodos de observación. Así que estoy usando checkout_controller_onepage_save_shipping_method para validar los métodos de envío y, si hay un error, agrego ese error a una variable de sesión como la siguiente

  $error = array('error' => -1, 'message' => Mage::helper('core')->__("Message here")); Mage::getSingleton('checkout/session')->setSavedMethodError($error); 

Entonces puede, para cada acción, aplicar otro observador a 'controller_action_postdispatch_'.$this->getFullActionName()

Así que lo usé para observar controller_action_postdispatch_checkout_onepage_saveShippingMethod, que allí compruebo la variable de error de la sesión y configuro el cuerpo de la respuesta si existe.

 $error = Mage::getSingleton('checkout/session')->getSavedMethodError(); if($error){ Mage::app()->getResponse()->setBody(Mage::helper('core')->jsonEncode($error)); } Mage::getSingleton('checkout/session')->setSavedMethodError(false); 

No estoy seguro si esto es mejor o peor, así que por favor dejen cualquier comentario, pero sé que prefiero poder hacer esto sin tener que volver a escribir la clase.

Esto funciona porque está anulando el cuerpo de respuesta que se estableció en la acción saveShippingMethod.