0

Context: we have a project which uses M2E so our client can sell on eBay. For easy reference, we've added custom columns to the product grid in the admin panel so that the eBay item ID is displayed next to the other product details.

The above all works fine, no problems.

The problem is that occasionally eBay issues a new item ID for an item for some reason or another, and then we have two eBay item IDs for the same product. This has just been flagged as an issue because when we use joinField to add the item ID to the product collection, it's grabbing the first ID it finds, not the latest one.

So what we want to do is grab the newest eBay item ID instead of the first one found but I'm struggling to find a way to make this work within Magento. Straight SQL would be no problem, but I'm a little less skilled with Magento DB queries.

This is the code we're using to join the eBay item ID table at present:

$collection->joinField('ebay_item_id', 'm2epro_ebay_item', 'item_id', 'product_id=entity_id', null, 'left');

This is what we tried adding to make it work (no luck):

$collection->addAttributeToSort('m2epro_ebay_item.update_date', 'DESC');

These are the relevant column headings in the table we're joining:

id (row ID)
item_id (eBay item ID)
product_id (Magento product ID)
update_date (last updated)
create_date (creation date)

It could be sorted by any of ID, update_date, or create_date, but I can't get my head around how to get it to do it within the Magento architecture.

So any help or pointers would be appreciated.

Edited to add:

class Digitalsix_CustomGrid_Model_Adminhtml_Observer {

    public function onBlockHtmlBefore(Varien_Event_Observer $observer) {
        $block = $observer->getBlock();
        if (!isset($block)) {
            return;
        }

        switch ($block->getType()) {
            case 'adminhtml/catalog_product_grid':
                $block->addColumn('ebay_item_id', array(
                    'header' => Mage::helper('catalog')->__('Ebay ID'),
                    'width' => '80px',
                    'index' => 'ebay_item_id',
                    'filter' => false,
                ));
                break;
        }
    }

    public function onEavLoadBefore(Varien_Event_Observer $observer) {
        $collection = $observer->getCollection();
        if (!isset($collection)) {
            return;
        }

        if (is_a($collection, 'Mage_Catalog_Model_Resource_Product_Collection')) {
            $collection->getSelect()->group('e.entity_id');

            if (!$collection->fieldAlreadyJoined("ebay_item_id")) {
                $collection->joinField('ebay_item_id', 'm2epro_ebay_item', 'item_id', 'product_id=entity_id', null, 'left');
            }
        }
    }

}
2

Basically, you've got two options here – there is a third one, but that's not recommended due to bad performance. Both queries shown here should perform well. Which one will be faster is hard to anticipate and depends on your use case.

1. Uncorrelated

public function onEavLoadBefore(Varien_Event_Observer $observer) {
    $collection = $observer->getCollection();
    if (!isset($collection)) {
        return;
    }

    if (is_a($collection, 'Mage_Catalog_Model_Resource_Product_Collection')) {
        $tableAlias = 'mei';
        $select = $collection->getSelect();

        if ( !array_key_exists ( $tableAlias, $select->getPart ( Varien_Db_Select::FROM ) ) )
        {
            $tableName = 'm2epro_ebay_item';
            $productIdFieldName = 'product_id';
            $sortFieldName = 'id';
            $sourceFieldName = 'item_id';
            $targetFieldName = 'ebay_item_id';
            $adapter = $select->getAdapter();

            $select
                ->joinLeft
                (
                    array
                    (
                        $tableAlias =>
                            $adapter
                                ->select()
                                ->from ( array ( $tableAlias => $tableName ) )
                                ->joinInner
                                (
                                    array
                                    (
                                        $tableAlias . 'grouped' =>
                                            $adapter
                                                ->select()
                                                ->from ( $tableName, array ( $productIdFieldName, 'MaxId' => 'MAX(`'.$sortFieldName.'`)' ) )
                                                ->group ( $productIdFieldName )
                                    ),
                                    '`'.$tableAlias.'`.`'.$productIdFieldName.'` = `'.$tableAlias . 'grouped`.`'.$productIdFieldName.'` AND `'.$tableAlias.'`.`'.$sortFieldName.'` = `'.$tableAlias . 'grouped`.`MaxId`',
                                    null
                                )
                    ),
                    '`e`.`entity_id` = `'.$tableAlias.'`.`'.$productIdFieldName.'`',
                    array ( $targetFieldName => $sourceFieldName )
                )
            ;
        }
    }
}

2. Correlated

public function onEavLoadBefore(Varien_Event_Observer $observer) {
    $collection = $observer->getCollection();
    if (!isset($collection)) {
        return;
    }

    if (is_a($collection, 'Mage_Catalog_Model_Resource_Product_Collection')) {
        $select = $collection->getSelect();
        $targetFieldName = 'ebay_item_id';

        $ebayItemIdAlreadyAdded = false;
        foreach ( $select->getPart ( Varien_Db_Select::COLUMNS ) as $column )
        {
            if ( $column[2] == $targetFieldName )
            {
                $ebayItemIdAlreadyAdded = true;
                break;
            }
        }
        if ( !$ebayItemIdAlreadyAdded )
        {
            $tableName = 'm2epro_ebay_item';
            $productIdFieldName = 'product_id';
            $sortFieldName = 'id';
            $sourceFieldName = 'item_id';

            $select
                ->from
                (
                    '',
                    array
                    (
                        $targetFieldName =>
                            $select
                                ->getAdapter()
                                ->select()
                                ->from ( $tableName, $sourceFieldName )
                                ->where ( '`e`.`entity_id` = `'.$tableName.'`.`'.$productIdFieldName.'`' )
                                ->order ( $sortFieldName . ' ' . Varien_Db_Select::SQL_DESC )
                                ->limit ( 1 )
                    )
                )
            ;
        }
    }
}

Instead of building queries this way, you might as well provide a string to improve performance somehow and/or make it more readable. Building e.g. the correlated query in a simpler way looks like

$select
    ->from
    (
        '',
        array
        (
            $targetFieldName =>
                sprintf
                (
                    '(SELECT `%1$s` FROM `%2$s` WHERE `e`.`entity_id` = `%2$s`.`%3$s` ORDER BY `%4$s` DESC LIMIT 1)',
                    $sourceFieldName,
                    $tableName,
                    $productIdFieldName,
                    $sortFieldName
                )
        )
    )
;

NB: fieldAlreadyJoined() has to be refactored depending on the method chosen (as implemented above).

  • No joy, unfortunately. – indefinitedevil Nov 18 '16 at 10:43
  • Do you mind exposing some more contextual code? – pong Nov 18 '16 at 10:44
  • I don't mind, do you have anything particular in mind? – indefinitedevil Nov 18 '16 at 11:02
  • Can you post $collection from its initialization to its final usage including the assumed foreach block? – pong Nov 18 '16 at 11:04
  • Not so much. The code is in an observer on the magento product grid in Adminhtml. So we're just hitching onto the Magento core code. But I can post the Observer code if you think that's likely to be useful. – indefinitedevil Nov 18 '16 at 11:08
0

Right, so I have come up with a solution but it's not very elegant and it's going to be database-heavy so I'd still rather have a solution for the collection join. But that said, this is the solution I've come up with for the interim.

Basically, I've scrapped the joinField idea entirely and instead created a custom column renderer for the product grid which fetches the correct eBay item ID from the m2epro_ebay_item table by direct SQL. This works and provides the correct item information but is an additional SQL query for each row of the grid on each page load. Not ideal by a long stretch.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.