Get Product Collection Containing In-Stock Products Only
To answer the question. You would use this (not very different than your version):
$productCollection = Mage::getResourceModel('catalog/product_collection')
->addAttributeToSelect(array('name', 'image', 'price'))
->addAttributeToFilter('status', array('eq' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED));
Mage::getSingleton('cataloginventory/stock')
->addInStockFilterToCollection($productCollection);
$this->_productCollection = $productCollection;
But I don't know exactly what causes your error, because it seems related to the fact that the getSubmitUrl
/getAddToCartUrl
product param is boolean false, and not to the collection per se.
Perhaps a day late and a dollar short, but instead of doing all this second-step work, you can simply join the cataloginventorystock_stock_status
table to your collection select():
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->getSelect()->join('cataloginventory_stock_status', 'cataloginventory_stock_status.product_id = e.entity_id', array('stock_status'));
$collection->getSelect()->where("`cataloginventory_stock_status`.`stock_status` = 1");
You can do this in conjunction with additional join() or where() clauses. Hope it helps you in the right direction.
Newermind answered the original question correctly; my thanks to him. For future adventurers, here's what was wrong with my code. Special thanks to Melvyn for his help.
Problem
From my code in the question, $this->_productCollection
contains an object. When we iterate over that object in the view, the $_product
variable is an array.
$_products = $this->_productCollection;
foreach ( $_products as $_product ) {
echo gettype( $_product ); // <-- returns type [array]
}
The method at app/code/core/Mage/Catalog/Block/Product/Abstract.php:117
(ultimately) calls getTypeInstance()
. That method is expecting an object, specifically an instance of Mage_Catalog_Model_Product
.
In the view, I was calling $this->getSubmitUrl($_product)
inside the foreach loop:
$_products = $this->_productCollection;
foreach ( $_products as $_product ) {
echo $this->getSubmitUrl( $_product );
}
getSubmitUrl()
is a method of Mage_Catalog_Block_Product_Abstract
, line 115. On line 123 it calls getAddToCartUrl()
, which calls getTypeInstance()
and that is expecting an object. Problem was, I was handing it an array.
Simple OOP principle, but I guess I was too tired to see it. Thx all for the help.
The Solution
So, unfortunately the addInStockFilterToCollection
method returns an inventory stock object - not what I was after. I need a product collection of in-stock products.
Also, the addInStockFilterToCollection
method only works with a Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Link_Product_Collection
collection.
So, how to get the collection? My approach was as follows:
- Get a collection of in-stock products.
- Create an ID array from the result set.
- Get the product collection, using the ID's from the in-stock results.
Here's the code:
$inStockProductIds = array();
$inStockCollection = Mage::getModel('cataloginventory/stock')
->getItemCollection()
->addFieldToFilter('is_in_stock',
array( 'eq' => 1 )
)
->addFieldToFilter( 'entity_id',
array( 'in' => array ('1', '2') )
)
;
if ( $inStockCollection) {
foreach ($inStockCollection as $stockProduct) {
$inStockProductIds[] = $stockProduct->getId();
}
}
$this->_productCollection = Mage::getModel('catalog/product')
->getCollection()
->addAttributeToSelect(
array('name', 'image', 'price')
)
->addIdFilter( $inStockProductIds )
->setPageSize( 2 )
->load();
;
return $this->_productCollection;
That returns a product collection, only containing in-stock products. It's a bit heavy, but it works. I'd appreciate any improvements on this. Thanks.