×
关于 Yii(About Yii)从 Yii 1.1 升级

入门(Getting Started)

安装 Yii运行应用第一次问候使用 Forms玩转 Databases用 Gii 生成代码更上一层楼(Looking Ahead)

应用结构

结构概述(Overview)入口脚本(Entry Scripts)应用(Applications)应用组件(Components)控制器(Controllers)模型(Models)视图(Views)模块(Modules)过滤器(Filters)小部件(Widgets)前端资源(Assets)扩展(Extensions)

请求处理

运行概述(Overview)引导(Bootstrapping)路由引导与创建 URL请求(Requests)响应(Responses)Sessions and Cookies错误处理(Handling Errors)日志(Logging)

关键概念(Key Concepts)

组件(Components)属性(Properties)事件(Events)行为(Behaviors)配置(Configurations)别名(Aliases)类自动加载(Class Autoloading)服务定位器(Service Locator)依赖注入容器

配合数据库工作

数据库访问(Data Access)查询生成器(Query Builder)活动记录(Active Record)数据库迁移(Migrations)SphinxRedisMongoDBElasticSearch

接收用户数据

创建表单(Creating Forms)输入验证(Validating Input)文件上传(Uploading Files)收集列表输入多模型同时输入在客户端扩展 ActiveForm

显示数据

格式化输出数据分页(Pagination)排序(Sorting)数据提供器(Data Providers)数据小部件(Data Widgets)操作客户端脚本主题(Theming)

安全(Security)

认证(Authentication)授权(Authorization)处理密码(Passwords)加密(Cryptography)客户端认证(Auth Clients)安全领域的最佳实践

缓存(Caching)

概述(Overview)数据缓存(Data Caching)片段缓存(Fragment Caching)分页缓存(Page Caching)HTTP 缓存(HTTP Caching)

RESTful Web 服务

快速入门(Quick Start)资源(Resources)控制器(Controllers)路由(Routing)格式化响应(Response Formatting)授权验证(Authentication)速率限制(Rate Limiting)版本化(Versioning)错误处理(Error Handling)

开发工具

调试工具栏和调试器使用 Gii 生成代码TBD 生成 API 文档

测试(Testing)

概述(Overview)搭建测试环境单元测试(Unit Tests)功能测试(Functional Tests)验收测试(Acceptance Tests)测试夹具(Fixtures)

高级专题(Special Topics)

高级应用模版从头构建自定义模版控制台命令核心验证器(Core Validators)Docker国际化(Internationalization)收发邮件(Mailing)性能优化共享主机环境模板引擎集成第三方代码使用 Yii 作为微框架

小部件(Widgets)

Bootstrap 小部件jQuery UI 小部件

助手类(Helpers)

助手一览(Overview)Array 助手(ArrayHelper)Html 助手(Html)Url 助手(Url)

数据提供器(Data Providers)


在 Pagination 和 Sorting 部分, 我们已经介绍了如何允许终端用户选择一个特定的数据页面,根据一些字段对它们进行展现与排序。 因为分页和排序数据的任务是很常见的,所以Yii提供了一组封装好的data provider类。

数据提供者是一个实现了 yiidataDataProviderInterface 接口的类。 它主要用于获取分页和数据排序。它经常用在 data widgets 小物件里,方便终端用户进行分页与数据排序。

下面的数据提供者类都包含在Yii的发布版本里面:

  • yiidataActiveDataProvider:使用 yiidbQuery 或者 yiidbActiveQuery 从数据库查询数据并且以数组项的方式或者 Active Record实例的方式返回。
  • yiidataSqlDataProvider:执行一段SQL语句并且将数据库数据作为数组返回。
  • yiidataArrayDataProvider:将一个大的数组依据分页和排序规格返回一部分数据。

所有的这些数据提供者遵守以下模式:

// 根据配置的分页以及排序属性来创建一个数据提供者
$provider = new XyzDataProvider([
    'pagination' => [...],
    'sort' => [...],
]);

// 获取分页和排序数据
$models = $provider->getModels();

// 在当前页获取数据项的数目
$count = $provider->getCount();

// 获取所有页面的数据项的总数
$totalCount = $provider->getTotalCount();

你可以通过配置 yiidataBaseDataProvider::pagination 和 yiidataBaseDataProvider::sort 的属性来设定数据提供者的分页和排序行为。属性分别对应于 yiidataPagination 和 yiidataSort。 你也可以对它们配置false来禁用分页和排序特性。

Data widgets,诸如 yiigridGridView,有一个属性名叫 dataProvider ,这个属性能够提供一个 数据提供者的示例并且可以显示所提供的数据,例如,

echo yiigridGridView::widget([
    'dataProvider' => $dataProvider,
]);

这些数据提供者的主要区别在于数据源的指定方式上。在下面的部分,我们将详细介绍这些数据提供者的使用方法。

活动数据提供者

为了使用 yiidataActiveDataProvider,你应该配置其 yiidataActiveDataProvider::query 的属性。 它既可以是一个 yiidbQuery 对象,又可以是一个 yiidbActiveQuery 对象。假如是前者,返回的数据将是数组; 如果是后者,返回的数据可以是数组也可以是 Active Record 对象。 例如,

use yiidataActiveDataProvider;

$query = Post::find()->where(['status' => 1]);

$provider = new ActiveDataProvider([
    'query' => $query,
    'pagination' => [
        'pageSize' => 10,
    ],
    'sort' => [
        'defaultOrder' => [
            'created_at' => SORT_DESC,
            'title' => SORT_ASC,
        ]
    ],
]);

// 返回一个Post实例的数组
$posts = $provider->getModels();

假如在上面的例子中,$query 用下面的代码来创建,则数据提供者将返回原始数组。

use yiidbQuery;

$query = (new Query())->from('post')->where(['status' => 1]);

注意:假如查询已经指定了 orderBy 从句,则终端用户给定的新的排序说明(通过 sort 来配置的)将被添加到已经存在的从句中。 任何已经存在的 limit 和 offset 从句都将被终端用户所请求的分页(通过 pagination 所配置的)所重写。

默认情况下,yiidataActiveDataProvider使用 db 应用组件来作为数据库连接。你可以通过配置 yiidataActiveDataProvider::db 的属性来使用不同数据库连接。

SQL数据提供者

yiidataSqlDataProvider 应用的时候需要结合需要获取数据的SQL语句。基于 yiidataSqlDataProvider::sort 和 yiidataSqlDataProvider::pagination 规格,数据提供者会根据所请求的数据页面(期望的顺序)来调整 ORDER BY 和 LIMIT 的SQL从句。

为了使用 yiidataSqlDataProvider,你应该指定 yiidataSqlDataProvider::sql 属性以及 yiidataSqlDataProvider::totalCount 属性,例如,

use yiidataSqlDataProvider;

$count = Yii::$app->db->createCommand('
    SELECT COUNT(*) FROM post WHERE status=:status
', [':status' => 1])->queryScalar();

$provider = new SqlDataProvider([
    'sql' => 'SELECT * FROM post WHERE status=:status',
    'params' => [':status' => 1],
    'totalCount' => $count,
    'pagination' => [
        'pageSize' => 10,
    ],
    'sort' => [
        'attributes' => [
            'title',
            'view_count',
            'created_at',
        ],
    ],
]);

// 返回包含每一行的数组
$models = $provider->getModels();

说明:yiidataSqlDataProvider::totalCount 的属性只有你需要分页数据的时候才会用到。 这是因为通过 yiidataSqlDataProvider::sql 指定的SQL语句将被数据提供者所修改并且只返回当前页面数据。 数据提供者为了正确计算可用页面的数量仍旧需要知道数据项的总数。

数组数据提供者

yiidataArrayDataProvider 非常适用于大的数组。数据提供者允许你返回一个经过一个或者多个字段排序的数组数据页面。 为了使用 yiidataArrayDataProvider,你应该指定 yiidataArrayDataProvider::allModels 属性 作为一个大的数组。 这个大数组的元素既可以是一些关联数组(例如:DAO查询出来的结果)也可以是一些对象(例如:Active Record实例) 例如,

use yiidataArrayDataProvider;

$data = [
    ['id' => 1, 'name' => 'name 1', ...],
    ['id' => 2, 'name' => 'name 2', ...],
    ...
    ['id' => 100, 'name' => 'name 100', ...],
];

$provider = new ArrayDataProvider([
    'allModels' => $data,
    'pagination' => [
        'pageSize' => 10,
    ],
    'sort' => [
        'attributes' => ['id', 'name'],
    ],
]);

// 获取当前请求页的每一行数据
$rows = $provider->getModels();

注意:数组数据提供者与 Active Data Provider 和 SQL Data Provider 这两者进行比较的话, 会发现数组数据提供者没有后面那两个高效,这是因为数组数据提供者需要加载所有的数据到内存中。

数据键的使用

当使用通过数据提供者返回的数据项的时候,你经常需要使用一个唯一键来标识每一个数据项。 举个例子,假如数据项代表的是一些自定义的信息,你可能会使用自定义ID作为键去标识每一个自定义数据。 数据提供者能够返回一个通过 yiidataDataProviderInterface::getModels() 返回的键与数据项相对应的列表。 例如,

use yiidataActiveDataProvider;

$query = Post::find()->where(['status' => 1]);

$provider = new ActiveDataProvider([
    'query' => Post::find(),
]);

// 返回包含Post对象的数组
$posts = $provider->getModels();

// 返回与$posts相对应的主键值
$ids = $provider->getKeys();

在上面的例子中,因为你提供给 yiidataActiveDataProvider 一个 yiidbActiveQuery 对象, 它是足够智能地返回一些主键值作为键。你也可以明确指出键值应该怎样被计算出来,计算的方式是通过使用一个字段名或者一个可调用的计算键值来配置。 例如,

// 使用 "slug" 字段作为键值
$provider = new ActiveDataProvider([
    'query' => Post::find(),
    'key' => 'slug',
]);

// 使用md5(id)的结果作为键值
$provider = new ActiveDataProvider([
    'query' => Post::find(),
    'key' => function ($model) {
        return md5($model->id);
    }
]);

创建自定义数据提供者

为了创建自定义的数据提供者类,你应该实现 yiidataDataProviderInterface 接口。 一个简单的方式是从 yiidataBaseDataProvider 去扩展,这种方式允许你关注数据提供者的核心逻辑。 这时,你主要需要实现下面的一些方法:

  • yiidataBaseDataProvider::prepareModels():准备好在当前页面可用的数据模型,并且作为一个数组返回它们。

  • yiidataBaseDataProvider::prepareKeys():接受一个当前可用的数据模型的数组,并且返回一些与它们相关联的键。

  • yiidataBaseDataProvider::prepareTotalCount(): 在数据提供者中返回一个标识出数据模型总数的值。

下面是一个数据提供者的例子,这个数据提供者可以高效地读取CSV数据:

fileObject = new SplFileObject($this->filename);
    }

    /**
     * @inheritdoc
     */
    protected function prepareModels()
    {
        $models = [];
        $pagination = $this->getPagination();

        if ($pagination === false) {
            // in case there's no pagination, read all lines
            while (!$this->fileObject->eof()) {
                $models[] = $this->fileObject->fgetcsv();
                $this->fileObject->next();
            }
        } else {
            // in case there's pagination, read only a single page
            $pagination->totalCount = $this->getTotalCount();
            $this->fileObject->seek($pagination->getOffset());
            $limit = $pagination->getLimit();

            for ($count = 0; $count < $limit; ++$count) {
                $models[] = $this->fileObject->fgetcsv();
                $this->fileObject->next();
            }
        }

        return $models;
    }

    /**
     * @inheritdoc
     */
    protected function prepareKeys($models)
    {
        if ($this->key !== null) {
            $keys = [];

            foreach ($models as $model) {
                if (is_string($this->key)) {
                    $keys[] = $model[$this->key];
                } else {
                    $keys[] = call_user_func($this->key, $model);
                }
            }

            return $keys;
        } else {
            return array_keys($models);
        }
    }

    /**
     * @inheritdoc
     */
    protected function prepareTotalCount()
    {
        $count = 0;

        while (!$this->fileObject->eof()) {
            $this->fileObject->next();
            ++$count;
        }

        return $count;
    }
}

分类导航

关注微信下载离线手册

bootwiki移动版 bootwiki
(群号:472910771)