Magento product list collection modification

According to Marius, events are always the best approach to modify and apply filter on product listing page. This way, your changes are independent of the presentation layer (theme). If you have 2 websites with different themes you will have all modifications in one place. Changing the template file may result in pagination problems.

I had a requirement to customize product listing (category) page such that if a configurable product is present, and even a single associated product for that configurable product is out of stock, configurable product should not appear in product listing (category) page.

I’ve created my own module and observer and customized it. Here goes the code:

app/etc/modules/Retailon_Configurable.xml

<config>
<modules>
<Retailon_Configurable>
<active>true</active>
<codePool>local</codePool>
</Retailon_Configurable>
</modules>
</config>

app/code/local/Retailon/etc/config.xml

<?xml version="1.0"?>
<config>
<global>
<models>
<retailon_configurable>
<class>Retailon_Configurable_Model</class>
</retailon_configurable>
</models>
</global>
<frontend>
<events>
<catalog_block_product_list_collection>
<observers>
<retailon_configurable_list>
<type>singleton</type>
<class>retailon_configurable/observer</class>
<method>addInStockOnlyFilter</method>
-</retailon_configurable_list>
</observers>
</catalog_block_product_list_collection>
</events>
</frontend>
</config>

app/code/local/Retailon/Model/Observer.php

<?php

class Retailon_Configurable_Model_Observer {
/**
* Observes the catalog_block_product_list_collection event
*/
public function addInStockOnlyFilter($observer){
$productCollection = $observer->getEvent()->getCollection();

foreach ($productCollection as $product) {
if ($product->getTypeId() == "configurable"){
$product->getTypeInstance(true)->getUsedProducts ( null, $product);
foreach ($product->getTypeInstance(true)->getUsedProducts ( null, $product) as $simple) {
//all associated pro
if($simple->getStockItem()->getQty() < 1 ){
$proArray[] = $product->getId();
}
$stock = Mage::getModel('cataloginventory/stock_item')->loadByProduct($simple)->getQty();
echo $simple->getName()." with size ".$simple->getSize()." have a stock of ".$stock. " have sku "
.$simple->getSku()."Qty of ".$simple->getStockItem()->getQty();
echo '<br/>';
}
}
}

if(count($proArray)){
foreach ($proArray as $key) {
$productCollection->removeItemByKey($key);
}
}

$observer->getEvent()->setCollection($productCollection);
}

}