Comment empêcher l'enregistrement des données d'un modèle à l'aide de l'événement _save_before

8

J'ai créé un modèle qui a sa propre table de base de données. Pour une personnalisation, je dois déclencher un save_beforeévénement de ce modèle.

Si une valeur de champ ne correspond pas, les données ne doivent pas être enregistrées.

Mon objectif principal est d'empêcher l'enregistrement des données à l'aide de l'événement "avant l'enregistrement"

Mon code 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
la source

Réponses:

17

Si vous regardez la méthode Mage_Core_Model_Abstract::save, vous voyez ce bloc de code:

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

Dans la _beforeSave()méthode de la deuxième ligne, l' save_beforeévénement est distribué. Par conséquent, vous devriez pouvoir simplement lancer une exception dans votre code d'observateur. Cela devrait être rattrapé par le bloc try-catch ci-dessus et devrait empêcher le modèle de sauvegarder.

Une autre possibilité est le _dataSaveAllowedchamp. Vous pouvez le définir sur false dans votre code d'observateur. Cela empêchera le modèle de sauvegarder. Et ce champ est exactement conçu à cet effet, comme le révèle le document 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;
Simon
la source
4
+1 pour révéler la $_dataSaveAllowedpropriété.
Rajeev K Tomy
Simon, pouvez-vous vérifier la réponse de p @ programmer_rkt, est-ce une bonne logique?
Amit Bera
vote positif pour u ...
Amit Bera
1
@AmitBera Sent un peu hacky ce qu'il fait et je ne comprends pas vraiment le point ... Voir mon commentaire.
Simon
1
Ah désolé, j'ai raté le terrain protected. Je pensais que vous pouvez faire quelque chose comme ça $observer->getDataObject()->setDataSaveAllowed(false), mais il n'y a pas de setter respectif. Par conséquent, vous ne pouvez utiliser cette approche qu'avec un modèle personnalisé dans lequel vous pouvez ajouter un setter pour le champ. Pour Magento ou d'autres modèles que vous ne contrôlez pas, utilisez l'approche d'exception.
Simon
2

Dans le cas où vous devez empêcher l'exécution de la méthode de sauvegarde pour un modèle principal (c.-à-d. Catalogue / produit), vous pouvez utiliser la réflexion pour définir "$ _dataSaveAllowed" sur 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;
}
José Romero
la source
1

Vous devez d'abord essayer la réponse @Simon. Mais si vous devez continuer à économiser dans les deux conditions, vous pouvez utiliser ce 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);
            }
        }
    }
}

Ce que fait cette méthode, c'est qu'elle va d'abord collecter des données qui correspondent à l'entité qui va enregistrer, puis définir les données actuelles avec cette valeur. Cela se traduit par enregistrer la valeur précédente elle-même dans la base de données. Si aucun identifiant d'entité n'est présent, cela signifie que c'est une nouvelle entité. Enregistrez donc les valeurs nulles pour ce champ

ÉDITER

Mes amis Simon et AmitBera se sont trompés sur cette partie

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

Il serait donc bon d'expliquer cette partie un peu. Supposons que la table ait deux champs field_oneet field_two. Dans ce cas, pour une nouvelle entité (cela signifie qu'elle n'a pas d'entrée dans la base de données), nous pouvons définir ces valeurs comme ceci.

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

Cela effacera la valeur transmise et définira la valeur nulle. Ainsi, pendant l'action d'enregistrement, ces valeurs vides seront stockées dans la base de données.

Prenez l'idée que j'essaie de transmettre et s'il vous plaît ne jugez pas sur la base du code de démonstration que j'ai fourni :)

Rajeev K Tomy
la source
Pourriez-vous l'expliquer un peu plus loin? Je ne comprends pas vraiment le point. L'idée de base est que lorsque vous définissez les données sur null, rien ne sera enregistré?
Simon
1
c'est l' before_saveaction. Des moyens saveet des aftersaveactions doivent avoir lieu. L'entité éditée peut donc être déjà existante dans la base de données ou une nouvelle. Si l'entité modifiée a une entrée dans la base de données, nous obtiendrons ces valeurs et définirons ces valeurs au lieu des valeurs modifiées qui sont actuellement détenues par l'entité / l'objet. donc quand une action de sauvegarde a lieu, la valeur définie maintenant est la valeur précédente elle-même. Cela ne fait aucune mise à jour de la valeur de la table. Signifie que les valeurs précédentes sont enregistrées.
Rajeev K Tomy
pour les nouvelles entités, cela signifie qu'elles n'ont pas d'entrée dans la base de données, au lieu d'utiliser des valeurs initiales actuellement détenues par cette entité, nous définissons des valeurs nulles. Cela fera une nouvelle entrée dans la base de données avec tous les champs ayant une valeur nulle. si cela setData(null)n'a pas fonctionné, je suppose que cela setData(array())peut fonctionner (tableau nul). C'est juste une logique
Rajeev K Tomy
@Simon: avez-vous compris mon point?
Rajeev K Tomy
2
Oui, je l'ai fait, merci. Sent un peu hacky. Et cela peut sauver une entité factice qui n'est pas le comportement souhaité.
Simon
0

Cela peut affecter plus que l'objet client que vous essayez d'empêcher d'enregistrer , mais vous pouvez le faire dans votre observateur pour empêcher l'application de l'enregistrement dans la base de données.

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

L'exception levée seule ne le fera pas, vous devez donc essayer d'annuler la transaction avec InnoDB. Cependant, il peut y avoir plus que ce compte client en cours de modification / création dans cette transaction, alors utilisez-le avec prudence.

Tyler V.
la source