【问题标题】:Stopping product saving process in observer在观察者中停止产品保存过程
【发布时间】:2011-07-22 11:27:09
【问题描述】:

我目前正在开发一个与后端产品编辑一起使用的模块。 其目的是检索产品所属的类别并使用所选类别列表填充属性(品牌属性)。

管理员必须至少选择一个类别。

我的模块按预期工作,只是如果管理员在编辑产品时没有选择任何类别,我不知道如何停止保存过程。

这是工作流程

  • 管理员在产品编辑页面的类别选项卡中选择类别
  • 管理员点击“保存”
  • 我的模块“观察”并收集所有类别

--> 如果有选择的类别

  • 我的模块的观察者会做自己的事情来更新品牌属性

--> 否则

  • 我的模块的观察者在管理会话中添加了一个错误
  • 我的模块的观察者应该告诉 Magento 停止保存产品。但是我该怎么做呢?

一般问题可能是:如何将“停止保存”参数传递给观察者?

这是我的 config.xml 文件的示例以及处理我上面解释的工作流的方法。

非常感谢您的帮助,祝您玩得开心!

config.xml

    <catalog_product_prepare_save>
        <observers>
            <brands_product_save_observer>
                <type>singleton</type>
                <class>brands/observer</class>
                <method>saveProductBrand</method>
            </brands_product_save_observer>
        </observers>
    </catalog_product_prepare_save>

Observer.php

public function saveProductBrand($observer) {
    $product = $observer->getProduct();
    $categoryIds = $product->getCategoryIds();
    if (isset($categoryIds)) {
        foreach ($categoryIds as $categoryId) {
            $isBrandCategory = Mage::getModel('brands/navigation')->isBrandCategory($categoryId);
            if ($isBrandCategory)
                $brandCategories[] = $categoryId;
        }
        if (isset($brandCategories)) {
            $brandId = Mage::getModel('brands/navigation')->getBrand($brandCategories[0]);
            if ($brandId) {
                $attribute = Mage::getModel('eav/config')->getAttribute('catalog_product', 140);
                foreach ($attribute->getSource()->getAllOptions(true, true) as $option) {
                    $attributeArray[$option['label']] = $option['value'];
                }
                $categoryName = Mage::getModel('catalog/category')->load($brandId)->getName();
                $product->setData('brand', $attributeArray[$categoryName]);
            }
        } else {
            Mage::getSingleton('adminhtml/session')->addError(Mage::helper('catalog')->__('Please add this product to a brand in the "Categories" tab.'));

            HERE SOME CODE TO TELL MAGENTO TO STOP SAVING THE PRODUCT

            return;
        }
    }
}

【问题讨论】:

    标签: php magento save observer-pattern abort


    【解决方案1】:

    我认为你不能通过观察者以你想要的方式停止执行,Magento 不会关注你可能通过观察者返回或设置的任何内容。

    一个想法是重写产品模型的保存方法。您可以检查您在观察者中设置的任何错误标志,然后从那时起阻止保存。像这样的:

    function save()
    {
        if( $error_detection )
        {
            return $this;
        }
        else
        {
            return parent::save();
        }
    }
    

    【讨论】:

    • 我会非常警惕重写 Product 模型...许多自定义模块会重写该模型,最终导致大量冲突。尽可能避免!
    • 是的,这是一个很好的观点。这只是想到的第一个想法,因为我认为 Magento 在这种情况下不会捕获抛出的异常。虽然我可能错了。
    • 我也同意,不会走那条路:)
    【解决方案2】:

    关于 Magento 的哪些部分支持这一点总是一个废话,但抛出异常通常是告诉 Magento 出现问题的规定方式。堆栈较高的层设置为捕获这些异常并使用它们返回表单并显示错误消息。试试这个

    Mage::throwException(Mage::helper('adminhtml')->__('You totally failed at that.'));
    

    如果您查看 Adminhtml 模块的 Catalog/ProductController.php(1.5,但我会假设在以前的版本中采用类似的格式)

    function saveAction()
    {
        ...
        $product = $this->_initProductSave();
    
        try {
            $product->save();
            $productId = $product->getId();
        ...
    }
    

    _initProductSave 方法是触发catalog_product_prepare_save 事件的地方。由于这在 saveAction 的 try/catch 块之外,因此不会捕获异常(如下面的 cmets 所述)。

    您需要将验证代码移动到产品模型的保存前事件 (catalog_product_save_before)。这样做应该让您抛出异常并让管理员显示错误消息并表示要编辑的表单。

    【讨论】:

    • 绝对值得一试。我查看了 Mage_Catalog_Model_Product 的 _beforeSave() 方法、它的父类和关联的资源类,在继续保存之前它们没有检查任何异常:(
    • 伙计们,我试过了,但它“失败了”,因为它在漂亮的错误报告页面上抛出异常,而不是重新加载带有“你完全失败”消息的产品编辑页面。无论如何,非常感谢。如果我成功了,我会继续挖掘并告诉你!
    • @vrnet 我进一步研究了这个问题,并用更多信息更新了答案。如果您将验证移动到 catalog_product_save_before 事件,您应该被设置。
    • vrnet::getHappiness('掌声')->thankAlanTonsOfTimes(); - 伙计,这是巨大的!非常感谢!唯一的纳米缺点是重新加载时不会保留产品版本中的数据。管理员必须重新输入所有信息......他/她会小心下一个产品:) 再次感谢。
    • @vrnet 要保留数据,您可以在模型中抛出异常之前调用Mage::getSingleton('adminhtml/session')-&gt;set[MODULE]Data($this-&gt;getData());,然后在Form.php 中_prepareForm 函数的末尾调用$form-&gt;setValues(Mage::getSingleton('adminhtml/session')-&gt;get[MODULE]Data());
    【解决方案3】:

    一些想法。您真的要停止保存,还是“撤消”更改就足够了?如果您的观察者检测到缺少所需的信息,则只需遍历更改的数据并将其设置回原始数据并允许保存继续。您应该可以通过$product-&gt;getOrigData() 来比较哪个发生了变化?

    另外,为什么不强制类别属性?你应该可以在你的配置 xml 中做到这一点(不完全确定我的想法)

    最后,您可以改为绑定到controller_action_predispatch_catalog_product_save 事件,如果您检测到错误状态,设置no-dispatch 标志,将您的错误消息添加到会话和redirectReferrer。查看我之前的回答here 了解详情。

    =========编辑=========

    我找到了一种新方法。在您的观察者中,将对象上的_dataSaveAllowed 值更改为falseMage_Core_Model_Abstract::save() 在继续保存之前检查该值。

    HTH,
    京东

    【讨论】:

    • 嘿乔纳森 - 非常感谢,但似乎 Magento 并不关心不派送。我已经转储了 Mage::app()->getFrontController()->getAction()->getFlag($action) 并且它正确返回 Array ( [save] => Array ( [check_url_settings] => 1 [no-dispatch ] => 1))。但是产品保存仍然发生...... Arg.
    【解决方案4】:

    其中一种可能的方法也可以是这种方法 - 虽然它是一种 hack

    Mage::app()-&gt;getRequest()-&gt;setPost("YOUR_KEY",false);

    【讨论】:

      【解决方案5】:

      如果您需要阻止对核心模型(即目录/产品)执行保存方法,您可以使用反射将“$_dataSaveAllowed”设置为 false:

      public function catalogProductSaveBefore($observer)
      {
          try {
              $product = $observer->getProduct();
      
              $reflectionClass = new ReflectionClass('Mage_Catalog_Model_Product');
              $reflectionProperty = $reflectionClass->getProperty('_dataSaveAllowed');
              $reflectionProperty->setAccessible(true);
              $reflectionProperty->setValue($product, false);
          } catch (Exception $e) {
                  Mage::log($e->getMessage());
          }
      
          return $this;
      }
      

      【讨论】:

        猜你喜欢
        • 2014-07-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-23
        相关资源
        最近更新 更多