Magento Zend_Db_Adapter_Abstract:: проблема обновления
Я написал модуль, который может взять файл CSV и добавить данные в таблицу sales_flat_order (код ниже). Несмотря на мой скептицизм и отсутствие знаний о взаимодействии с БД через Magento, я смог успешно обновить необходимые столбцы в таблице. Однако каждый раз, когда я запускаю код, он обновляет строки, но всегда добавляет одну дополнительную строку в таблицу со всеми нулевыми значениями. Я пытался распечатать сырой SQL, и я не вижу никаких посторонних вызовов SQL, но он продолжает это делать.
Вот важные фрагменты кода, которые должны помочь объяснить, что я делаю. Надеюсь, это известная проблема, с которой столкнулся кто-то другой, и которая может указать мне правильное направление.
Во-первых, вот мой config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<modules>
<VPS_Sorting>
<version>0.1.0</version>
</VPS_Sorting>
</modules>
<admin>
<routers>
<adminhtml>
<args>
<modules>
<sorting after="Mage_Adminhtml">VPS_Sorting</sorting>
</modules>
</args>
</adminhtml>
</routers>
</admin>
<global>
<models>
<sorting>
<class>VPS_Sorting_Model</class>
<resourceModel>sorting_mysql4</resourceModel>
</sorting>
<sorting_mysql4>
<class>VPS_Sorting_Model_Mysql4</class>
<!-- Doesn't need entities when you aren't using your own table!! -->
</sorting_mysql4>
</models>
<blocks>
<sorting>
<class>VPS_Sorting_Block</class>
</sorting>
</blocks>
<resources>
<!-- this section used to install/configure the DB dynamically -->
<sorting_setup>
<setup>
<module>VPS_Sorting</module>
<class>VPS_Sorting_Model_Mysql4_Setup</class>
</setup>
<connection>
<use>core_setup</use>
</connection>
</sorting_setup>
<!-- end setup section -->
<sorting_write>
<connection>
<use>core_write</use>
</connection>
</sorting_write>
<sorting_read>
<connection>
<use>core_read</use>
</connection>
</sorting_read>
</resources>
</global>
<adminhtml>
<acl>
...
</acl>
</adminhtml>
</config>
Как говорится в комментариях, я не предоставил никаких сущностей, потому что я не использую свою собственную таблицу (она инициализируется с использованием модели ресурсов продаж / заказов (см. Удар)
Затем я добавил это в свой файл system.xml, чтобы добавить окно импорта файла в конфигурацию:
<importcsv translate="label">
<label>Import CSV</label>
<comment>
<![CDATA[requires 2 columns, 'order_id' and 'real_ship_cost']]>
</comment>
<frontend_type>import</frontend_type>
<backend_model>sorting/import_csv</backend_model>
<sort_order>5</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</importcsv>
Вот класс backend_model, используемый в system.xml для поля загрузки:
class VPS_Sorting_Model_Import_Csv extends Mage_Core_Model_Config_Data
{
protected function _construct()
{
parent::_construct();
$this->_init('sorting/csv'); //initialize the resource model
}
public function _afterSave()
{
if($rm = $this->_getResource())
$rm->uploadAndImport($this);
else
Mage::logException("Failed to load VPS_Sorting Resource Model");
}
}
И наконец, суть всего этого - класс Model Resource, который выполняет всю работу. Вы можете увидеть здесь, что я звоню _init('sales/order')
в конструкторе, чтобы я мог использовать модель ресурсов sales_order и не создавать отдельное соединение с БД (я предполагаю, что это нормально... это работает, но дайте мне знать, если это плохая идея)
class VPS_Sorting_Model_Mysql4_Csv extends Mage_Core_Model_Mysql4_Abstract
{
protected $_adapter;
protected function _construct()
{
$this->_init('sales/order', 'entity_id');
}
public function uploadAndImport(Varien_Object $object)
{
$csvFile = $_FILES['groups']['tmp_name']['actions']['fields']['importcsv']['value'];
$io = new Varien_Io_File();
$info = pathinfo($csvFile);
$io->open(array('path' => $info['dirname']));
$io->streamOpen($info['basename'], 'r');
// check and skip headers
$headers = $io->streamReadCsv();
// return parent::_afterSave();
if ($headers === false || count($headers) < 2 || $headers[0] != 'order_id' || $headers[1] != 'real_ship_cost')
{
$io->streamClose();
Mage::throwException("Invalid Real Shipping Cost CSV Format. File must contain 2 columns: 'order_id' and 'real_ship_cost'");
}
//Varien_Db_Adapter_Pdo_Mysql
$this->_adapter = $this->_getWriteAdapter();
$this->_adapter->beginTransaction();
try {
$importData = array();
while (false !== ($csvLine = $io->streamReadCsv()))
{
if (empty($csvLine)) {
continue;
}
$importData[] = array('id' => $csvLine[0], 'rsc' => $csvLine[1]);
if (count($importData) == 5000) {
$this->_saveImportData($importData);
$importData = array();
}
}
$this->_saveImportData($importData);
$io->streamClose();
} catch (Mage_Core_Exception $e) {
$this->_adapter->rollback();
$io->streamClose();
Mage::throwException($e->getMessage());
} catch (Exception $e) {
$this->_adapter->rollback();
$io->streamClose();
Mage::logException($e);
Mage::throwException('An error occurred while importing Real Shipping Cost data.');
}
$this->_adapter->commit();
return $this;
}
protected function _saveImportData($_data)
{
foreach($_data as $_row)
{
$this->_adapter->update($this->getMainTable(), array('real_ship_cost' => $_row['rsc']), array('`increment_id` = ?' => $_row['id']));
}
}
}
Я упустил много своих операторов отладки, чтобы упростить его, но важно отметить, что если я повторяю размер массива $ importData, он всегда равен 3, как и ожидалось от моего CSV. Если я добавлю запись в Zend_Db_Adapter_Abstract для печати каждого оператора SQL, который он запускает, он запускается только 3. Поэтому я не знаю, почему вставляется дополнительная строка.
Заранее благодарю за любую помощь!
1 ответ
Я не уверен на 100%, почему это произошло, но я нашел решение. Я считаю, что это связано с тем, что по умолчанию любой Mage_Core_Model_Config_Data
объект хранит свои значения в core_config_data
Таблица. Так как я инициализировал это, чтобы использовать мою собственную модель ресурсов, которая на самом деле совмещает sales/order
модель ресурсов, она запуталась и пыталась сохранить поддельную информацию в sales/order
Таблица.
Чтобы это исправить, я сделал следующее:
Сначала в конструкторе для класса backend_model, используемого в system.xml, установите для флага _ dataSaveAllowed значение false:
protected function _construct()
{
parent::_construct();
$this->_init('sorting/csv'); //initialize the resource model
$this->_dataSaveAllowed = false;
}
Далее, вместо использования _afterSave для обработки импорта CSV, используйте _beforeSave (_afterSave не вызывается, если вы не разрешаете сохранение данных)
Это, кажется, решило мои проблемы, но я приветствую любые комментарии / предложения, если мой метод ошибочен. Я все еще новичок в этом, поэтому любое опытное понимание всегда ценится:)