1. 最小化用法
控制器:
DataProvider 自行解决了数据分页甚至是排序问题,以下提供了 yii\data\ActiveDataProvider
和 yii\data\ArrayDataProvider
的用法,yii\data\SqlDataProvider
还没遇到需要用它的情况,不做介绍。
use app\models\User;
use yii\data\ActiveDataProvider;
use yii\data\ArrayDataProvider;
use yii\db\Query;
/**
* 使用 ActiveDataProvider
*
* 使用 ActiveDataProvider 的好处:
* 不用自己计算数据总数
* 不用自己做分页控制
*/
public function actionDemoA()
{
$query = User::find()/*->asArray()*/;// 加上 asArray() 可以让每条数据都是数组
// 或者
$query = (new Query())->from(User::tableName());
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
return $this->render('users', [
'dataProvider' => $dataProvider,
]);
}
/**
* 使用 ArrayDataProvider
*
* ArrayDataProvider 是对现成的数组进行分页和排序,数据量太大的话需要自己掂量一下
*/
public function actionDemoB()
{
// 注意这里查询比上面多了 all()
$data = User::find()/*->asArray()*/->all();
// 或者
$data = (new Query())->from(User::tableName())->all();
// 或者
$data = [
[
'id' => 1,
'user_name' => 'a',
// ...
],
[
'id' => 2,
'user_name' => 'b',
// ...
],
// ...
];
$dataProvider = new ArrayDataProvider([
'allModels' => $data,
]);
return $this->render('users', [
'dataProvider' => $dataProvider,
]);
}
视图:
直接使用 DataProvider
use yii\widgets\LinkPager;
/**
* @var $this \yii\web\View
* @var $dataProvider \yii\data\ActiveDataProvider
*/
if ($dataProvider->totalCount) {
foreach ($dataProvider->models as $model) {
echo ($model->id, '<br>', $model->username, '<br>');
}
} else {
echo '没有数据';
}
// 输出分页链接
echo LinkPager::widget([
'pagination' => $dataProvider->pagination,
]) ?>
// 输出排序链接
echo $dataProvider->sort->link('id');
echo $dataProvider->sort->link('name');
循环里的
$model
变量是对象还是数组,取决于使用 ActiveRecord 查询时是否执行了asArray()
方法。
使用 GridView
如果你觉得上面自己写各种 html 麻烦的话,那么用 GridView 一定是更方便的方法,它使用 DataProvider 来帮你做好了上面做的事情,如果你对表格样式不满意,又不想每个页面都做大量配置,你还可以用 DI 容器来定制它,或者可以参考这里,封装好大量的默认配置。
use yii\grid\GridView;
/**
* @var $this \yii\web\View
* @var $dataProvider \yii\data\ActiveDataProvider
*/
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
'id',
'user_name',
],
]);
2. 带搜索的用法
以下搜索无论是哪种用法,关键点都在于使用 filterWhere()
方法,当某字段在 GET 传过来的值为空时不对该字段进行任何查询,当然也可以用传统的先判断值,然后在判断里执行 where()
。
where()
的更多用法可到yii\db\QueryInterface
查看。
2.1 基本用法
控制器代码如下:
use app\models\User;
use yii\data\ActiveDataProvider;
$request = Yii::$app->request;
$id = $request->get('id');
$username = $request->get('username');
$mobile = $request->get('mobile');
$query = User::find();
$query->andFilterWhere([
'id' => $id,
'mobile' => $mobile,
]);
$query->andFilterWhere(['like', 'username', $username]);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
return $this->render('users', [
'dataProvider' => $dataProvider,
]);
2.2 SearchModel
有时候数据库表的字段太多,可以建立一个类来继承你的 Model 专门用来查询,其实你要是用过 gii 生成 crud 代码的话,你可以跳过这一节。
以用户表为例,建立一个用来搜索的 UserSearch 类,代码如下:
namespace app\models\search;
use app\models\User;
use yii\data\ActiveDataProvider;
class UserSearch extends User
{
/**
* 重写父类规则,同时也决定了 GridView 上该字段是否显示搜索框
*/
public function rules()
{
return [
['id', 'integer'],
['mobile', 'number'],
[['username'], 'safe'],
];
}
public function search($params)
{
$query = User::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
// 接收 get 参数,能否赋值到 model 取决于该字段是否出现在上面的 rules 方法里
$this->load($params);
// 可选,验证 rules,如果有不符合规则的,则不进行搜索
if (!$this->validate()) {
return $dataProvider;
}
// model 赋值后可以直接 $this 调用属性
$query->andFilterWhere([
'id' => $this->id,
'mobile' => $this->mobile,
]);
$query->andFilterWhere(['like', 'username', $this->username]);
return $dataProvider;
}
}
控制器
use app\models\search\UserSearch;
$searchModel = new UserSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('users', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
视图:
和最简用法的区别在于传给 GridView 的参数多了一个 filterModel
。
use yii\grid\GridView;
/**
* @var $this \yii\web\View
* @var $searchModel \app\models\search\UsersSearch
* @var $dataProvider \yii\data\ActiveDataProvider
*/
echo GridView::widget([
'filterModel' => $searchModel,
'dataProvider' => $dataProvider,
'columns' => [
'id',
'user_name',
'mobile',
],
]);
3. 自定义列的内容
首先,以下代码给出的两种输出 created_at
的作用是等效的,具有输出对应字段值、中文 label、搜索、排序的作用。
'columns' => [
'created_at',
[
'attribute' => 'created_at',
],
],
以下以格式化时间戳为例(实际有更好的格式化方法,这里是为了演示):
'columns' => [
[
'attribute' => 'created_at',
'value' => function ($model) {
/** @var $model \app\models\User */
return date('Y-m-d H:i:s', $model->created_at);
},
],
],
使用这种方法,还可以创建自定义列,只是无法排序和搜索,而且 label 需要手动设置:
'columns' => [
[
'label' => '平均值',
'value' => function ($model) {
return $model['all'] / $model['count'];
},
],
],