콜렉션에서 그룹 절을 사용할 때 그리드 페이지 매김이 작동하지 않음


9

제품 표에서 작업 중이지만 페이지 매김 또는 제품 수가 작동하지 않습니다 (잘못된 수가 표시됨). 내 블록 _preparecollection 함수는 다음과 같습니다 .i 컬렉션에 카테고리 필터 코드를 추가 했으므로 동일한 id에 대한 오류가 이미 존재하지 않도록 group 절을 사용해야합니다.

    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

어떤 쿼리가 getSelectCountSql에 대한 호출을 반환합니까?
Amasty

답변:


17

마 젠토에서의 수집과 지연 로딩

페이지 매김이 작동하지 않는 이유는 컬렉션이 계산되는 방식과 컬렉션에서 지연로드가 작동하는 방식 때문입니다.

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

기본적으로 한계, 열, 순서 등을 삭제하고 필터를 남겨 둡니다. 그런 다음 COUNT()열에 MySQL 을 추가합니다 .

문제

일반적으로 한 테이블에서 총 개수와 함께 하나의 행을 반환합니다. 이유입니다 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()우리는 PHP 함수 로 fetchAll()싸여있었습니다 count(). 이제 총계가 적절하게 반환됩니다.


2
이것이 내가 SE에 대한 모든 대답을 원했던 방법입니다. 해결책과 깊이.
샴푸

4

훌륭한 솔루션. 어쩌면 누군가가 우리와 같은 문제를 겪을 수도 있으므로 다른 가능한 해결책을 게시 할 것입니다. 우리의 경우 컬렉션이 있었는데 컬렉션에로드 된 그리드에 따라 그룹 별 문장이 포함되기도했습니다. 위의 솔루션을 사용하여 두 가지 문제를 발견했습니다.

  1. 컬렉션이 비어 있으면 크기는 1이지만 값은 1이어야합니다.
  2. 컬렉션의 group by 문없이 getSize 메서드를 호출 한 경우 컬렉션의 항목 수에 관계없이 크기는 1로 계산됩니다.

잠시 동안 디버깅 한 후 1의 경우

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

값이 0 인 항목이 하나 인 배열을 반환합니다. 항목을 찾을 수 없지만 count 함수는 1을 반환합니다.

2의 경우 동일한 부분은 하나의 항목이있는 배열을 반환하며, 값은 컬렉션의 실제 크기입니다. 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;
}

이미 언급 한 두 가지 문제를 해결하고 내가 볼 수있는 한 다른 경우에도 작동합니다.


제품 콜렉션 모델을 참조 해 주셔서 감사합니다. 그것은 나를 도왔다.
Dinesh Yadav
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.