การแบ่งเลขกริดไม่ทำงานเมื่อใช้ส่วนคำสั่งกลุ่มในการรวบรวม


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
Zaheerabbas

แบบสอบถามใดส่งคืนการเรียกไปยัง getSelectCountSql
Amasty

คำตอบ:


17

ของสะสมและ Lazy Loading ในวีโอไอพี

การแบ่งหน้าเหตุผลไม่ทำงานเนื่องจากการนับจำนวนคอลเล็กชันและวิธีการโหลดแบบไม่ทำงานกับการรวบรวม

คอลเล็กชันใน 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
นี่คือวิธีที่ฉันต้องการคำตอบทั้งหมดใน SE คือ ทางออกและความลึกบางส่วน
แชมพู

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

มันแก้ปัญหาทั้งสองเรื่องที่ฉันพูดไปแล้วและเท่าที่ฉันเห็นมันยังใช้ได้กับกรณีอื่น ๆ


ขอบคุณที่ให้การอ้างอิงรูปแบบการรวบรวมผลิตภัณฑ์ มันช่วยฉัน
Dinesh Yadav
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.