Unterschied zwischen catalog_product_save_after und catalog_product_save_commit_after?

8

Kann jemand den Unterschied zwischen diesen Ereignissen erklären. Nur das schnelle und dreckige bitte. Vielen Dank.

Ich habe eine Observer-Methode wie folgt:

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

Es kommt nicht zum sendStatusMail()

Ich bin an der Veranstaltung beteiligt:

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

Sollte ich verwenden: catalog_product_save_commit_after

TOR:

Lassen Sie sich eine E-Mail senden, nachdem das Produkt deaktiviert wurde.

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);
    }
}
diese Methode
quelle
Sie sollten Ereignis verwenden <catalog_product_status_update>
Nickool
Ist das der Grund, warum es nicht feuert? Einfach das falsche Ereignis verwenden? @ Nickool
Methode

Antworten:

14

Das Speichern erfolgt in einer MySQL-Transaktion und das save_afterEreignis wird ausgelöst, bevor die Transaktion festgeschrieben wird, sodass Sie innerhalb derselben Transaktion zusätzliche Aktualisierungen in der Datenbank vornehmen können.

Das save_commit_afterEreignis wird ausgelöst, nachdem die Transaktion festgeschrieben wurde, dh als die Änderungen in die Datenbank geschrieben wurden.

Außerdem wurde save_commit_afterdie _hasDataChangesEigenschaft bereits auf zurückgesetzt false, sodass Ihre Prüfung nicht funktioniert. Wenn es keine Änderungen gäbe, würden beide Ereignisse nicht einmal ausgelöst, da Mage_Core_Model_Abstract :: save () nichts tut, wenn es keine Datenänderungen gäbe:

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

Davon abgesehen verstehe ich nicht, warum Ihr Code nicht funktionieren sollte.

Fabian Schmengler
quelle
Danke für die Antwort. Wenn ich anstelle von sendStatusMail () ein Mage :: log () hinzufüge, erhalte ich die Protokollmeldung korrekt. Aber es werden keine E-Mails gesendet. Ich habe sichergestellt, dass "E-Mail-Kommunikation deaktivieren" auf NEIN gesetzt ist und dass sich meine E-Mail-Adresse in meiner benutzerdefinierten E-Mail-Adresse> E-Mail-Adressen speichern befindet. Irgendwelche anderen Ideen, warum es nicht funktioniert? @ Fschmengler
Methode
Ohne Ihre sendStatusMail-Methode zu kennen, nein. Das ist wahrscheinlich Material für eine andere Frage. Oder funktioniert dieselbe Methode, wenn sie aus einem anderen Kontext aufgerufen wird?
Fabian Schmengler
Ich habe meine ursprüngliche Frage aktualisiert, um die sendStatusMail-Methode anzuzeigen. Wenn es Ihnen nichts ausmacht, weiter zu helfen. Vielen Dank.
Methode
Gibt es eine Chance, dass Sie mir Ihre Meinung zu meiner sendStatusMail-Methode ($ product) mitteilen?
Methode
Ich kann dort keine Fehler erkennen, sorry
Fabian Schmengler
0

Anbieter / Magento / Framework / Model / 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;
}

Lassen Sie uns einen Blick auf das Speichern der Produktentität werfen.

-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

Hier ist der Code der Festschreibungsfunktion:

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

Schauen wir uns unser Beispiel genauer an.

  1. $this->getConnection()->commit();Geben Sie Werte in die DB für unser 1. Level ein (es ist Stock). Wenn hier etwas Schlimmes passiert, wird eine Ausnahme ausgelöst und alle Änderungen werden zurückgesetzt.

  2. Dann werden Rückrufe verarbeitet. Da wir uns derzeit auf der 1. Ebene befinden, werden keine Rückrufe aufgerufen. Und wir verlassen das Ereignis catalog_product_after_save, um Produktänderungen (Stufe 0) festzuschreiben.

  3. $this->getConnection()->commit();Geben Sie Werte für unsere 0-Ebene in die Datenbank ein (es ist das Produkt selbst). Wenn hier etwas Schlimmes passiert, wird auch eine Ausnahme ausgelöst und alle Änderungen werden ebenfalls zurückgesetzt.

  4. Dann gehen wir zur Ausführung von Rückrufen über. Jetzt sind wir auf 0 und Rückrufe werden ausgeführt. Alles, was Sie drinnen schlecht call_user_func($callback);finden, wird eingeholt und nur protokolliert. Nichts wird zurückgesetzt, wenn ein Rückruf eine Ausnahme verursacht

zhartaunik
quelle