【问题标题】:What is the correct way to stop a checkout from an event observer in Magento?在 Magento 中停止事件观察者结帐的正确方法是什么?
【发布时间】:2011-06-11 09:28:16
【问题描述】:

我在事件 checkout_controller_onepage_save_shipping_method 期间验证运输报价,如果验证失败,我想将用户发送回运输方式选择,但我还想显示一条消息,说明失败的原因。 Magento 有内置的方法吗?

我已经在验证数据,只是缺少对运输方式的重定向和显示消息的方式。

【问题讨论】:

    标签: php magento


    【解决方案1】:

    (这些都不是经过测试的代码,但这些概念应该可以让你到达你需要去的地方)

    Magento 是由一群软件工程师运行的项目。当您与一群软件工程师一起工作时,文档就是代码。

    即每当您需要做一些与 Magento 共同的事情时,请观察核心团队是如何做到的,考虑到您应该将自己限制为观察者、覆盖和新代码,因为您无法与核心团队讨论您的更改。

    看看单页结账控制器的IndexAction方法

    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 允许您向会话对象添加错误,这些错误将在下一个请求时由消息块处理。

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

    处理错误的那个。接下来是重定向。这发生在这里

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

    由于您是从观察者调用此代码,因此您将无权访问此方法。但是,如果您检查控制器

    /**
     * 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;
    }
    

    你可以看到它使用响应对象。 Magento 使用全局响应对象(类似于 Zend 和其他 Web 框架)来处理发送回浏览器的内容(即重定向标头)。您可以通过

    获得对同一对象的引用
    Mage::app()->getResponse()
    

    并且可以使用类似的东西执行重定向

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

    【讨论】:

    • 查看下面的答案,上面的方法可能适用于一页结帐的 ajax 系统流程。
    • 对于任何人复制/粘贴 - Mage::app()->getResponse()->setRedirct(Mage::getUrl('checkout/cart')); 应该是 Mage::app()->getResponse()->setRedirect(Mage::getUrl('checkout/cart')); 我会编辑,但它少于 6 个字符。谢谢艾伦!
    【解决方案2】:

    为此我想出了一种不同的方法,而不必覆盖控制器。基本上我做同样的事情,但只是在观察者方法中。所以我也使用 checkout_controller_onepage_save_shipping_method 来验证运输方式,如果出现错误,我会将该错误添加到如下所示的会话变量中

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

    然后你可以为每个动作应用另一个观察者'controller_action_postdispatch_'.$this->getFullActionName()

    所以我用它来观察 controller_action_postdispatch_checkout_onepage_saveShippingMethod 在那里我检查会话错误变量并设置响应正文(如果存在)。

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

    我不确定这是好是坏,所以请留下任何 cmets,但我知道我希望能够做到这一点而无需对课程进行任何重写。

    这是有效的,因为您正在覆盖在 saveShippingMethod 操作中设置的响应正文。

    【讨论】:

    • 我之前使用过类似的方法,虽然我使用了 Mage::register()/Mage::registry() 方法而不是在会话中设置。但是你真的必须小心这种做事的方式。主要问题是常规方法也在修改会话中的数据。例如这个 sn-p 在 saveShippingMethodAction()... $this->getCheckout() ->setStepData('shipping_method', 'complete', true) ->setStepData('payment', 'allow', true) ;
    【解决方案3】:

    Alan Storm 的回答一如既往,内容丰富且富有启发性。但在这种情况下,单页结帐主要是 AJAX,它会忽略会话错误消息,直到离开结帐页面后您才会看到它。

    saveShippingMethodAction 中有以下行:

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

    ...然后 $result 是 JSON 编码的。如果您覆盖 Mage_Checkout_Model_Type_Onepage::saveShippingMethod 来执行检查,然后控制返回的内容,您可以插入一条错误消息,该消息将返回给浏览器并在弹出窗口中显示给用户。

    您的覆盖可能如下所示:

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

    【讨论】:

    • 啊,我误读了 OP 连接到哪个事件。我以为这是最后的提交。我的直觉认为,仍然有一种方法可以在没有覆盖的情况下执行此操作,尽管如果您不重新分发代码,覆盖可能是最好的前进路径。
    • 很遗憾,我正在重新分发代码 :( 这是运输提供商提供给客户的模块
    • @rennat:这不是我所说的再分配的意思。你把这个给客户。这意味着您与他们有现有的关系,并且如果他们有另一个模块也试图覆盖您的功能,那么您可以帮助他们解决这个问题。此外,仅仅因为已经得出结论,不应该在可再发行代码中使用类覆盖,这并没有阻止扩展开发人员这样做。
    猜你喜欢
    • 2011-01-04
    • 2012-02-03
    • 2014-09-24
    • 1970-01-01
    • 2012-10-19
    • 2022-01-10
    • 1970-01-01
    • 2012-09-08
    • 1970-01-01
    相关资源
    最近更新 更多