8

I have create a model which has its own database table. For a customization I need to trigger save_before event of this model.

If one field value is not matched, then the data should not be saved.

My main target is preventing data save using "before save" event

My config.xml code:

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


}
}
17

If you have a look at the method Mage_Core_Model_Abstract::save, you see this code block:

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

In the _beforeSave() method in the second line, the save_before event is dispatched. Hence, you should be able to just throw an exception in your observer code. This should be catched by the try-catch-block above and should prevent the model to save.

Another possibility is the _dataSaveAllowed field. You can set it to false in your observer code. This will prevent the model to save. And this field is exactly designed for this purpose as the PHP doc reveals:

/**
 * 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 for revealing $_dataSaveAllowed property. – Rajeev K Tomy Sep 2 '14 at 6:11
  • simon,can you please check p@programmer_rkt answer,is good logic? – Amit Bera Sep 2 '14 at 6:19
  • upvote for u ... – Amit Bera Sep 2 '14 at 6:26
  • 1
    @AmitBera Feels a bit hacky what he does and I do not really get the point... See my comment. – Simon Sep 2 '14 at 6:29
  • 1
    Ah sorry, I missed that the field is protected. I thought that you can do something like $observer->getDataObject()->setDataSaveAllowed(false), but there is no respective setter. Hence, you can only use this approach with a custom model where you can add a setter for the field. For Magento or other models you do not control, use the exception approach. – Simon Sep 2 '14 at 8:03
2

In case you need to prevent the save method to execute for a core model (i.e. Catalog/Product), you can use reflection to set "$_dataSaveAllowed" to 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

You should try @Simon answer first. But if you need to still go for save in both condition, then you can use this cocept

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

What this method does is, it will first collect data that is correspond to the entity that is going to save and then set current data with that value. This results into save the previous value itself into the database. If there is no entity id present, that means its a new entity. So save null values for that field

EDIT

My friends Simon and AmitBera got confused on this part

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

So it would be good to explain this part little bit. Suppose the table has two fiels field_one and field_two. In that case, for a new entity (means this has no entry in database), we can set those values like this.

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

This will erase the value that passed and set null value. So during save action, this empty values will be stored in database.

Take idea that I am trying to convey and please don't judge on the basis of demo code that I have provided :)

  • Could you explain it a bit further? I do not really get the point. The base idea is that when you set the data to null, nothing will be saved? – Simon Sep 2 '14 at 6:28
  • 1
    this is before_save action. Means save and aftersave actions has to take place. So edited entity may be already existing one in database or a new one. If edited entity has an entry in database, we will get that values and set those values instead of changed values that are currently hold by the entity/object. so when save action takes place, the value set now is previous value itself. This makes no table value updation. Means previous values get saved. – Rajeev K Tomy Sep 2 '14 at 6:34
  • for new entities, means those has no entry in database, instead of using initial values that are currently hold by that entity, we set null values. This will make a new entry in database with all field has null value in it. if setData(null) didnt work, I guess setData(array()) may work (null array). Its just a logic – Rajeev K Tomy Sep 2 '14 at 6:38
  • @Simon : did you get my point ? – Rajeev K Tomy Sep 2 '14 at 6:38
  • 2
    Yes, I did, thanks. Feels a bit hacky. And it may save a dummy entity which is not the desired behaviour. – Simon Sep 2 '14 at 6:44
0

This may affect more than just the customer object you're trying to prevent from saving, but you can do this in your observer to prevent the save from being applied in the database.

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

The thrown exception alone won't do it, so you must attempt to rollback the transaction with InnoDB. However, there might be more than just this customer account being modified/created in that transaction, so use this with caution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.