Differenza tra catalog_product_save_after e catalog_product_save_commit_after?


8

Qualcuno può spiegare la differenza tra questi eventi. Solo il veloce e sporco per favore. Grazie.

Ho un metodo Observer in questo modo:

public function detectProductChanges($observer)
    {
        $product = $observer->getProduct();
        $old = $product->getOrigData();
        $new = $product->getData();
        if ($product->hasDataChanges() && $old['status'] == 1 && $new['status'] == 2) {
            $this->_sendStatusMail($product);
        }
    }

Non sta arrivando al sendStatusMail()

Sto partecipando all'evento:

        <events>
            <catalog_product_save_after>
                <observers>
                    <productchange>
                        <type>singleton</type>
                        <class>A_ProductNotification_Model_Observer</class>
                        <method>detectProductChanges</method>
                    </productchange>
                </observers>
            </catalog_product_save_after>
        </events>

Dovrei usare: catalog_product_save_commit_after

OBBIETTIVO:

Ricevi un'email dopo aver disabilitato il prodotto.

private function _sendStatusMail($product)
    {
        if (!Mage::getStoreConfig('trans_email/ident_custom3/email')) return false;
        $emailTemplate = Mage::getModel('core/email_template');
        $emailTemplate->loadDefault('elec_productnotification_tpl');
        $emailTemplate->setTemplateSubject('Product has been disabled');
        $emailTemplate->setSenderEmail($salesData['email']);
        $emailTemplateVariables['style_number']   = $product->getElecStyle();
        $emailTemplateVariables['frame_color']    = $product->getAttributeText('frame_color');
        $emailTemplateVariables['size']           = $product->getAttributeText('size');
        $emailTemplateVariables['elec_color'] = $product->getAttributeText('elec_color');
        $emailTemplateVariables['store_name']   = Mage::getModel('core/store')->load($product->getStoreId())->getName();
        $emailTemplateVariables['product_name'] = Mage::getModel('catalog/product')->load($product->getId())->getName();
        $emailTemplateVariables['product_sku']  = $product->getSku();
        $emailTemplateVariables['dates']        = date("F jS Y h:i:sA", strtotime('-7 hours'));
        // Get General email address (Admin->Configuration->General->Store Email Addresses)
        $emails = explode(',', Mage::getStoreConfig('trans_email/ident_custom3/email'));
        foreach ($emails as $email) $emailTemplate->send($email, $product->getStoreId(), $emailTemplateVariables);
    }
}

dovresti usare event <catalog_product_status_update>
Nickool l'

È questa la ragione per cui non sta sparando? Semplicemente usando l'evento sbagliato? @Nickool
thismethod

Risposte:


14

Il salvataggio avviene in una transazione MySQL e l' save_afterevento viene attivato prima che la transazione venga impegnata, in modo da poter effettuare ulteriori aggiornamenti nel database all'interno della stessa transazione.

L' save_commit_afterevento viene attivato dopo il commit della transazione, ovvero quando le modifiche sono state scritte nel database.

Inoltre, on save_commit_after, la _hasDataChangesproprietà è già stata reimpostata sufalse , quindi il controllo non funzionerebbe. D'altra parte, se non ci fossero modifiche, entrambi gli eventi non verrebbero nemmeno attivati, perché Mage_Core_Model_Abstract :: save () non fa nulla se non ci sono modifiche ai dati:

if (!$this->_hasModelChanged()) {
    return $this;
}

Detto questo, non vedo perché il tuo codice non dovrebbe funzionare.


Grazie per la risposta. Quando aggiungo un Mage :: log () al posto di sendStatusMail () ottengo il messaggio di log correttamente. Ma non sta inviando e-mail. Mi sono assicurato che "Disabilita comunicazioni e-mail" sia impostato su NO e che il mio indirizzo e-mail sia nella mia e-mail personalizzata> archivia gli indirizzi e-mail. Altre idee sul perché non funziona? @fschmengler
thismethod

Senza conoscere il metodo sendStatusMail, no. Questo è probabilmente materiale per un'altra domanda. Oppure funziona lo stesso metodo se chiamato da un contesto diverso?
Fabian Schmengler,

Ho aggiornato la mia domanda originale per mostrare il metodo sendStatusMail. Se non ti dispiace aiutare ulteriormente. Grazie.
thismethod

Qualche possibilità che potresti darmi la tua opinione sul mio metodo sendStatusMail ($ product)?
thismethod

Non riesco a individuare alcun errore, mi dispiace
Fabian Schmengler,

0

vendor / magento / quadro / Modello / ResourceModel / Db / AbstractDb.php

public function save(\Magento\Framework\Model\AbstractModel $object)
{
    // ...

    $this->beginTransaction();

    try {
        // ...
        if ($object->isSaveAllowed()) {
            // ...
            $this->_beforeSave($object);
            // ...
            if ($this->isObjectNotNew($object)) {
                $this->updateObject($object);
            } else {
                $this->saveNewObject($object);
            }
            // ...
            $this->processAfterSaves($object);
        }
        $this->addCommitCallback([$object, 'afterCommitCallback'])->commit();
        // ...
    } catch (\Exception $e) {
        $this->rollBack();
        $object->setHasDataChanges(true);
        throw $e;
    }
    return $this;
}

Diamo un'occhiata al salvataggio dell'entità del prodotto.

-product_model save
|-product_resource save
|--begin transaction (0 lvl)
|---before product save events
|---creating new product or updating existing one
|---after product save events
|----one of event is saving another entity CatalogInventory Stock
|-----catalog_inventory_stock resource save
|------begin another transaction (1 lvl)
|-------before stock save events
|-------updating / creating stock item
|-------after product save events (here could be one more 
        dependable entity which could cause one more save
        operation and begin another transaction)
|------commit of 1st level !!! No callbacks executed
|--commit of 0 level ALL CALLBACKS ARE EXECUTED

Ecco il codice della funzione commit:

/**
 * Commit resource transaction
 *
 * @return $this
 * @api
 */
public function commit()
{
    $this->getConnection()->commit();
    /**
     * Process after commit callbacks
     */
    if ($this->getConnection()->getTransactionLevel() === 0) {
        $callbacks = CallbackPool::get(spl_object_hash($this->getConnection()));
        try {
            foreach ($callbacks as $callback) {
                call_user_func($callback);
            }
        } catch (\Exception $e) {
            $this->getLogger()->critical($e);
        }
    }
    return $this;
}

Diamo un'occhiata più da vicino al nostro esempio.

  1. $this->getConnection()->commit();inserisci i valori in DB per il nostro 1 ° livello (è Stock). Se succede qualcosa di brutto qui, verrà generata un'eccezione e tutte le modifiche verranno ripristinate.

  2. Quindi procede all'elaborazione dei callback. Dato che siamo attualmente al 1 ° livello, non verranno chiamati callback. E stiamo uscendo dall'evento catalog_product_after_save per eseguire il commit delle modifiche al prodotto (livello 0).

  3. $this->getConnection()->commit();inserisci i valori in DB per il nostro livello 0 (è il Prodotto stesso). Se succede qualcosa di brutto qui verrà generata anche un'eccezione e verranno ripristinate anche tutte le modifiche.

  4. Quindi stiamo passando all'esecuzione di callback. Ora siamo a livello 0 e verranno eseguiti i callback. Qualunque cosa cattiva dentro call_user_func($callback);sarà recuperata e appena registrata. Non verrà eseguito il rollback di nulla se la richiamata causa un'eccezione

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.