我已经解决了这个问题,最后!
基本上我正在使用$where = $select->getPart('where')
获得WHERE部分,然后我会查看每个条件并搜索created_at
,如果找到匹配,那么我将created_at
替换为main_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);
}
}
我正在尝试使用observer从自定义表格中添加销售订单网格中的新列。一切正常,直到我尝试使用列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>
答案 0 :(得分:4)
经过大量的研究,我已经找到了解决这个问题的各种解决方案,其中没有一个看起来很理想,但有人可能会改进其中一个。
首先,问题的原因。在您加入之前,Magento已经准备了一部分查询,表示为对象。这部分设置了'select'和“where”,需要进行过滤,这将导致查询看起来像:
SELECT `main_table`.* FROM `sales_flat_order_grid`
WHERE (`grand_total` <= '20')
问题是查询的“where”部分,因为列名不以表名别名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'
如果我们能够在SQL实际准备好之前到达$column
对象,那将解决所有问题。
覆盖和子类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;
}
}
这是问题中显示的解决方案,您可以在其中获取'where'子句,然后执行某种查找和替换以添加main_table
前缀。像
$select = $collection->getSelect();
$where = $select->getPart('where');
//find an replace each element in the where array
由于问题是由两个表中具有相同名称的列引起的,因此可以更改“join”查询以重命名或删除不明确的列。将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'部分。这意味着如果您使用上述查询,则无法过滤要添加的新列。
sales_flat_order_grid表可以扩展为包含您需要的额外列,并自动更新该列。这里描述了这种技术https://magento.stackexchange.com/a/4626/34327
在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);
}
}
}
我希望有人可以改进其中一种方法来创造真正有用的东西。
答案 1 :(得分:2)
尝试更改
<filter_index>field_to_show_in_grid</filter_index>
要
<filter_index>main_table.created_at</filter_index>
请参阅Adding a column to Magento orders grid - alternative way using layout handles
答案 2 :(得分:0)
您可以在观察者中使用$collection->addFilterToMap('created_at', 'main_table.created_at');