5

The problem

I have joined the category product list collection (getLoadedProductCollection from Mage_Catalog_Block_Product_List) with a custom table. Because this collection is loaded from _beforeToHtml we have to update it via observer event:

<frontend>
    <events>
        <catalog_block_product_list_collection>
            <observers>
                <promotion_list_collection>
                    <class>promotion/observer</class>
                    <method>catalogBlockProductListCollection</method>
                </promotion_list_collection>
            </observers>
        </catalog_block_product_list_collection>

I am using this as my join:

public function catalogBlockProductListCollection($observer)
{
    $collection = $observer->getEvent()->getCollection();

    $collection->addAttributeToSelect('sku');

    $collection->joinTable(
        array('promotion'=>'custom_promotion'),
        'sku=sku',
        array('up_coupon_upc'=>'up_coupon_upc')
        );

}

But it turns out that that after it is loaded the column up_coupon_upc is not added to the collection. It is, however, available if you $collection->getData() to dump the contents of the loaded collection.

Things I've tried

I assumed that perhaps it wasn't actually adding to the MCMP model in the collection, so I have tried adding the attribute to the select:

    $collection->addAttributeToSelect('up_coupon_upc');

Doesn't work. I tried using various aliases. I tried using $collection->getSelect()->join() instead with the same result.

I also have tried to define other columns - none of which show up either. Doing array('*') adds all columns to my SQL query, but none of the attributes actually show up, though the SQL output from $collection->getSelect() outputs exactly the correct query.

Guesses

I'm guessing that the modification of the collection is actually taking place either only within the scope of the Observer, or the product collection is somehow being load-ed prior to my observer being called.

Or, perhaps I'm just having a monumental fail and I've missed something obvious .

  • What does the dispatchEvent pass in your magento version in 1.8 it only passes the select instead of the collection Mage::dispatchEvent('catalog_category_flat_loadnodes_before', array('select' => $select)) – Martijn Schot Mar 17 '15 at 16:41
  • My apologies - wrong event. Updated. – philwinkle Mar 17 '15 at 16:45
  • And it passes the collection - Mage::dispatchEvent('catalog_block_product_list_collection', array( 'collection' => $this->_getProductCollection() )); – philwinkle Mar 17 '15 at 16:45
  • What does (string)$this->_getProductCollection()->getSelect(); output afterwards? – Martijn Schot Mar 17 '15 at 16:54
  • See the SQL output here: gist.github.com/philwinkle/8840d68d76fcebc2fd22 – philwinkle Mar 17 '15 at 17:01
2

As you said collection could already be loaded (and therefor won't reload). You can check this via $this->_getProductCollection()->isLoaded()

1

Big thanks to Martjin for his help.

In my case the collection was already explicitly loaded by Mage_Review. In order to affect my collection change ahead of Mage_Review I needed to make Mage_Review depend on my module.

Thankfully this is easy to do with my module's app/modules/ registration XML:

<?xml version="1.0"?>
<config>
    <modules>
        <PJ_Promotion>
            <active>true</active>
            <codePool>local</codePool>
        </PJ_Promotion>
        <Mage_Review>
            <depends>
                <PJ_Promotion/>
            </depends>
        </Mage_Review>
    </modules>
</config> 

Additional information

I was able to skirt this without needing to join after all. Taking some inspiration from Mage_Review I instead opted to add the table collection to the product collection by iterating. This is how Mage Review does it:

Event Listener:

public function catalogBlockProductCollectionBeforeToHtml(Varien_Event_Observer $observer)
{
    $productCollection = $observer->getEvent()->getCollection();
    if ($productCollection instanceof Varien_Data_Collection) {
        $productCollection->load();
        Mage::getModel('review/review')->appendSummary($productCollection);
    }

    return $this;
}

Model append method:

/**
 * Append review summary to product collection
 *
 * @param Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection $collection
 * @return Mage_Review_Model_Review
 */
public function appendSummary($collection)
{
    $entityIds = array();
    foreach ($collection->getItems() as $_itemId => $_item) {
        $entityIds[] = $_item->getEntityId();
    }

    if (sizeof($entityIds) == 0) {
        return $this;
    }

    $summaryData = Mage::getResourceModel('review/review_summary_collection')
        ->addEntityFilter($entityIds)
        ->addStoreFilter(Mage::app()->getStore()->getId())
        ->load();

    foreach ($collection->getItems() as $_item ) {
        foreach ($summaryData as $_summary) {
            if ($_summary->getEntityPkValue() == $_item->getEntityId()) {
                $_item->setRatingSummary($_summary);
            }
        }
    }

    return $this;
}

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.