循环中使用的Magento集合过滤器中出现意外行为

时间:2012-12-07 01:30:42

标签: magento

我在集合中看到一个意想不到的行为,也许有人可以启发我(或者可能是一些PHP我不会理解)(对不起这篇文章的篇幅,但我不得不包含示例代码和结果)。

我的目标是撰写一份报告,我会收到订单及其订单商品,然后转到订单的发票和发货数据,并从其商品中获取匹配的订单商品数据。我知道所有订单只有一张发票和货件,所以即使Magento在订单和发票/货件之间使用了1-M的关系,我也可以利用它,好像它是1-1

我知道这些项目都是使用order_item_id字段相关的,所以我尝试编写一个使用以下调用的函数 -

$invoiceItem = $order
  ->getInvoiceCollection()
  ->getFirstItem()
  ->getItemsCollection()
  ->addFieldToFilter('order_item_id', $orderItem->getItemId())
  ->getFirstItem();

但这并不是我预期的结果,我看到的是与过滤器中使用的订单商品ID无关的相同发票项目。

因此,为了尝试理解这个问题,我编写了以下小程序来查看查询的创建方式。

<?php

require dirname(__FILE__).'/../app/Mage.php';    
umask(0);
Mage::app('default');

$orders = Mage::getResourceModel('sales/order_collection')
       ->addAttributeToSelect('*')
       ->addAttributeToFilter('state', 'processing') 
       ->addAttributeToSort('created_at', 'desc')
       ->addAttributeToSort('status', 'asc')
       ->load();

foreach ($orders as $order) {

    echo "\ngetting data for order id ". $order->getId();

    $items = $order->getAllItems();
    $invoice = $order->getInvoiceCollection()->getFirstItem();

    foreach ($items as $orderItem) {

        echo "\n\ngetting data for order item id ". $orderItem->getItemId();    
        $invoiceItems = $order
                   ->getInvoiceCollection()
                   ->getFirstItem()
                   ->getItemsCollection()
                   ->addFieldToFilter('order_item_id', $orderItem->getItemId());    
        echo "\n".$invoiceItems->getSelect();    
    }
    die;  //just quit after one iteration
}

该计划的输出如下 -

getting data for order id 7692

getting data for order item id 20870
SELECT `main_table`.* FROM `sales_flat_invoice_item` AS `main_table` WHERE (parent_id = '7623') AND (order_item_id = '20870')

getting data for order item id 20871
SELECT `main_table`.* FROM `sales_flat_invoice_item` AS `main_table` WHERE (parent_id = '7623') AND (order_item_id = '20870') AND (order_item_id = '20871')

getting data for order item id 20872
SELECT `main_table`.* FROM `sales_flat_invoice_item` AS `main_table` WHERE (parent_id = '7623') AND (order_item_id = '20870') AND (order_item_id = '20871') AND (order_item_id = '20872')

正如你所看到的,每次循环时,另外一个“AND(order_item_id =”为我正在过滤的每个项目ID添加。我认为每次循环,我都会得到一个新的版本使用$ order-&gt; getInvoiceCollection()。

的集合

那么,有人能告诉我示例代码中出了什么问题并教会我正确的方法吗?

谢谢!

1 个答案:

答案 0 :(得分:0)

关于您的业务问题:需要更多信息。目标是生成具有订单项对象的集合,这些对象是EACH了解发票和装运详细信息的吗?似乎有渲染问题被推入建模问题。

关于select语句问题:Varien collections有一个优化,阻止他们多次访问存储后端。通过将_isCollectionLoaded属性设置为true,可以在DB collection个实例中实现此标准行为。

在您的情况下,发票集合实例是通过订单实例stored in a protected property创建的,immediately load()ed是通过IteratorAggregate创建的(通过foreach调用)。因为您在每次迭代中使用相同的订单对象实例,所以您正在处理此已加载的发票集合实例,并且每次迭代都会有效地调用addFieldToFilter(/* next order id */),从而导致不断扩展的WHERE子句。通过调用$order->reset()可以轻松解决此特定优化问题。这让我们回到了一个突出的问题,即需要更好地理解目标,并且(可能)使用自定义集合或操纵集合来加入您需要的特定数据。