在观察者中停止产品保存过程

时间:2011-03-24 20:57:20

标签: php magento save observer-pattern abort

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

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

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

这是工作流程

  • 管理员在产品修改页面的类别标签中选择类别
  • 管理员点击“保存”
  • 我的模块“观察”并收集所有类别

- >如果有选定的类别

  • 我的模块的观察者用它来更新Brand属性

- >其他

  • 我的模块的观察者向管理会话添加错误
  • 我的模块观察员应告诉Magento停止保存产品。但是我该怎么办?

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

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

非常感谢你的帮助,玩得开心Magentoing!

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

5 个答案:

答案 0 :(得分:15)

对于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块之外,因此不会捕获异常(如下面的注释中所述)。

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

答案 1 :(得分:2)

有几点想法。你真的想停止保存,还是“撤消”变化就足够了?如果您的观察者检测到缺少所需信息,则只需遍历已更改的数据并将其重新设置为原始数据并允许保存继续。您应该能够$product->getOrigData()比较哪些已更改?

或者,为什么不强制使用category属性?你应该能够在你的配置xml中做到这一点(不完全确定我的头脑中有多少)

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

<强> ========= EDIT =========

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

HTH,
JD

答案 2 :(得分:1)

如果您需要阻止为核心模型(即目录/产品)执行保存方法,您可以使用反射来设置&#34; $ _ dataSaveAllowed&#34;为假:

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

答案 3 :(得分:0)

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

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

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

答案 4 :(得分:0)

其中一种可能的方法也可以是这种方法 - 但这是黑客攻击

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