Magento schlägt fehl, wenn versucht wird, das Produkt im Event Observer auf dem Frontend zu speichern?

15

Ich habe eine Funktion, die an einen Ereignisbeobachter gebunden ist

Eine der Anforderungen ist, dass beim Durchlaufen der Bestellpositionsdaten, wenn ein bestimmtes Produktattribut leer ist, eine Anforderung ausgegeben wird, bestimmte Daten über ein separates Modell abzurufen (funktioniert einwandfrei).

Der Problemcode läuft im Grunde darauf hinaus

foreach ($order->getAllItems() as $key => $item) {
    /** @var Tantor_Catalog_Model_Product $productData */
    $productData = $item->getProduct();
    $_item = Mage::getModel('catalog/product')->load($productData->getId());
    $_item->setNetsuiteItemIid('foo');
    $_item->save();
}

Magento wirft jedoch eine Ausnahme von

2014-03-05T21:14:14+00:00 ERR (3):
exception 'Exception' with message 'Warning: Invalid argument supplied for foreach()  in /var/www/html/app/code/core/Mage/Eav/Model/Entity/Abstract.php on line 1180' in /var/www/html/app/code/core/Mage/Core/functions.php:245
Stack trace:
#0 /var/www/html/app/code/core/Mage/Eav/Model/Entity/Abstract.php(1180): mageCoreErrorHandler(2, 'Invalid argumen...', '/var/www/html/a...', 1180, Array)
#1 /var/www/html/app/code/core/Mage/Eav/Model/Entity/Abstract.php(1123): Mage_Eav_Model_Entity_Abstract->_collectSaveData(Object(Tantor_Catalog_Model_Product))
#2 /var/www/html/app/code/core/Mage/Core/Model/Abstract.php(318): Mage_Eav_Model_Entity_Abstract->save(Object(Tantor_Catalog_Model_Product))
#3 /var/www/html/app/code/local/Tantor/Netsuite/Model/Observer.php(218): Mage_Core_Model_Abstract->save()
#4 /var/www/html/app/code/core/Mage/Core/Model/App.php(1338): Tantor_Netsuite_Model_Observer->saveOrder(Object(Varien_Event_Observer))
#5 /var/www/html/app/code/core/Mage/Core/Model/App.php(1317): Mage_Core_Model_App->_callObserverMethod(Object(Tantor_Netsuite_Model_Observer), 'saveOrder', Object(Varien_Event_Observer))
#6 /var/www/html/app/Mage.php(447): Mage_Core_Model_App->dispatchEvent('sales_order_pla...', Array)
#7 /var/www/html/app/code/core/Mage/Sales/Model/Order.php(1096): Mage::dispatchEvent('sales_order_pla...', Array)
#8 [internal function]: Mage_Sales_Model_Order->place()
#9 /var/www/html/app/code/core/Mage/Core/Model/Resource/Transaction.php(105): call_user_func(Array)
#10 /var/www/html/app/code/core/Mage/Core/Model/Resource/Transaction.php(159): Mage_Core_Model_Resource_Transaction->_runCallbacks()
#11 /var/www/html/app/code/core/Mage/Sales/Model/Service/Quote.php(189): Mage_Core_Model_Resource_Transaction->save()
#12 /var/www/html/app/code/core/Mage/Sales/Model/Service/Quote.php(249): Mage_Sales_Model_Service_Quote->submitOrder()
#13 /var/www/html/app/code/core/Mage/Checkout/Model/Type/Onepage.php(774): Mage_Sales_Model_Service_Quote->submitAll()
#14 /var/www/html/app/code/core/Mage/Checkout/controllers/OnepageController.php(511): Mage_Checkout_Model_Type_Onepage->saveOrder()
#15 /var/www/html/app/code/core/Mage/Core/Controller/Varien/Action.php(419): Mage_Checkout_OnepageController->saveOrderAction()
#16 /var/www/html/app/code/core/Mage/Core/Controller/Varien/Router/Standard.php(250): Mage_Core_Controller_Varien_Action->dispatch('saveOrder')
#17 /var/www/html/app/code/core/Mage/Core/Controller/Varien/Front.php(176): Mage_Core_Controller_Varien_Router_Standard->match(Object(Mage_Core_Controller_Request_Http))
#18 /var/www/html/app/code/core/Mage/Core/Model/App.php(354): Mage_Core_Controller_Varien_Front->dispatch()
#19 /var/www/html/app/Mage.php(683): Mage_Core_Model_App->run(Array)
#20 /var/www/html/index.php(86): Mage::run('', 'store')
#21 {main}

Warum sollte ich in der Lage sein, identischen Code in einem Skript eines Drittanbieters außerhalb des Magento-Beobachters zu verwenden, aber wenn ich versuche, ihn in diesem Beobachter auszuführen, schlägt dies mit dieser zufälligen Fehlermeldung fehl?

Zxurian
quelle
Dieser Fehler ist typisch für ein Nicht-Array, in das analysiert wird foreach. Der Stack-Trace zeigt an, dass ein Ereignis ausgelöst wurde und der Beobachter fehlerhaft ist. Sind Sie sicher, dass $order->getAllItems()es eine Neuabstimmung gibt array()? benutzen Zend_Debug::dump($order->getAllItems());. Es könnte sich jedoch auch um einen anderen Beobachter mit einem schlechten Code handeln.
Asche
Das Problem liegt beim Magento-Kerncode, nicht bei meinem Snippet oben.
Zxurian

Antworten:

33

Das Problem ist, dass Sie keine Produkte vom Frontend speichern dürfen.

Dies geschieht dadurch, dass beim Laden eines Produkts im Frontend die origDataEigenschaft nicht gefüllt wird:

public function setOrigData($key=null, $data=null)
{
    if (Mage::app()->getStore()->isAdmin()) {
        return parent::setOrigData($key, $data);
    }

    return $this;
}

Wenn Sie versuchen, das Produkt zu speichern, wird der von Ihnen beschriebene Fehler ausgelöst.

Sie können dieses Problem lösen, indem Sie den aktuellen Store in admin ändern, z. B. mit dem Code von @magboy:

Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);

besser nutzen Mage_Core_Model_App_Emulation

Und meine bevorzugte Lösung ist, Mage_Catalog_Model_Productdie setOrigDataMethode zu erweitern und zu ersetzen

public function setOrigData($key = null, $data = null)
{
    if (is_null($key)) {
        $this->_origData = $this->_data;
    } else {
        $this->_origData[$key] = $data;
    }
    return $this;
}

Ich spreche hier NICHT über ein Umschreiben! Verwenden Sie Ihr Modell nur an dieser Stelle, um das Speichern zu ermöglichen. Dann haben Sie das Sicherheitsmerkmal noch überall aktiviert.

Fabian Blechschmidt
quelle
7

Versuchen Sie, diese Codezeile hinzuzufügen:

Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);

Ich bin mir nicht sicher, warum Sie dies jetzt in der aktuellen Version von Magento tun müssen. Vielleicht kann jemand anderes erklären?

Magboy
quelle
Muss ich den ursprünglichen Wert wiederherstellen, nachdem ich den aktuellen Speicher auf "Admin" gesetzt und das Produkt gespeichert habe?
Giuseppe
1
@ Giuseppe Es kommt darauf an, was Sie später mit der Anfrage machen. Es ist sauberer und führt zu weniger Problemen, wenn Sie es tun
Simonthesorcerer