Magento collections когда не работает setPageSize и пагинация

Magento collections когда не работает setPageSize и пагинация

Решил написать о проблеме, которая не часто но встречается везде, где используются коллекции: товары, новости, блог и т.п.

Проблема заключается в том, что вы пытаетесь установить лимит для коллекции но он не работает, так же не работает и пагинация, при выборе любой страницы вы оказываетесь всегда на первой на которой отображаются все записи.

Ниже код в котором находится проблема. Это функция которая добавляет комментарии к каждой новости и тут все плохо 🙂

  • нужно оптимизировать до одного запроса или в лучшем случае информация о комментариях – количество, пишется, собирается отдельным процессом в отдельную колонку, чтобы эти данные уже были доступны сразу, а не когда то потом, – если это важная информация
  • в мадженто коллекции используют лейзи лоад паттерн (Lazy Load) отложенная загрузка, т.е. загрузка данных начнется когда вы будете использовать foreach, count по этому вам нужно быть осторожным, когда вы без надобности собираетесь “пробежаться” по массиву
<?php

/**
 * Add comments to collection
 *
 * @param CommerceLab_News_Model_Mysql4_News_Collection $collection
 * @return $this
 */
private function addCommentToCollection($collection){

    foreach ($collection as $item) {
        $comments = Mage::getModel('clnews/comment')->getCollection()
            ->addNewsFilter($item->getNewsId())
            ->addApproveFilter(CommerceLab_News_Helper_Data::APPROVED_STATUS);
        $item->setCommentsCount(count($comments));
    }

    return $this;
}

?>

В этом случае данные будут загружены и обработаны до класса, который реализует пагинацию, если данные уже были загружены, то их обработка во второй раз не случится, к счастью.

Паттерн Varien_Data_Collection реализует функции из интерфейсов IteratorAggregate, Countable которые загрузят данные

<?php

class Varien_Data_Collection implements IteratorAggregate, Countable {

    /**
     * Implementation of IteratorAggregate::getIterator()
     */
    public function getIterator()
    {
        $this->load();
        return new ArrayIterator($this->_items);
    }
    
    /**
     * Retireve count of collection loaded items
     *
     * @return int
     */
    public function count()
    {
        $this->load();
        return count($this->_items);
    }
    
}
    
?>

 

 

Правильный вариант

Установить флаг загрузки данных – информации о комментариях и после того как данные будут загружены – это важно, добавить информацию о комментариях.

<?php
class Extension_News_Model_Mysql4_News_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
{

    /**
     * Load with comment count flag
     *
     * @var boolean
     */
    protected $_loadWithCommentCount     = false;

    /**
     * Set flag for loading product count
     *
     * @param boolean $flag
     * @return $this
     */
    public function setLoadCommentCount($flag)
    {
        $this->_loadWithCommentCount = $flag;
        return $this;
    }

    public function load($printQuery = false, $logQuery = false)
    {
        parent::load($printQuery, $logQuery);

        if ($this->_loadWithCommentCount === true){
            $this->_loadCommentCount();
        }

        return $this;
    }

    /**
     * Add information about comments - count
     * @return $this
     */
    protected function _loadCommentCount(){

        foreach ($this->_items as $item){

            $select = $this->_conn->select();
            $select->from(
                $this->getTable('news/comment'),
                new Zend_Db_Expr('COUNT(DISTINCT comment_id)')
            )
                ->where('news_id =?', $item->getId())
                ->where('comment_status =?', CommerceLab_News_Helper_Data::APPROVED_STATUS)
            ;

            $item->setCommentsCount(intval($this->_conn->fetchOne($select)));
        }

        return $this;
    }
}