8

我已经解决了问题,终于!

基本上我得到 WHERE 部分,$where = $select->getPart('where')然后我遍历每个条件并搜索created_at,如果我找到匹配然后我替换created_atmain_table.created_at

我已经对此进行了测试,一切正常,如果有什么可能是“错误”的,请告诉我。

谢谢大家!!

public function salesOrderGridCollectionLoadBefore($observer)
{

  $collection = $observer->getOrderGridCollection();
  $select     = $collection->getSelect();
  $select->joinLeft(array('custab' => 'my_custom_table'), 'main_table.entity_id = custab.order_id',array('custab.field_to_show_in_grid'));

  if ($where = $select->getPart('where')) {
      foreach ($where as $key=> $condition) {
          if (strpos($condition, 'created_at')) {
              $new_condition = str_replace("created_at", "main_table.created_at", $condition);
              $where[$key] = $new_condition;
          }
      }
      $select->setPart('where', $where);
  }

}

我正在尝试使用观察者在自定义表中的销售订单网格中添加新列。一切正常,直到我尝试使用 column 过滤网格created_at

问题是因为我created_at在自定义表和sales_flat_order_grid表中具有相同的列名 ()。

我收到此错误

SQLSTATE [23000]:违反完整性约束:1052 where 子句中的列“created_at”不明确

如果我将此行编辑'index' => 'created_at''index' => '**main_table**.created_at'app/code/core/Mage/Adminhtml/Block/Sales/Order/Grid.php

$this->addColumn('created_at', array(
        'header' => Mage::helper('sales')->__('Purchased On'),
        'index' => 'main_table.created_at',
        'type' => 'datetime',
        'width' => '100px',
    ));

一切正常,但我不想更改核心文件或将它们复制到本地文件夹并编辑,我认为有一些简单的解决方案需要添加到我的观察者中。

这是我的 Observer.php

class Testinggrid_ExtendOrderGrid_Model_Observer{
    public function salesOrderGridCollectionLoadBefore($observer)
    {
       $collection = $observer->getOrderGridCollection();
       $select     = $collection->getSelect();
       $select->joinLeft(array('custab' => 'my_custom_table'), 'main_table.entity_id = custab.order_id',array('custab.field_to_show_in_grid'));
    }
}

这是我的模块布局

<layout>
  <sales_order_grid_update_handle>
    <reference name="sales_order.grid">
        <action method="addColumnAfter">
            <columnId>field_to_show_in_grid</columnId>
            <arguments>
                <header>Column header</header>
                <index>field_to_show_in_grid</index>
                <filter_index>field_to_show_in_grid</filter_index>
                <type>text</type>
            </arguments>
            <after>shipping_name</after>
        </action>
    </reference>
  </sales_order_grid_update_handle>
  <adminhtml_sales_order_grid>
    <!-- apply layout handle defined above -->
    <update handle="sales_order_grid_update_handle" />
  </adminhtml_sales_order_grid>
  <adminhtml_sales_order_index>
    <!-- apply layout handle defined above -->
    <update handle="sales_order_grid_update_handle" />
  </adminhtml_sales_order_index>
</layout>
4

3 回答 3

4

经过大量研究,我想出了解决这个问题的各种解决方案,但似乎都不理想,但有人可能会改进其中的一个。

首先,问题的原因。在您进行连接之前,Magento 已经准备好一部分查询,表示为对象。这部分设置需要为过滤完成的“选择”和“位置”,它将导致查询看起来像:

SELECT `main_table`.* FROM `sales_flat_order_grid`
WHERE (`grand_total` <= '20')

问题是查询的“where”部分,因为列名没有以表名 alias 为前缀main_table如果您随后尝试通过将联接添加到具有与 where 子句中的任何列同名的列的表来扩展此查询,您将收到“歧义”错误。例如,如果您要将上述查询连接到sales_flat_order表,那么它将失败,因为该表也有一个grand_total列,从而使过滤器中的“where”子句不明确。

Magento 有一个机制来处理这个问题,filterIndex. 形成网格的列对象可以有一个过滤器索引集,使用

$column = $block->getColumn('grand_total');
$column->setFilterIndex('main_table.grand_total');

这会将上述查询中的“where”子句调整为WHERE `main_table`.`grand_total` <= '20'

如果我们能够在$columnSQL 实际准备好之前获取对象,这将解决所有问题。

解决方案

  1. 覆盖核心文件

覆盖和子Mage_Adminhtml_Block_Widget_Grid类类。只覆盖这样的_prepareColumns()方法:

class Mycomp_Mymodule_Block_Sales_Order_Grid extends Mage_Adminhtml_Block_Sales_Order_Grid
{
    protected function _prepareColumns()
    {
        //get the columns from the parent so they can be returned as expected
        $columns = parent::_prepareColumns();
        $this->addColumnAfter('custom_column', array(
            'header'    => 'Custom Column',
            'index'     => 'custom_column',
            'type'      => 'text',
            'filter_index'=> 'custom_table.custom_column',
        ), 'billing_name' );
        //columns need to be reordered
        $this->sortColumnsByOrder();
        return $columns;
    }
}
  1. 在执行之前重写查询

这是问题中显示的解决方案,您可以在其中获取“where”子句,然后进行某种查找和替换以添加main_table前缀。就像是

$select = $collection->getSelect();    
$where = $select->getPart('where');
//find an replace each element in the where array
  1. 在“加入”子句中使用子查询

由于问题是由两个表中具有相同名称的列引起的,因此可以更改“连接”查询以重命名或删除不明确的列。将 join 子句调整为:

$subquery = new Zend_Db_Expr( 
    '(SELECT order_id AS order_alias, 
             field_to_show_in_grid AS field_to_show_in_grid_alias
      FROM my_custom_table)');
$select->joinLeft( array('custab' => $subquery), 
                   'main_table.entity_id = custab.order_alias',
                   array('custab.field_to_show_in_grid_alias'));

虽然这确实有效,但查询速度太慢,不实用。可以修改查询以加快速度,如下所示:

$subquery = new Zend_Db_Expr( 
    '(SELECT field_to_show_in_grid
      FROM my_custom_table
      WHERE main_table.entity_id=my_custom_table.order_id)');
$select->addFieldToSelect( array('field_to_show_in_grid_alias'=>$subquery) );

虽然这可行且速度很快,但问题是 Magento 两次使用构成此查询的对象,一次用于网格本身,一次用于“计数”,以在网格页面顶部生成分页 wigits。不幸的是,当在“count”查询中使用时,Magento 不使用选定的列,只使用查询的“from”、“join”和“where”部分。这意味着如果您使用上述查询,您将无法过滤您正在添加的新列。

  1. 将列添加到 sales_flat_order_grid

sales_flat_order_grid 表可以扩展为包含您需要的额外列并自动更新该列。此处描述了此技术https://magento.stackexchange.com/a/4626/34327

  1. 在构建查询之前拦截并添加过滤器索引

在 SQL 完全准备好之前,有一个事件可以被拦截、询问和更改。这是resource_get_tablename,但您需要检查您使用的表格是否正确。

为了让这个工作,我会写一个事件的观察者resource_get_tablename如下

public function resourceGetTablename(Varien_Event_Observer $observer)
{
    //Check we are working with the correct table
    if( $observer->getTableName() == 'sales_flat_order_grid' ) {

        $block = Mage::getSingleton('core/layout')->getBlock('sales_order.grid');

        foreach( $block->getColumns() as $column ) {
            //create a filter index for each column using 'main_table' prefixed to the column index
            $column->setFilterIndex('main_table.' . $column->index);
        }

    }
}

我希望有人可以改进其中一种方法来创造一些真正有用的东西。

于 2016-10-31T21:05:10.410 回答
2

尝试改变

<filter_index>field_to_show_in_grid</filter_index>

<filter_index>main_table.created_at</filter_index>

请参阅向 Magento 订单网格添加列 - 使用布局句柄的替代方式

于 2013-08-09T13:46:12.423 回答
0

您可以$collection->addFilterToMap('created_at', 'main_table.created_at');在观察者中使用

于 2013-08-09T13:20:34.547 回答