如何防止使用_save_before事件保存模型数据


8

我创建了一个具有自己的数据库表的模型。对于自定义,我需要触发save_before该模型的事件。

如果一个字段值不匹配,则不应保存数据。

我的主要目标是防止使用“保存前”事件保存数据

我的config.xml代码:

<?xml version="1.0" ?>
<config>
    <modules>
        <Amit_Custommodule>
            <version>1.0.0</version>
        </Amit_Custommodule>
    </modules>
    <global>
        <models>
            <custommodule>
                <class>Amit_Custommodule_Model</class>
                <resourceModel>custommodule_resource</resourceModel>
            </custommodule>
            <custommodule_resource>
                <class>Amit_Custommodule_Model_Resource</class>
                <entities>
                    <custommodule>
                        <table>custommodule</table>
                    </custommodule>
                </entities>
            </custommodule_resource>
        </models>
        <resources>
            <custommodule_setup>
                <setup>
                    <module>Amit_Custommodule</module>
                </setup>
                <connection>
                    <use>core_setup</use>
                </connection>
            </custommodule_setup>
            <custommoule_read>
                <connection>
                    <use>core_read</use>
                </connection>
            </custommoule_read>
            <custommodule_write>
                <connection>
                    <use>core_write</use>
                </connection>
            </custommodule_write>
        </resources>
        <events>
            <custommodule_save_before>
                <observers>
                    <custommodule>
                        <type>singleton</type>
                        <class>custommodule/observer</class>
                        <method>customerSaveAfter</method>
                    </custommodule>
                </observers>
            </custommodule_save_before>
    </global>


</config>

Observer.php

<?php
class Amit_Custommodule_Model_Observer
{
public function customerSaveAfter($observer){

if($observer->getEvent()->getMyfield()==MatchWithMyLogic){
}
else
{
/*  i want prevent data base if my business logic is not match here */
}


}
}

Answers:


17

如果您看一下method Mage_Core_Model_Abstract::save,则会看到以下代码块:

try {
    $this->_beforeSave();
    if ($this->_dataSaveAllowed) {
        $this->_getResource()->save($this);
        $this->_afterSave();
    }
    $this->_getResource()->addCommitCallback(array($this, 'afterCommitCallback'))
        ->commit();
    $this->_hasDataChanges = false;
    $dataCommited = true;
} catch (Exception $e) {
    $this->_getResource()->rollBack();
    $this->_hasDataChanges = true;
    throw $e;
}

_beforeSave()第二行的方法中,save_before调度事件。因此,您应该能够在观察者代码中抛出异常。这应该被上面的try-catch-block捕获,并且应该防止模型被保存。

另一种可能性是_dataSaveAllowed领域。您可以在观察者代码中将其设置为false。这将阻止模型保存。正如PHP文档所揭示的那样,该字段正是为此目的而设计的:

/**
 * Flag which can stop data saving after before save
 * Can be used for next sequence: we check data in _beforeSave, if data are
 * not valid - we can set this flag to false value and save process will be stopped
 *
 * @var bool
 */
protected $_dataSaveAllowed = true;

4
+1用于揭示$_dataSaveAllowed属性。
Rajeev K Tomy 2014年

simon,请问p @ programmer_rkt的答案,逻辑好吗?
阿米特·贝拉

为你加油...
阿米特·贝拉

1
@AmitBera觉得自己的工作有些拙劣,但我并没有真正明白这一点……请参阅我的评论。
西蒙

1
抱歉,我错过了该字段protected。我以为您可以做类似的事情$observer->getDataObject()->setDataSaveAllowed(false),但没有各自的二传手。因此,只能将这种方法与自定义模型一起使用,在该模型中可以为字段添加设置器。对于您无法控制的Magento或其他模型,请使用异常方法。
西蒙

2

如果需要阻止对核心模型(例如,目录/产品)执行save方法,则可以使用反射将“ $ _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;
}

1

您应该先尝试@Simon答案。但是,如果您仍然需要在两种情况下都进行保存,则可以使用此概念

<?php
class Amit_Custommodule_Model_Observer
{
    public function customerSaveAfter($observer)
    {

        if ($observer->getEvent()->getMyfield() == MatchWithMyLogic) {
            //do some other works
            //save data normally
        } else {
            //defines your modules model
            $model = Mage::getModel('model_alias/entity');
            //get entity id that is trying to save if any
            $id = (int)$observer->getEvent()->getEntityId();
            if ($id >= 0 ) {
                //load the correspondign model and retrieve data
                $data = $model->load($id)->getData();

                //set this value to the current object that is trying to save
                $observer->getEvent()->setData($data); 
            } else {
                //set null value for all fields for new entity
                $observer->getEvent()->setData(null);
            }
        }
    }
}

此方法的作用是,它将首先收集与将要保存的实体相对应的数据,然后使用该值设置当前数据。这导致将先前的值本身保存到数据库中。如果不存在实体ID,则表示其为新实体。因此,请为该字段保存空值

编辑

我的朋友西蒙和阿米特贝拉对此感到困惑

else {
        //set null value for all fields for new entity
        $observer->getEvent()->setData(null);
}

因此,最好对此部分进行解释。假设桌子有两个字段field_onefield_two。在这种情况下,对于新实体(意味着该实体在数据库中没有条目),我们可以像这样设置这些值。

 $observer->getEvent()->setEntityOne('');
  $observer->getEvent()->setEntityTwo('');

这将清除传递的值并设置为空值。因此,在保存操作期间,此空值将存储在数据库中。

考虑一下我要传达的想法,请不要根据我提供的演示代码来判断:)


您能再解释一下吗?我不太明白这一点。基本思想是,当您将数据设置为null时,将不会保存任何内容?
西蒙

1
这是before_save行动。必须采取手段saveaftersave行动。因此,编辑后的实体可能已经存在于数据库中,也可能是新实体。如果已编辑实体在数据库中具有条目,我们将获取该值并设置这些值,而不是实体/对象当前持有的已更改值。因此,当执行保存操作时,现在设置的值就是先前的值本身。这不会更新表值。表示保存以前的值。
Rajeev K Tomy 2014年

对于新实体,意味着这些实体在数据库中没有条目,我们设置空值,而不是使用该实体当前持有的初始值。这将在数​​据库中创建一个新条目,其中所有字段的值为空。如果setData(null)没有奏效,我想setData(array())可能会奏效(空数组)。它只是一个逻辑
拉杰夫ķ和Tomy

@西蒙:你明白我的意思了吗?
拉杰夫K Tomy 2014年

2
是的,我做到了,谢谢。感觉有点。并且它可以保存虚拟实体,这不是期望的行为。
西蒙

0

这可能不仅影响您要防止保存的客户对象,还可以在观察者中执行此操作,以防止将保存应用到数据库中。

$customer->getResource()->rollBack();
Mage::throwException('Invalid customer account information');

单独抛出的异常不会做,因此您必须尝试使用​​InnoDB回滚事务。但是,可能不仅仅在该交易中修改/创建了该客户帐户,因此请谨慎使用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.