1

I have an question about Magento that I don't know if is a bug or not.

Category Collection:

I used an Observer to filter only the customer categories (business rule)

My_Module/config.xml

<frontend>
        <events>
            <catalog_category_collection_load_before>
                <observers>
                    <my_module>
                        <type>model</type>
                        <class>my_module/catalog_observer</class>
                        <method>removeUnavailableCategories</method>
                    </my_module>
                </observers>
            </catalog_category_collection_load_before>
        </events>
</frontend>

My_Module/Model/Catalog/Observer.php

<?php
class My_Module_Model_Catalog_Observer
{
    function removeUnavailableCategories($observer)
    {
        $collection = $observer->getCategoryCollection();

        $allowedCategories = array();

         foreach (Mage::helper('my_module/customer')->getAllowedCategories() as $category)
         {
             $allowedCategories[]['like'] = $category->getPath();
             $allowedCategories[]['like'] = $category->getPath() . '/%';
         }

        if (count($allowedCategories) > 0)
        {
            $collection->addFieldToFilter('path', $allowedCategories);
        }
        else
        {
            /**
             * Clear collection
             */
            $collection->getSelect()->reset(Zend_Db_Select::WHERE);
            $collection->getSelect()->where('e.entity_id < 0');
        }
    }
}

As you can see, I put a filter to show only the categories allowed for the customer.

But, when I use the function "getAllIds" in the category collection, this observer is not called:

Mage::getModel('catalog/category')->getCollection()->getAllIds();

I do it like this:

Mage::getModel('catalog/category')->getCollection()->load()->getAllIds();

And it worked.

But I don't like this. Since the function "getAllIds" makes the search again:

Mage_Eav_Model_Entity_Collection_Abstract

protected function _getAllIdsSelect($limit = null, $offset = null)
{
    $idsSelect = clone $this->getSelect();
    $idsSelect->reset(Zend_Db_Select::ORDER);
    $idsSelect->reset(Zend_Db_Select::LIMIT_COUNT);
    $idsSelect->reset(Zend_Db_Select::LIMIT_OFFSET);
    $idsSelect->reset(Zend_Db_Select::COLUMNS);
    $idsSelect->columns('e.' . $this->getEntity()->getIdFieldName());
    $idsSelect->limit($limit, $offset);

    return $idsSelect;
}

public function getAllIds($limit = null, $offset = null)
{
    return $this->getConnection()->fetchCol($this->_getAllIdsSelect($limit, $offset), $this->_bindParams);
}

My question is:

Is it correct use to call the function _beforeLoad before search for the IDs?

Like this:

public function getAllIds($limit = null, $offset = null)
{
    $this->_beforeLoad();
    return $this->getConnection()->fetchCol($this->_getAllIdsSelect($limit, $offset), $this->_bindParams);
}

OR

protected function _getAllIdsSelect($limit = null, $offset = null)
{
    $this->_beforeLoad();

    $idsSelect = clone $this->getSelect();
    $idsSelect->reset(Zend_Db_Select::ORDER);
    $idsSelect->reset(Zend_Db_Select::LIMIT_COUNT);
    $idsSelect->reset(Zend_Db_Select::LIMIT_OFFSET);
    $idsSelect->reset(Zend_Db_Select::COLUMNS);
    $idsSelect->columns('e.' . $this->getEntity()->getIdFieldName());
    $idsSelect->limit($limit, $offset);

    return $idsSelect;
}

Or is there something that I don't know?

1 Answer 1

1

It's intended behavior. getAllIds() is meant to be used for a single COUNT() query and does not actually load the collection. So triggering the before_load event does not make sense semantically.

I would not recommend to rewrite the category model to always call _beforeLoad() as you suggested because that might result in undesired side effects.

On the other hand I understand why you'd want it because most of the time you change filters in this event and having those on the count query would be useful.

A possible solution is to move the actual filter logic from the observer to a different class (could be a helper) and call it from the observer and also in the places where you use getAllIds() in your code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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