Phân trang lưới không hoạt động khi sử dụng mệnh đề nhóm trong bộ sưu tập


9

Tôi đang làm việc trên lưới sản phẩm nhưng số trang hoặc số sản phẩm của nó không hoạt động (vì nó hiển thị số đếm sai). vì chức năng _preparecollection của khối của tôi như dưới đây. Tôi đã thêm mã bộ lọc danh mục trong bộ sưu tập nên tôi phải sử dụng mệnh đề nhóm để ngăn lỗi cho cùng một id đã tồn tại.

    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;
    }

Tôi đã có google và nhận được câu trả lời và thêm nó vào 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;
}

nhập mô tả hình ảnh ở đây Nhưng không có may mắn xin vui lòng giúp giải quyết điều này


Bạn đang mở rộng lớp nào? Mage_Adminhtml_Block_Widget_Grid?
B00mer

Có i mở rộngMage_Adminhtml_Block_Widget_Grid
Zaheerabbas

Truy vấn nào trả về cuộc gọi đến getSelectCountSql?
Amasty

Câu trả lời:


17

Bộ sưu tập và tải lười biếng trong Magento

Lý do phân trang không hoạt động là do cách các bộ sưu tập được tính và cách tải lười biếng hoạt động với các bộ sưu tập.

Bộ sưu tập trong Magento thực hiện các lớp Countable. Do lười tải các bộ sưu tập trong Magento, bất cứ khi nào phương thức count()được gọi, dữ liệu phải được tải. Như một giải pháp thay thế, các bộ sưu tập thực hiện một phương thức được gọi là getSize(). Nó sẽ sao chép câu lệnh SQL của bạn, bọc nó COUNT()lại và trả về kết quả. Điều này cho phép một bộ sưu tập có được tổng số mà không tải tất cả dữ liệu. Điều này cho phép những thứ như bộ lọc được thêm vào phút cuối.

Đây là những gì Varien_Data_Collection_Db::getSize()và đối tác của nó getSelectCountSql()trông giống như:

/**
     * 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;
    }

Về cơ bản, nó giảm giới hạn, cột, đặt hàng, vv và để lại các bộ lọc phía sau. Sau đó, nó thêm một MySQL COUNT()vào các cột.

Vấn đề

Thông thường, trên một bảng, điều này sẽ trả về một hàng với tổng số. Đây là lý do tại sao getSize()không fetchOne()chống lại truy vấn. Tuy nhiên, khi thực hiện những việc như tham gia bảng, bys nhóm và tương tự, bạn sẽ không trả về một hàng, bạn sẽ trả lại nhiều. Chính vì điều này mà bạn cần thay đổi getSize()phương thức trong bộ sưu tập của mình.

Giải pháp

Đây là những gì phương pháp của bạn sẽ trông giống như bây giờ:

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 );
    }

Thay vì một fetchOne(), chúng tôi chạy một fetchAll()bọc trong một count()chức năng PHP. Bây giờ tổng số của bạn sẽ trở lại thích hợp.


2
Đây là cách tôi muốn tất cả các câu trả lời trên SE. Một giải pháp VÀ một số độ sâu.
gội đầu

4

Giải pháp tuyệt vời. Có lẽ ai đó có cùng một vấn đề như chúng tôi đã có, vì vậy tôi sẽ đăng một giải pháp khả thi khác. Trong trường hợp của chúng tôi, chúng tôi đã có một bộ sưu tập, đôi khi bao gồm một nhóm bằng câu lệnh và đôi khi không, tùy thuộc vào lưới nơi bộ sưu tập được tải. Sử dụng giải pháp trên, chúng tôi thấy hai vấn đề:

  1. Nếu bộ sưu tập trống, kích thước có giá trị là 1, mặc dù nó phải bằng không.
  2. Trong trường hợp phương thức getSize được gọi mà không có nhóm bằng câu lệnh trên bộ sưu tập, kích thước được định giá là 1 cho dù có bao nhiêu mục trong bộ sưu tập.

Sau khi gỡ lỗi một lúc, chúng tôi phát hiện ra rằng trong trường hợp 1 phần

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

trả về một mảng có một mục nhập có giá trị 0. Đó là lý do tại sao hàm đếm trả về 1 mặc dù không tìm thấy mục nào.

Trong trường hợp 2, cùng một phần trả về một mảng với một mục nhập, có giá trị là kích thước thực của bộ sưu tập. Hàm đếm lại trả về 1 và không phải giá trị.

Tìm kiếm một giải pháp thay thế, chúng tôi phát hiện ra rằng bộ sưu tập sản phẩm sử dụng chức năng viết lại của hàm getSelectCountSql (). Chúng tôi đã điều chỉnh nó và thay đổi nó một chút, kết thúc trong giải pháp này:

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;
}

Nó giải quyết hai vấn đề tôi đã đề cập và theo như tôi thấy, nó cũng hoạt động cho các trường hợp khác.


Cảm ơn bạn đã tham khảo mô hình bộ sưu tập sản phẩm. Nó đã giúp đỡ tôi.
Dinesh Yadav
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.