catalog_product_save_after和catalog_product_save_commit_after之间的区别?


8

任何人都可以解释这些事件之间的区别。请快速而肮脏。谢谢。

我有一个类似的Observer方法:

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

没到 sendStatusMail()

我很喜欢这个事件:

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

我应该使用: catalog_product_save_commit_after

目标:

禁用产品后发送电子邮件。

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

您应该使用事件 <catalog_product_status_update>
Nickool,2013年

这是它不点火的原因吗?只是使用错误的事件?@Nickool
方法

Answers:


14

保存发生在MySQL事务中,并且在save_after提交事务之前触发了该事件,因此您可以在同一事务中对数据库进行其他更新。

save_commit_after交易一直致力于后触发事件,即当变化写入数据库。

此外,在上save_commit_after,该_hasDataChanges属性已被重置为false,因此您的检查将无法进行。另一方面,如果没有更改,则两个事件都不会被触发,因为如果没有数据更改,Mage_Core_Model_Abstract :: save()不会执行任何操作:

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

话虽如此,我不明白为什么您的代码不起作用。


谢谢你的回答。当我添加Mage :: log()代替sendStatusMail()时,我会正确获取日志消息。但这不是发送电子邮件。我确保将“禁用电子邮件通信”设置为“否”,并且我的电子邮件地址在我的自定义电子邮件>存储电子邮件地址中。还有其他想法为什么不起作用?@fschmengler
thismethod

不知道您的sendStatusMail方法,不。这可能是另一个问题的实质。还是从不同的上下文调用相同的方法?
Fabian Schmengler 2016年

我更新了原始问题,以显示sendStatusMail方法。如果您不介意进一步协助。谢谢。
方法

您是否有机会对我的sendStatusMail($ product)方法发表意见?
方法

很抱歉,我无法发现任何错误
Fabian Schmengler

0

供应商/ magento /框架/模型/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;
}

让我们看一下保存产品实体。

-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

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

让我们更仔细地看一下我们的例子。

  1. $this->getConnection()->commit();将价值放入我们第1级的库存(即库存)。如果此处发生不良情况,将引发异常并回滚所有更改。

  2. 然后处理回调。由于我们目前处于第一级,因此不会调用任何回调。我们正在从catalog_product_after_save事件移出以提交产品更改(0级)。

  3. $this->getConnection()->commit();将0级别的值放入数据库(这是产品本身)。如果发生什么不好的事情,这里也会抛出异常,所有更改也将被回滚。

  4. 然后我们转向回调执行。现在我们处于0级别,将运行回调。您内部的任何不良情况call_user_func($callback);都会被追上并记录下来。如果回调导致异常,则不会回滚任何内容

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.