コレクションでグループ句を使用するとグリッドのページネーションが機能しない
-
12-12-2019 - |
質問
製品グリッドで作業していますが、そのページネーションまたは製品カウントが機能しません(間違ったカウントが表示されるため)。私のブロック _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;
}
しかし、運が悪いので、これを解決するのを手伝ってください
解決
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として大きさを評価します。
デバッグした後、私達が見つけたときに、それを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つの問題を解決し、私が見ることができる限りでは、それはそれ以外の場合も機能します。