Kotak pagination tidak berfungsi saat menggunakan klausa grup dalam koleksi


9

Saya bekerja pada kisi-kisi produk tetapi pagination atau jumlah produknya tidak berfungsi (karena menampilkan jumlah yang salah). karena fungsi blok _preparecollection saya adalah seperti di bawah ini. Saya telah menambahkan kode filter kategori dalam koleksi jadi saya harus menggunakan klausa grup untuk mencegah kesalahan karena id yang sama sudah ada.

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

Saya punya google dan mendapat jawaban dan menambahkannya ke 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;
}

masukkan deskripsi gambar di sini Tapi tidak berhasil tolong bantu untuk menyelesaikan ini


Kelas apa yang Anda perpanjang? Mage_Adminhtml_Block_Widget_Grid?
B00MER

Ya saya memperpanjangMage_Adminhtml_Block_Widget_Grid
Zaheerabbas

Permintaan apa yang mengembalikan panggilan ke getSelectCountSql?
Amasty

Jawaban:


17

Koleksi dan Pemuatan Malas di Magento

Alasan pagination tidak berfungsi adalah karena bagaimana koleksi dihitung dan bagaimana lazy loading bekerja dengan koleksi.

Koleksi di Magento mengimplementasikan kelas Countable. Karena pemuatan koleksi yang malas di Magento, kapan pun metode count()ini dipanggil, data harus dimuat. Sebagai solusinya, koleksi menerapkan metode yang disebut getSize(). Ini akan mengkloning pernyataan SQL Anda, membungkusnya COUNT()dan mengembalikan hasilnya. Ini memungkinkan koleksi untuk mendapatkan jumlah total tanpa memuat semua data. Ini memungkinkan hal-hal seperti filter ditambahkan pada menit terakhir.

Ini adalah apa Varien_Data_Collection_Db::getSize()dan pasangannya getSelectCountSql()terlihat seperti:

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

Pada dasarnya, itu menjatuhkan batas, kolom, pemesanan, dll dan meninggalkan filter. Kemudian ia menambahkan MySQL COUNT()ke kolom.

Masalah

Biasanya, di satu meja, ini akan mengembalikan satu baris dengan jumlah total. Inilah sebabnya mengapa getSize()melakukan fetchOne()terhadap query. Namun, saat melakukan hal-hal seperti tabel bergabung, bys grup, dan sejenisnya, Anda tidak akan mengembalikan satu baris, Anda akan kembali beberapa. Karena inilah Anda perlu mengubah getSize()metode dalam koleksi Anda.

Solusinya

Seperti inilah seharusnya metode Anda sekarang:

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

Alih-alih fetchOne(), kami menjalankan fungsi PHP yang fetchAll()dibungkus count(). Sekarang total Anda akan kembali dengan tepat.


2
Ini adalah bagaimana saya berharap semua jawaban pada SE itu. Solusi DAN kedalaman.
shampo

4

Solusi bagus Mungkin seseorang memiliki masalah yang sama seperti kita, jadi saya akan memposting solusi lain yang mungkin. Dalam kasus kami, kami memiliki koleksi, yang kadang-kadang termasuk grup dengan pernyataan dan kadang-kadang tidak, tergantung pada kotak di mana koleksi dimuat. Menggunakan solusi di atas, kami menemukan dua masalah:

  1. Jika koleksinya kosong, ukurannya bernilai 1, meskipun harus nol.
  2. Dalam kasus di mana metode getSize dipanggil tanpa grup dengan pernyataan pada koleksi, ukurannya dinilai sebagai 1 tidak peduli berapa banyak item dalam koleksi.

Setelah men-debug beberapa saat kami menemukan, bahwa dalam kasus 1 bagian

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

mengembalikan array yang memiliki satu entri dengan nilai 0. Itulah sebabnya fungsi hitungan mengembalikan 1 meskipun tidak ada entri yang ditemukan.

Dalam kasus 2 bagian yang sama mengembalikan array dengan satu entri, yang nilainya adalah ukuran sebenarnya dari koleksi. Fungsi hitungan lagi mengembalikan 1 dan bukan nilai.

Mencari alternatif, kami menemukan, bahwa koleksi produk menggunakan penulisan ulang fungsi getSelectCountSql (). Kami mengadaptasi ini dan mengubahnya sedikit, yang berakhir dengan solusi ini:

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

Ini memecahkan dua masalah yang sudah saya sebutkan dan sejauh yang saya bisa lihat, itu juga berfungsi untuk kasus lain.


Terima kasih telah memberikan referensi model koleksi produk. Itu membantu saya.
Dinesh Yadav
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.