コレクションでグループ句を使用するとグリッドのページネーションが機能しない


9

私は製品グリッドで作業していますが、ページ付けまたは製品数が機能していません(間違った数が表示されているため)。私のブロックの_preparecollection関数は次のとおりです。コレクションにカテゴリフィルターコードを追加したので、同じidが既に存在する場合のエラーを防ぐためにグループ句を使用する必要があります。

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

私はグーグルを持っていて、答えを得てそれを追加しました 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 2015年

getSelectCountSqlの呼び出しを返すクエリは何ですか?
Amasty、2015

回答:


17

Magentoでのコレクションと遅延読み込み

ページネーションが機能しない理由は、コレクションのカウント方法と、コレクションでの遅延読み込みの動作方法です。

Magentoのコレクションはクラスを実装しCountableます。Magentoでのコレクションの遅延読み込みのため、メソッドcount()が呼び出されるたびに、データを読み込む必要があります。これの回避策として、コレクションはと呼ばれるメソッドを実装しgetSize()ます。それはあなたのSQLステートメントを複製し、それをaにラップし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()を列に追加します。

問題

通常、1つのテーブルでは、これは合計数とともに1行を返します。これが、クエリに対してgetSize()a fetchOne()を実行する理由です。ただし、テーブルの結合やグループ化などの処理を行うと、1行ではなく複数行が返されます。このため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

素晴らしいソリューション。多分誰かが私たちと同じ問題を抱えているので、私は別の可能な解決策を投稿します。私たちのケースでは、コレクションがロードされたグリッドによっては、コレクションが含まれることもあれば、グループ化ステートメントが含まれることもありました。上記のソリューションを使用して、2つの問題が見つかりました。

  1. コレクションが空の場合、サイズは1と評価されますが、ゼロでなければなりません。
  2. コレクションのgroup byステートメントなしでgetSizeメソッドが呼び出された場合、コレクション内のアイテムの数に関係なく、サイズは1として評価されます。

しばらくデバッグした後、ケース1ではパーツが

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

値が0のエントリが1つある配列を返します。そのため、エントリが見つからなかったにもかかわらず、count関数は1を返します。

ケース2では、同じ部分が1つのエントリを持つ配列を返します。その値はコレクションの実際のサイズです。count関数は、値ではなく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;
}

それは私がすでに述べた2つの問題を解決し、私が見る限り、それは他のケースでも機能します。


商品回収モデルの参考にしていただきありがとうございます。それは私を助けました。
Dinesh Yadav
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.