After much research, I came up with various solutions to this problem that do not seem ideal, but someone can improve one of them.
First, why is the problem. Before you join, Magento has already prepared the part of the request, presented as objects. This part sets up the "select" and "where" that need to be run for filtering, this will result in a query that looks something like this:
SELECT `main_table`.* FROM `sales_flat_order_grid` WHERE (`grand_total` <= '20')
The problem is the “where” part of the query, because the column names do not have a prefix with the table alias main_table . If you then try to expand this query by adding a join to a table with a column with the same name as the any column in the where clause, you will get an "ambiguous" error. For example, if you joined the above query in the sales_flat_order table, then it would fail, since this table also has a grand_total column, which makes the where clause in this file ambiguous.
Magento has a mechanism to solve this problem, filterIndex . The column objects that form the grid can have a filter index using
$column = $block->getColumn('grand_total'); $column->setFilterIndex('main_table.grand_total');
To adjust the where WHERE `main_table`.`grand_total` <= '20' in the above query to WHERE `main_table`.`grand_total` <= '20'
To solve all the problems, if we could get the $column object before SQL was actually prepared.
Decision
Override Class and Subclass Mage_Adminhtml_Block_Widget_Grid . Just override the _prepareColumns() method as follows:
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; } }
- Rewrite the request before executing it
This solution is shown in the question where you grab the where clause, and then do some kind of find and replace to add to the main_table prefix. Something like
$select = $collection->getSelect(); $where = $select->getPart('where'); //find an replace each element in the where array
- Use subquery in 'join' clause
Since the problem is caused by a column with the same name in both tables, you can modify the 'join' query to rename or delete an ambiguous column. Connection offer setup:
$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'));
While this works, the request is too slow to be practical. The query can be modified to speed it up as follows:
$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) );
While this works and runs quickly, the problem is that Magento uses the objects that make up this query twice, once for the grid itself, and also for “counting”, to create paginated widgets at the top of the grid page . Unfortunately, when using the "count" query, Magento does not use the selected columns, but only the "from", "attach" and "where" parts. This means that if you use the above query, you cannot filter the new column that you are adding.
- Add column to sales_flat_order_grid
The sales_flat_order_grid table can be expanded to include the extra column that you need and update that column. This method is described here https://magento.stackexchange.com/a/4626/34327
- Intercept and add a filter index before creating a query
There is an event that can be intercepted, interrogated, and modified before SQL is fully prepared. This is resource_get_tablename , but you need to check that you are working with the correct table.
To get this working, I would write a resource_get_tablename event observer as follows
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); } } }
I hope someone can improve one of these methods to create something really useful.