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

magento.stackexchange https://magento.stackexchange.com//questions/50285

質問

製品グリッドで作業していますが、そのページネーションまたは製品カウントが機能しません(間違ったカウントが表示されるため)。私のブロック _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;
}

enter image description hereしかし、運が悪いので、これを解決するのを手伝ってください

役に立ちましたか?

解決

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() 柱に。

問題

通常、1 つのテーブルでは、合計数を含む 1 つの行が返されます。これが理由です getSize() ありません 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つの問題が見つかりました。

  1. コレクションが空の場合、サイズは1として値が1として値です。
  2. 集録メソッドがコレクション上のグループによってグループなしで呼び出された場合には、コレクションに含まれている項目の数に関係なく、1として大きさを評価します。

    デバッグした後、私達が見つけたときに、それを1の場合はその

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

    値0の入力を1つ持つ配列を返します。 それが、エントリが見つからなかったが、カウント関数が1を返す理由です。

    ケース2では、同じ部分が1つのエントリを持つ配列を返します。その値はコレクションの実サイズです。カウント関数は再び値を返し、値は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つの問題を解決し、私が見ることができる限りでは、それはそれ以外の場合も機能します。

ライセンス: CC-BY-SA帰属
所属していません magento.stackexchange
scroll top