Cómo evitar que un modelo guarde datos usando el evento _save_before

8

He creado un modelo que tiene su propia tabla de base de datos. Para una personalización, necesito activar el save_beforeevento de este modelo.

Si un valor de campo no coincide, los datos no deberían guardarse.

Mi objetivo principal es evitar el almacenamiento de datos mediante el evento "antes de guardar"

Mi código 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 */
}


}
}
Amit Bera
fuente

Respuestas:

17

Si observa el método Mage_Core_Model_Abstract::save, verá este bloque de código:

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

En el _beforeSave()método de la segunda línea, save_beforese distribuye el evento. Por lo tanto, debería poder lanzar una excepción en su código de observador. Esto debería ser detectado por el bloque try-catch-above y debería evitar que el modelo se guarde.

Otra posibilidad es el _dataSaveAllowedcampo. Puede establecerlo en falso en su código de observador. Esto evitará que el modelo se guarde. Y este campo está exactamente diseñado para este propósito como revela el documento 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;
Simón
fuente
44
+1 por revelar $_dataSaveAllowedpropiedad.
Rajeev K Tomy
Simon, ¿puedes comprobar p @ programmer_rkt respuesta, es buena lógica?
Amit Bera
voto a favor para ti ...
Amit Bera
1
@AmitBera Siente un poco hacky lo que hace y realmente no entiendo el punto ... Ver mi comentario.
Simon
1
Ah lo siento, me perdí que el campo es protected. Pensé que puedes hacer algo como $observer->getDataObject()->setDataSaveAllowed(false), pero no hay un setter respectivo. Por lo tanto, solo puede usar este enfoque con un modelo personalizado en el que puede agregar un setter para el campo. Para Magento u otros modelos que no controle, use el enfoque de excepción.
Simon
2

En caso de que necesite evitar que el método de guardar se ejecute para un modelo central (es decir, Catálogo / Producto), puede usar la reflexión para establecer "$ _dataSaveAllowed" en falso:

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;
}
José Romero
fuente
1

Deberías intentar @Simon responder primero. Pero si aún necesita ir a guardar en ambas condiciones, puede usar este 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);
            }
        }
    }
}

Lo que hace este método es que primero recopilará los datos que corresponden a la entidad que va a guardar y luego establecerá los datos actuales con ese valor. Esto resulta en guardar el valor anterior en la base de datos. Si no hay una identificación de entidad presente, eso significa que es una nueva entidad. Así que guarde valores nulos para ese campo

EDITAR

Mis amigos Simon y AmitBera se confundieron en esta parte.

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

Por lo tanto, sería bueno explicar esta parte un poco. Supongamos que la mesa tiene dos campos field_oney field_two. En ese caso, para una nueva entidad (significa que no tiene entrada en la base de datos), podemos establecer esos valores de esta manera.

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

Esto borrará el valor que pasó y establecerá un valor nulo. Entonces, durante la acción de guardar, estos valores vacíos se almacenarán en la base de datos.

Tome la idea de que estoy tratando de transmitir y por favor no juzgue sobre la base del código de demostración que he proporcionado :)

Rajeev K Tomy
fuente
¿Podría explicarlo un poco más? Realmente no entiendo el punto. La idea base es que cuando establezca los datos en nulo, ¿no se guardará nada?
Simon
1
Esto es before_saveacción. Los medios savey las aftersaveacciones tienen que tener lugar. Por lo tanto, la entidad editada puede ser una existente en la base de datos o una nueva. Si la entidad editada tiene una entrada en la base de datos, obtendremos esos valores y estableceremos esos valores en lugar de los valores modificados que actualmente posee la entidad / objeto. así que cuando se lleva a cabo la acción de guardar, el valor establecido ahora es el valor anterior en sí Esto no actualiza el valor de la tabla. Significa que los valores anteriores se guardan.
Rajeev K Tomy
para las nuevas entidades, significa que las que no tienen entrada en la base de datos, en lugar de usar valores iniciales que esa entidad posee actualmente, establecemos valores nulos. Esto hará que una nueva entrada en la base de datos con todos los campos tenga un valor nulo. si no setData(null)funcionó, supongo que setData(array())puede funcionar (matriz nula). Es solo una lógica
Rajeev K Tomy
@ Simon: ¿entendiste mi punto?
Rajeev K Tomy
2
Sí, lo hice, gracias. Se siente un poco hacky. Y puede salvar una entidad ficticia que no es el comportamiento deseado.
Simon
0

Esto puede afectar más que solo el objeto del cliente que está tratando de evitar que guarde , pero puede hacerlo en su observador para evitar que el guardado se aplique en la base de datos.

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

La excepción lanzada por sí sola no lo hará, por lo que debe intentar deshacer la transacción con InnoDB. Sin embargo, puede haber algo más que esta cuenta de cliente modificada / creada en esa transacción, así que use esto con precaución.

Tyler V.
fuente