Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting the first collection item without breaking pager

Tags:

magento

I posted a question about this earlier, but I have more information now and I thought it best to post a new one rather than modify (sorry if that's not proper protocol). You can find my original question here.

Anyhow, the initial problem was that I wanted to inspect the first item in a collection inside the List.php class just after setting the collection so that I could scrape the category and use that to show reviews. This was all based off a custom module, so there were a lot of variables. I have since tried it on a default Magento sample store and only added ONE line to app/code/core/Mage/catalog/Block/Product/List.php to break the pager. Here are the details. If you have any ideas why this is happening, please let me know as I'm stuck

First, open app/code/core/Mage/catalog/Block/Product/List.php and locate the _getProductCollection function. At the end of the if (is_null...) block, add $_foo123 = $this->_productCollection->getFirstItem(); so you have a function that looks like this:

protected function _getProductCollection()
{
    if (is_null($this->_productCollection)) {
        $layer = $this->getLayer();
        /* @var $layer Mage_Catalog_Model_Layer */
        if ($this->getShowRootCategory()) {
            $this->setCategoryId(Mage::app()->getStore()->getRootCategoryId());
        }

        // if this is a product view page
        if (Mage::registry('product')) {
            // get collection of categories this product is associated with
            $categories = Mage::registry('product')->getCategoryCollection()
            ->setPage(1, 1)
            ->load();
            // if the product is associated with any category
            if ($categories->count()) {
                // show products from this category
                $this->setCategoryId(current($categories->getIterator()));
            }
        }

        $origCategory = null;
        if ($this->getCategoryId()) {
            $category = Mage::getModel('catalog/category')->load($this->getCategoryId());
            if ($category->getId()) {
                $origCategory = $layer->getCurrentCategory();
                $layer->setCurrentCategory($category);
            }
        }
        $this->_productCollection = $layer->getProductCollection();

        $this->prepareSortableFieldsByCategory($layer->getCurrentCategory());

        if ($origCategory) {
            $layer->setCurrentCategory($origCategory);
        }

        //THIS LINE BREAKS THE PAGER
        $_foo123 = $this->_productCollection->getFirstItem();
    }

    return $this->_productCollection;
}

Now, simply go to any product list that uses that class (category view, for instance) and you'll see what I mean. No matter what you choose under Show XX per page in the toolbar, it will always show you all items in the list. If you comment out that $_foo123... line, it works fine.

What gives??

P.S. I know I'm not supposed to edit core files...this is just an example :)

like image 878
Mageician Avatar asked Dec 10 '22 08:12

Mageician


1 Answers

The reason is because when you call getFirstItem() (or just about any other retrieval method) on a collection that collection is loaded. Any subsequent operation ignores the database and uses only the loaded data, filters have no effect because they are SQL only, ditto for pagination and selected columns. The workaround is to use a second collection based on the first.

$secondCollection = clone $firstCollection;
$secondCollection->clear();
$_foo123 = $secondCollection->getFirstItem();

The clear() method unloads the data for that collection, forcing it to access the database again next time.

like image 65
clockworkgeek Avatar answered Jan 21 '23 13:01

clockworkgeek