catalog_product_save_after와 catalog_product_save_commit_after의 차이점은 무엇입니까?

magento.stackexchange https://magento.stackexchange.com/questions/120004

문제

누구든지 이러한 이벤트의 차이점을 설명할 수 있습니까?빠르고 더러운 것만 부탁합니다.감사합니다.

다음과 같은 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);
    }
}
도움이 되었습니까?

해결책

저장은 MySQL 트랜잭션에서 발생하고 트랜잭션이 커밋되기 전에 save_after 이벤트가 트리거되므로 동일한 트랜잭션 내에서 데이터베이스에서 추가 업데이트를 수행할 수 있습니다.

save_commit_after 이벤트는 트랜잭션이 커밋된 후, 즉 변경 사항이 데이터베이스에 기록되었을 때 트리거됩니다.

또한 save_commit_after에서 _hasDataChanges 속성은 이미 false로 재설정되었으므로 검사가 작동하지 않습니다.반면에 변경 사항이 없으면 두 이벤트 모두 트리거되지 않습니다. 데이터 변경 사항이 없으면 Mage_Core_Model_Abstract::save()이 아무 것도 하지 않기 때문입니다.

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

즉, 귀하의 코드가 작동하지 않아야 하는 이유를 모르겠습니다.

다른 팁

공급업체/마젠토/프레임워크/모델/리소스 모델/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 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();는 우리의 첫 번째 수준(주식)에 대한 값을 DB에 넣습니다.여기서 나쁜 일이 발생하면 예외가 발생하고 모든 변경 사항이 롤백됩니다.

  2. 그런 다음 콜백을 처리합니다.현재 1단계이므로 콜백이 호출되지 않습니다.그리고 제품 변경 사항(0 레벨)을 커밋하기 위해 catalog_product_after_save 이벤트에서 이동합니다.

  3. $this->getConnection()->commit();는 0 레벨(제품 자체)에 대한 값을 DB에 넣습니다.여기서 나쁜 일이 발생하면 예외도 발생하고 모든 변경 사항도 롤백됩니다.

  4. 그런 다음 콜백 실행으로 이동합니다.이제 우리는 0 레벨에 있고 콜백이 실행될 것입니다.call_user_func($callback); 내부에서 당신이 나쁜 것은 무엇이든 따라잡혀서 기록될 것입니다.콜백으로 인해 예외가 발생하면 아무 것도 롤백되지 않습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 magento.stackexchange
scroll top