Magento Zend_Db_Adapter_Abstract::更新问题

发布于 2024-12-01 11:37:09 字数 6746 浏览 2 评论 0原文

我编写了一个模块,可以接收 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>

这是 system.xml 中用于上传框的 backend_model 类:

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

最后,它的核心是模型资源类你可以完成所有的工作。看到这里,我在构造函数中调用 _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 array 它总是如预期的 3如果我将日志记录添加到 Zend_Db_Adapter_Abstract 来打印它运行的每个 SQL 语句,它只会运行 3。所以我不知道为什么要插入额外的行。

预先感谢您的任何帮助!

I've written a module that can take in a CSV file and add data to the sales_flat_order table (code below). Despite my skepticism and lack of knowledge in interacting directing with the DB through Magento, I was able to successfully update the necessary columns in the table. However, every time I run the code, it updates the rows but always adds one extra row to the table with all null values. I've tried printing out the raw SQL and I don't see any extraneous SQL calls, yet it keeps doing it.

Here are the important snippets of code that should help explain what I'm doing. Hopefully this is a known issue someone else has run into and can point me in the right direction.

First, here's my 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>

As it says in the comments, I didn't provide any entities because I'm not using my own table (it initializes using the sales/order resource model (see blow)

Next, I added this to my system.xml file to add a file import box to the config:

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

Here's the backend_model class used in system.xml for the upload box:

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

And finally, the meat of it all is the Model Resource class that does all the work. You can see here that I call _init('sales/order') in the constructor so that I can piggyback on the sales_order resource model and not have to make a separate DB connection (I'm assuming this is ok...it's working, but let me know if this is a bad idea)

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

I cut out a lot of my debug statements to simplify it, but it's important to note that if I echo the size of the $importData array it is always 3 as expected from my CSV. If I add logging to Zend_Db_Adapter_Abstract to print each SQL statement it runs, it only runs 3. So I don't know why the extra line is being inserted.

Thanks in advance for any help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦里人 2024-12-08 11:37:09

我不是 100% 确定发生这种情况的原因,但我找到了解决方案。我认为这是由于默认情况下任何 Mage_Core_Model_Config_Data 对象都将其值存储在 core_config_data 表中造成的。由于我将其初始化为使用自己的资源模型,该模型实际上搭载了 sales/order 资源模型,因此它感到困惑并尝试将虚假信息保存到 sales/order 表中。

为了解决这个问题,我执行了以下操作:

首先,在 system.xml 中使用的 backend_model 类的构造函数中,设置 _dataSaveAllowed标记为 false

protected function _construct()
{
    parent::_construct();
    $this->_init('sorting/csv'); //initialize the resource model
    $this->_dataSaveAllowed = false;
}

接下来,不要使用 _afterSave 来处理 CSV 导入,而是使用 _beforeSave_afterSave 不是'当你不允许时我不会打电话保存数据)

这似乎解决了我的问题,但如果我的方法有缺陷,我欢迎任何评论/建议。我对此还是新手,所以任何有经验的见解总是值得赞赏:)

I'm not 100% sure the reason why this was happening, but I have found a solution. I believe this is caused by the fact that, by default, any Mage_Core_Model_Config_Data object stores its values in the core_config_data table. Since I initialized this to use my own resource model which actually piggybacks on the sales/order resource model, it got confused and tried to save bogus information to the sales/order table.

To fix it, I did the following:

First, in the constructor for the backend_model class used in the system.xml, set the _dataSaveAllowed flag to false:

protected function _construct()
{
    parent::_construct();
    $this->_init('sorting/csv'); //initialize the resource model
    $this->_dataSaveAllowed = false;
}

Next, instead of using _afterSave to process the CSV import, use _beforeSave (_afterSave isn't called when you don't allow saving of the data)

This appears to have resolved my issues, but I welcome any comments/suggestions if my method is flawed. I'm still new at this, so any experienced insight is always appreciated :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文