Під час використання групового застереження в колекції не використовується пагинація сітки


9

Я працюю над сіткою продукту, але її сторінки та кількість сторінок не працюють (так як вона відображає неправильну кількість). як мій блок _preparecollection функція, як показано нижче. Я додав код фільтра категорії в колекцію, тому мені доведеться використовувати груповий пункт, щоб запобігти помилці для того ж ідентифікатора вже існує.

    protected function _prepareCollection()
    {
        $store = $this->_getStore();
        $collection = Mage::getModel('catalog/product')->getCollection()
            ->addAttributeToSelect('sku')
            ->addAttributeToSelect('name')
            ->addAttributeToSelect('attribute_set_id')
            ->addAttributeToSelect('type_id')
            ->joinField('category_id',
                'catalog/category_product',
                'category_id',
                'product_id=entity_id',
                null,
                'left');
$collection->addAttributeToFilter('category_id', array('in' => array(4,10)))
            ->distinct(true);
            $collection->getSelect()->group('e.entity_id');


        if (Mage::helper('catalog')->isModuleEnabled('Mage_CatalogInventory')) {
            $collection->joinField('qty',
                'cataloginventory/stock_item',
                'qty',
                'product_id=entity_id',
                '{{table}}.stock_id=1',
                'left');
        }
        $collection->joinField('position',
                'catalog/category_product',
                'position',
                'product_id=entity_id',
                null,
                'left');
        $collection->joinField('websites',
            'catalog/product_website',
            'website_id',
            'product_id=entity_id',
            null,
            'left');
        if ($store->getId()) {
            //$collection->setStoreId($store->getId());
            $adminStore = Mage_Core_Model_App::ADMIN_STORE_ID;
            $collection->addStoreFilter($store);
            $collection->joinAttribute(
                'name',
                'catalog_product/name',
                'entity_id',
                null,
                'inner',
                $adminStore
            );

            $collection->joinAttribute(
                'custom_name',
                'catalog_product/name',
                'entity_id',
                null,
                'inner',
                $store->getId()
            );
            $collection->joinAttribute(
                'status',
                'catalog_product/status',
                'entity_id',
                null,
                'inner',
                $store->getId()
            );
            $collection->joinAttribute(
                'visibility',
                'catalog_product/visibility',
                'entity_id',
                null,
                'inner',
                $store->getId()
            );
            $collection->joinAttribute(
                'price',
                'catalog_product/price',
                'entity_id',
                null,
                'left',
                $store->getId()
            );
        }
        else {
            $collection->addAttributeToSelect('price');
            $collection->joinAttribute('status', 'catalog_product/status', 'entity_id', null, 'inner');
            $collection->joinAttribute('visibility', 'catalog_product/visibility', 'entity_id', null, 'inner');
        }

        $this->setCollection($collection);

        parent::_prepareCollection();
        $this->getCollection()->addWebsiteNamesToResult();
        return $this;
    }

У мене був google, я отримав відповідь і додав його lib/varian/data/collection/db.php

    public function getSelectCountSql()
{
     $this->_renderFilters();

        $countSelect = clone $this->getSelect();
        $countSelect->reset(Zend_Db_Select::ORDER);
        $countSelect->reset(Zend_Db_Select::LIMIT_COUNT);
        $countSelect->reset(Zend_Db_Select::LIMIT_OFFSET);
        $countSelect->reset(Zend_Db_Select::COLUMNS);

        if(count($this->getSelect()->getPart(Zend_Db_Select::GROUP)) > 0) {
            $countSelect->reset(Zend_Db_Select::GROUP);
            $countSelect->distinct(true);
            $group = $this->getSelect()->getPart(Zend_Db_Select::GROUP);
            $countSelect->columns("COUNT(DISTINCT ".implode(", ", $group).")");
        } else {
            $countSelect->columns('COUNT(*)');
        }
        return $countSelect;
}

введіть тут опис зображення Але не щастить, будь ласка, допоможіть вирішити це питання


Який клас ти розширюєш? Mage_Adminhtml_Block_Widget_Grid?
B00MER

Так, я продовжуюMage_Adminhtml_Block_Widget_Grid
Захерабас

Який запит повертає виклик до getSelectCountSql?
Amasty

Відповіді:


17

Колекції та ліниві завантаження в Magento

Причина пагинації не працює в тому, як рахуються колекції і як ледаче завантаження працює з колекціями.

Колекції в Magento реалізують клас Countable. Через ледачу завантаження колекцій у Magento, щоразу, коли метод count()викликається, дані потрібно завантажувати. Як вирішення цього, колекції реалізують метод, який називається getSize(). Він буде клонувати ваш оператор SQL, загортати його в COUNT()і повертати результат. Це дозволило колекції отримати загальну кількість, не завантажуючи всіх даних. Це дозволяє додавати такі речі, як фільтри, в останню хвилину.

Ось як Varien_Data_Collection_Db::getSize()це і getSelectCountSql()виглядає партнер :

/**
     * Get collection size
     *
     * @return int
     */
    public function getSize()
    {
        if (is_null($this->_totalRecords)) {
            $sql = $this->getSelectCountSql();
            $this->_totalRecords = $this->getConnection()->fetchOne($sql, $this->_bindParams);
        }
        return intval($this->_totalRecords);
    }

    /**
     * Get SQL for get record count
     *
     * @return Varien_Db_Select
     */
    public function getSelectCountSql()
    {
        $this->_renderFilters();

        $countSelect = clone $this->getSelect();
        $countSelect->reset(Zend_Db_Select::ORDER);
        $countSelect->reset(Zend_Db_Select::LIMIT_COUNT);
        $countSelect->reset(Zend_Db_Select::LIMIT_OFFSET);
        $countSelect->reset(Zend_Db_Select::COLUMNS);

        $countSelect->columns('COUNT(*)');

        return $countSelect;
    }

В основному, вона скасовує ліміти, стовпці, упорядкування тощо та залишає фільтри позаду. Потім він додає MySQL COUNT()до стовпців.

Проблема

Зазвичай на одній таблиці це повертає один ряд із загальною кількістю. Ось чому getSize()це fetchOne()проти запиту. Однак, виконуючи такі речі, як приєднання таблиці, групові байси тощо, ви не повернете один рядок, ви повернете кілька. Саме через це вам потрібно змінити getSize()метод у вашій колекції.

Рішення

Ось як має виглядати ваш метод зараз:

public function getSize() {

        if ( is_null( $this->_totalRecords ) ) {
            $sql = $this->getSelectCountSql();
            // fetch all rows since it's a joined table and run a count against it.
            $this->_totalRecords = count( $this->getConnection()->fetchall( $sql, $this->_bindParams ) );
        }

        return intval( $this->_totalRecords );
    }

Замість того , щоб fetchOne()ми провели fetchAll()загорнуті в count()функції PHP. Тепер ваші суми повернуться належним чином.


2
Ось так я хотів би, щоб усі відповіді на ІП були. Розчин І деяка глибина.
шампунь

4

Прекрасне рішення. Можливо, у когось така ж проблема, як у нас, тому я опублікую ще одне можливе рішення. У нашому випадку у нас була колекція, яка іноді включала групу за заявою, а іноді і не, залежно від сітки, куди колекція завантажена. Використовуючи рішення вище, ми виявили дві проблеми:

  1. Якщо колекція порожня, розмір оцінюється як 1, хоча він повинен дорівнювати нулю.
  2. У випадках, коли метод getSize викликався без групи за допомогою заяви про колекцію, розмір оцінюється як 1, незалежно від того, скільки предметів у колекції.

Через деякий час налагодження ми з'ясували, що у випадку 1 частина

$this->getConnection()->fetchall( $sql, $this->_bindParams ) 

повертає масив, який має один запис зі значенням 0. Ось чому функція count повертає 1, хоча записів не знайдено.

У випадку 2 та сама частина повертає масив з одним записом, значення якого - реальний розмір колекції. Функція підрахунку знову повертає 1, а не значення.

Шукаючи альтернативу, ми з’ясували, що в колекції продуктів використовується перезапис функції getSelectCountSql (). Ми адаптували це і трохи змінили, що закінчилося цим рішенням:

public function getSelectCountSql()
{
    $countSelect = parent::getSelectCountSql();
    $countSelect->reset(Zend_Db_Select::COLUMNS);
    $countSelect->reset(Zend_Db_Select::GROUP);
    $countSelect->columns('COUNT(DISTINCT item_id)');

    return $countSelect;
}

Він вирішує два питання, про які я вже згадував, і наскільки я бачу, він також працює для інших випадків.


Дякуємо, що надали посилання на модель колекції товарів. Це мені допомогло.
Дінеш Ядав
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.