CGridview与自定义数据提供者不从源加载所有记录(延迟加载)

时间:2013-06-30 15:18:31

标签: yii lazy-loading

我是一个为期5天的Yii粉丝试图学习这个伟大框架的绳索。如果你能忍受我阅读我的问题并帮助我,我将非常感激。

所以这里,我正在通过其网络服务检索由在线市场的特定商家销售的产品列表。当我像这样查询Web服务时

api.marketplace.com?merchant_id=1234

我将在JSON中找回包含两个主要数据

的响应
  1. Merchant 1234销售的产品数量( total_products
  2. 所售产品的清单(数组)( list_product )。此数组中的每个元素代表一个不同的Product对象,其中包含两个字段: product_id product_name
  3. 因此,如果 total_products = 934 ,则数组中将有934个元素。 当我把它放在代码中时,我的派生DataProvider看起来像这样

    class ProductDataProvider extends CDataProvider /* or should I extend other better class? */ {
        public function __construct($config = array()) {
        foreach($config as $key=>$value)
            $this->$key=$value;
        }    
    
        protected function fetchData() {
            $request = "api.marketplace.com?merchant_id=1234";
            $response = retrieveProductsAndProcessJSONResponseIntoAppropriateDataStructure($request);
            $this->setTotalItemCount($response->total_products);
    
            if(($pagination=$this->getPagination())!==false)
                $pagination->setItemCount($this->getTotalItemCount());
    
            return $response->list_products;
        }
    
        protected function calculateTotalItemCount() {
            return $this->getTotalItemCount();
        }
    }
    

    我的模特

    class Product extends CModel {
        public $product_id;
        public $product_name;
    
        public function display() {
            return new ProductDataProvider(array(
                'pagination'=>array(
                    'pageSize'=>10,
            ));
        }
    }
    

    和我的观点

    $this->widget('zii.widgets.grid.CGridView', array(
        'id'=>'product-grid',
        'dataProvider'=>$model->display(),
        'columns'=>array(
            'product_id',
            'product_name',
        ),
    ));
    

    这适用于分页和所有这些。然而,检索所有934产品需要花费太长时间。我们可以对Web服务执行此操作。

    api.marketplace.com?merchant_id=1234&page_size=10&page_no=1
    

    这只会检索前10条记录。我们可以使用查询字符串变量 page_no 来检索10个组中的后续产品页面。从Web服务返回的 total_products 仍然是934。

    所以我的问题是,我如何将其付诸实践,以便ProductDataProvider在任何时候只检索10个产品并将其加载到CGridView中? CGridView必须知道总共有934种产品可以实现分页。用户浏览到CGridView的其他页面将触发ProductDataProvider以检索与正在查看的页码对应的下10个记录。我希望我长篇大论的问题是可以理解的。

2 个答案:

答案 0 :(得分:0)

我认为您需要创建自己的自定义数据提供程序。请参阅CDataProvider

的班级参考

Yii中有三个已实施的数据提供者。 CActiveDataProvider,CArrayDataProvider和CSqlDataProvider。您可以将它们用作自定义数据提供程序的模型。

答案 1 :(得分:0)

我有同样的问题。所以,我想:

首先,您应该实现CDataProvider中的所有3个抽象方法。在您的班级fetchKeys()未实施。

其次,分页逻辑应放在fetchData中。例如:

protected function fetchData() {
    $request = "api.marketplace.com?merchant_id=1234";
    // page size
    $request .= "&page_size=".$this->pagination->pageSize;
    // current page
    $request .= "&page_no=".$this->pagination->currentPage;
    $response = retrieveProductsAndProcessJSONResponseIntoAppropriateDataStructure($request);

    return $response->list_products;
}

要使用新的自定义数据提供程序,请按以下方式编写smth:

$dataProvider = new CustomDataProvider();
$pages = new CPagination($dataProvider->getTotalItemCount());
$pages->pageSize = 40; // page size
$dataProvider->pagination = $pages;

数据提供商使用calculateTotalItemCount()获取项目总数。所以,此外,你应该写一些逻辑来提供总项数。猜猜,您应该在API中使用另一种方法来实现此目的。请记住,如果您使用分页,您的数据提供者将执行2个api请求:第一个用于总项目计数,第二个用于当前页面项目。有人可以说只有一个请求就足够了,但在这种情况下,该请求将返回所有数据(934个元素)。太沉重了。

这就是你所需要的一切。