Yii提供了一套數(shù)據(jù)小部件?widgets?,這些小部件可以用于顯示數(shù)據(jù)。?DetailView?小部件能夠用于顯示一條記錄數(shù)據(jù),?ListView?和GridView?小部件能夠用于顯示一個(gè)擁有分頁、排序和過濾功能的一個(gè)列表或者表格。
yii\widgets\DetailView 小部件顯示的是單一 yii\widgets\DetailView::$model 數(shù)據(jù)的詳情。
它非常適合用常規(guī)格式顯示一個(gè)模型(例如在一個(gè)表格的一行中顯示模型的每個(gè)屬性)。 這里說的模型可以是 \yii\base\Model 或者其子類的一個(gè)實(shí)例,例如子類?active record,也可以是一個(gè)關(guān)聯(lián)數(shù)組。
DetailView使用 yii\widgets\DetailView::$attributes 屬性來決定顯示模型哪些屬性以及如何格式化。 可用的格式化選項(xiàng),見?formatter section?章節(jié)。
一個(gè)典型的DetailView的使用方法如下:
echo DetailView::widget([
'model' => $model,
'attributes' => [
'title', // title attribute (in plain text)
'description:html', // description attribute formatted as HTML
[ // the owner name of the model
'label' => 'Owner',
'value' => $model->owner->name,
],
'created_at:datetime', // creation date formatted as datetime
],
]);
yii\widgets\ListView 小部件用于顯示數(shù)據(jù)提供者?data provider?提供的數(shù)據(jù)。 每個(gè)數(shù)據(jù)模型用指定的視圖文件 yii\widgets\ListView::$itemView 來渲染。 因?yàn)樗峁╅_箱即用式的(譯者注:封裝好的)分頁、排序以及過濾這樣一些特性,所以它可以很方便地為最終用戶顯示信息并同時(shí)創(chuàng)建數(shù)據(jù)管理界面。
一個(gè)典型的用法如下例所示:
use yii\widgets\ListView;
use yii\data\ActiveDataProvider;
$dataProvider = new ActiveDataProvider([
'query' => Post::find(),
'pagination' => [
'pageSize' => 20,
],
]);
echo ListView::widget([
'dataProvider' => $dataProvider,
'itemView' => '_post',
]);
_post
?視圖文件可包含如下代碼:
<?php
use yii\helpers\Html;
use yii\helpers\HtmlPurifier;
?>
<div class="post">
<h2><?= Html::encode($model->title) ?></h2>
<?= HtmlPurifier::process($model->text) ?>
</div>
在上面的視圖文件中,當(dāng)前的數(shù)據(jù)模型?$model
?是可用的。另外,下面的這些變量也是可用的:
$key
:混合類型,鍵的值與數(shù)據(jù)項(xiàng)相關(guān)聯(lián)。$index
:整型,是由數(shù)據(jù)提供者返回的數(shù)組中以0起始的數(shù)據(jù)項(xiàng)的索引。$widget
:類型是ListView,是小部件的實(shí)例。假如你需要傳遞附加數(shù)據(jù)到每一個(gè)視圖中,你可以像下面這樣用 yii\widgets\ListView::$viewParams 屬性傳遞鍵值對:
echo ListView::widget([
'dataProvider' => $dataProvider,
'itemView' => '_post',
'viewParams' => [
'fullView' => true,
'context' => 'main-page',
// ...
],
]);
在視圖中,上述這些附加數(shù)據(jù)也是可以作為變量來使用的。
數(shù)據(jù)網(wǎng)格或者說 GridView 小部件是Yii中最強(qiáng)大的部件之一。如果你需要快速建立系統(tǒng)的管理后臺, GridView 非常有用。它從數(shù)據(jù)提供者?data provider?中取得數(shù)據(jù)并使用 yii\grid\GridView::columns 屬性的一組列配置,在一個(gè)表格中渲染每一行數(shù)據(jù)。
表中的每一行代表一個(gè)數(shù)據(jù)項(xiàng)的數(shù)據(jù),并且一列通常表示該項(xiàng)的屬性(某些列可以對應(yīng)于屬性或靜態(tài)文本的復(fù)雜表達(dá)式)。
使用GridView的最少代碼如下:
use yii\grid\GridView;
use yii\data\ActiveDataProvider;
$dataProvider = new ActiveDataProvider([
'query' => Post::find(),
'pagination' => [
'pageSize' => 20,
],
]);
echo GridView::widget([
'dataProvider' => $dataProvider,
]);
上面的代碼首先創(chuàng)建了一個(gè)數(shù)據(jù)提供者,然后使用GridView顯示每一行的每個(gè)屬性,每一行的數(shù)據(jù)是從數(shù)據(jù)提供者取來的。 展現(xiàn)出來的表格封裝了排序以及分頁功能。
表格的列是通過 yii\grid\Column 類來配置的,這個(gè)類是通過 GridView 配置項(xiàng)中的 yii\grid\GridView::columns 屬性配置的。根據(jù)列的類別和設(shè)置的不同,各列能夠以不同方式展示數(shù)據(jù)。 默認(rèn)的列類是 yii\grid\DataColumn,用于展現(xiàn)模型的某個(gè)屬性, 并且可以排序和過濾。
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
// 數(shù)據(jù)提供者中所含數(shù)據(jù)所定義的簡單的列
// 使用的是模型的列的數(shù)據(jù)
'id',
'username',
// 更復(fù)雜的列數(shù)據(jù)
[
'class' => 'yii\grid\DataColumn', //由于是默認(rèn)類型,可以省略
'value' => function ($data) {
return $data->name; // 如果是數(shù)組數(shù)據(jù)則為 $data['name'] ,例如,使用 SqlDataProvider 的情形。
},
],
],
]);
請注意,假如配置中沒有指定 yii\grid\GridView::columns 屬性,那么Yii會試圖顯示數(shù)據(jù)提供者的模型中所有可能的列。
通過使用不同類,網(wǎng)格列可以自定義:
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
[
'class' => 'yii\grid\SerialColumn', // <-- 這里
// 你還可以在此配置其他屬性
],
除了我們下面將要展開討論的Yii自帶的列類,你還可以創(chuàng)建你自己的列類。
每個(gè)列類是從 yii\grid\Column 擴(kuò)展而來, 從而在配置網(wǎng)格列的時(shí)候,你可以設(shè)置一些公共的選項(xiàng)。
yii\grid\Column::content 允許你傳遞一個(gè)有效的PHP回調(diào)來為一行返回?cái)?shù)據(jù),格式如下:
function ($model, $key, $index, $column) {
return 'a string';
}
你可以傳遞數(shù)組來指定各種容器式的HTML選項(xiàng):
yii\grid\DataColumn 用于顯示和排序數(shù)據(jù)。這是默認(rèn)的列的類型, 所以在使用 DataColumn 為列類時(shí),可省略類的指定(譯者注:不需要'class'選項(xiàng)的意思)。
數(shù)據(jù)列的主要配置項(xiàng)是 yii\grid\DataColumn::format 屬性。它的值對應(yīng)于?formatter
?application component?應(yīng)用組件里面的一些方法, 默認(rèn)是使用 \yii\i18n\Formatter 應(yīng)用組件:
echo GridView::widget([
'columns' => [
[
'attribute' => 'name',
'format' => 'text'
],
[
'attribute' => 'birthday',
'format' => ['date', 'php:Y-m-d']
],
],
]);
在上面的代碼中,text
?對應(yīng)于 \yii\i18n\Formatter::asText()。列的值作為第一個(gè)參數(shù)傳遞。在第二列的定義中,date
?對應(yīng)于 \yii\i18n\Formatter::asDate()。 同樣地,列值也是通過第一個(gè)參數(shù)傳遞的,而 'php:Y-m-d' 用作第二個(gè)參數(shù)的值。
可用的格式化方法列表,請參照?section about Data Formatting。
數(shù)據(jù)列配置,還有一個(gè)”快捷格式化串”的方法,詳情見API文檔 yii\grid\GridView::columns。 (譯者注:舉例說明,"name:text:Name"
?快捷格式化串,表示列名為?name
?格式為?text
?顯示標(biāo)簽是?Name
)
yii\grid\ActionColumn 用于顯示一些動作按鈕,如每一行的更新、刪除操作。
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
[
'class' => 'yii\grid\ActionColumn',
// you may configure additional properties here
],
可配置的屬性如下:
{view}
?將被?buttons['view']
?關(guān)聯(lián)的渲染回調(diào)函數(shù)的返回結(jié)果所替換。 如果沒有找到回調(diào)函數(shù),令牌將被替換成一個(gè)空串。默認(rèn)的令牌有?{view} {update} {delete}
?。yii\grid\ActionColumn::buttons 是一個(gè)按鈕的渲染回調(diào)數(shù)數(shù)組。數(shù)組中的鍵是按鈕的名字(沒有花括號),并且值是對應(yīng)的按鈕渲染回調(diào)函數(shù)。 這些回調(diào)函數(shù)須使用下面這種原型:
function ($url, $model, $key) {
// return the button HTML code
}
在上面的代碼中,$url
?是列為按鈕創(chuàng)建的URL,$model
是當(dāng)前要渲染的模型對象,并且?$key
?是在數(shù)據(jù)提供者數(shù)組中模型的鍵。
yii\grid\CheckboxColumn 顯示一個(gè)復(fù)選框列。
想要添加一個(gè)復(fù)選框到網(wǎng)格視圖中,將它添加到 yii\grid\GridView::$columns 的配置中,如下所示:
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
// ...
[
'class' => 'yii\grid\CheckboxColumn',
// 你可以在這配置更多的屬性
],
],
用戶可點(diǎn)擊復(fù)選框來選擇網(wǎng)格中的一些行。被選擇的行可通過調(diào)用下面的JavaScript代碼來獲得:
var keys = $('#grid').yiiGridView('getSelectedRows');
// keys 為一個(gè)由與被選行相關(guān)聯(lián)的鍵組成的數(shù)組
yii\grid\SerialColumn 渲染行號,以?1
?起始并自動增長。
使用方法和下面的例子一樣簡單:
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'], // <-- here
// ...
注意:這部分正在開發(fā)中。
為了過濾數(shù)據(jù)的 GridView 需要一個(gè)模型?model?來 從過濾表單接收數(shù)據(jù),以及調(diào)整數(shù)據(jù)提供者的查詢對象,以滿足搜索條件。 使用活動記錄?active records?時(shí),通常的做法是 創(chuàng)建一個(gè)能夠提供所需功能的搜索模型類(可以使用?Gii?來生成)。 這個(gè)類為搜索定義了驗(yàn)證規(guī)則并且提供了一個(gè)將會返回?cái)?shù)據(jù)提供者對象的?search()
?方法。
為了給?Post
?模型增加搜索能力,我們可以像下面的例子一樣創(chuàng)建?PostSearch
?模型:
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
class PostSearch extends Post
{
public function rules()
{
// 只有在 rules() 函數(shù)中聲明的字段才可以搜索
return [
[['id'], 'integer'],
[['title', 'creation_date'], 'safe'],
];
}
public function scenarios()
{
// 旁路在父類中實(shí)現(xiàn)的 scenarios() 函數(shù)
return Model::scenarios();
}
public function search($params)
{
$query = Post::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
// 從參數(shù)的數(shù)據(jù)中加載過濾條件,并驗(yàn)證
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
// 增加過濾條件來調(diào)整查詢對象
$query->andFilterWhere(['id' => $this->id]);
$query->andFilterWhere(['like', 'title', $this->title])
->andFilterWhere(['like', 'creation_date', $this->creation_date]);
return $dataProvider;
}
}
你可以在控制器中使用如下方法為網(wǎng)格視圖獲取數(shù)據(jù)提供者:
$searchModel = new PostSearch();
$dataProvider = $searchModel->search(Yii::$app->request->get());
return $this->render('myview', [
'dataProvider' => $dataProvider,
'searchModel' => $searchModel,
]);
然后你在視圖中將?$dataProvider
?和?$searchModel
?對象分派給 GridView 小部件:
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
// ...
],
]);
當(dāng)我們在一個(gè)網(wǎng)格視圖中顯示活動數(shù)據(jù)的時(shí)候,你可能會遇到這種情況,就是顯示關(guān)聯(lián)表的列的值,例如:發(fā)帖者的名字,而不是顯示他的?id
。 當(dāng)?Post
?模型有一個(gè)關(guān)聯(lián)的屬性名(譯者注:?Post
?模型中用?hasOne
?定義?getAuthor()
?函數(shù)) 叫?author
?并且作者模型(譯者注:本例的作者模型是?users
?)有一個(gè)屬性叫?name
,那么你可以通過在 yii\grid\GridView::$columns 中定義屬性名為author.name
?來處理。這時(shí)的網(wǎng)格視圖能顯示作者名了,但是默認(rèn)是不支持按作者名排序和過濾的。 你需要調(diào)整上個(gè)章節(jié)介紹的PostSearch
?模型,以添加此功能。
為了使關(guān)聯(lián)列能夠排序,你需要連接關(guān)系表,以及添加排序規(guī)則到數(shù)據(jù)提供者的排序組件中:
$query = Post::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
// 連接與 `users` 表相關(guān)聯(lián)的 `author` 表
// 并將 `users` 表的別名設(shè)為 `author`
$query->joinWith(['author' => function($query) { $query->from(['author' => 'users']); }]);
// 使得關(guān)聯(lián)字段可以排序
$dataProvider->sort->attributes['author.name'] = [
'asc' => ['author.name' => SORT_ASC],
'desc' => ['author.name' => SORT_DESC],
];
// ...
過濾也需要像上面一樣調(diào)用joinWith方法。你也需要在屬性和規(guī)則中定義該列,就像下面這樣:
public function attributes()
{
// 添加關(guān)聯(lián)字段到可搜索屬性集合
return array_merge(parent::attributes(), ['author.name']);
}
public function rules()
{
return [
[['id'], 'integer'],
[['title', 'creation_date', 'author.name'], 'safe'],
];
}
然后在?search()
?方法中,你僅需要添加一個(gè)額外過濾條件:
$query->andFilterWhere(['LIKE', 'author.name', $this->getAttribute('author.name')]);
信息:在上面的代碼中,我們使用相同的字符串作為關(guān)聯(lián)名稱和表別名; 然而,當(dāng)你的表別名和關(guān)聯(lián)名稱不相同的時(shí)候,你得注意在哪使用你的別名,在哪使用你的關(guān)聯(lián)名稱。 一個(gè)簡單的規(guī)則是在每個(gè)構(gòu)建數(shù)據(jù)庫查詢的地方使用別名,而在所有其他和定義相關(guān)的諸如:
attributes()
?和?rules()
?等地方使用關(guān)聯(lián)名稱。例如,你使用?
au
?作為作者關(guān)系表的別名,那么聯(lián)查語句就要寫成像下面這樣:$query->joinWith(['author' => function($query) { $query->from(['au' => 'users']); }]);
當(dāng)別名已經(jīng)在關(guān)聯(lián)函數(shù)中定義了時(shí),也可以只調(diào)用?
$query->joinWith(['author']);
。在過濾條件中,別名必須使用,但屬性名稱保持不變:
$query->andFilterWhere(['LIKE', 'au.name', $this->getAttribute('author.name')]);
排序定義也同樣如此:
$dataProvider->sort->attributes['author.name'] = [ 'asc' => ['au.name' => SORT_ASC], 'desc' => ['au.name' => SORT_DESC], ];
同樣,當(dāng)指定使用 yii\data\Sort::defaultOrder 來排序的時(shí)候,你需要使用關(guān)聯(lián)名稱替代別名:
$dataProvider->sort->defaultOrder = ['author.name' => SORT_ASC];
信息:更多關(guān)于?
joinWith
?和在后臺執(zhí)行查詢的相關(guān)信息, 可以查看?active record docs on joining with relations。
還有另外一種方法可以更快、更有用 - SQL 視圖。例如,我們要在?GridView
?中顯示用戶和他們的簡介,可以這樣創(chuàng)建 SQL 視圖:
CREATE OR REPLACE VIEW vw_user_info AS
SELECT user.*, user_profile.lastname, user_profile.firstname
FROM user, user_profile
WHERE user.id = user_profile.user_id
然后你需要?jiǎng)?chuàng)建活動記錄模型來代表這個(gè)視圖:
namespace app\models\views\grid;
use yii\db\ActiveRecord;
class UserView extends ActiveRecord
{
/**
* @inheritdoc
*/
public static function tableName()
{
return 'vw_user_info';
}
public static function primaryKey()
{
return ['id'];
}
/**
* @inheritdoc
*/
public function rules()
{
return [
// 在這定義你的規(guī)則
];
}
/**
* @inheritdoc
*/
public static function attributeLabels()
{
return [
// 在這定義你的屬性標(biāo)簽
];
}
}
之后你可以使用這個(gè) UserView 活動記錄和搜索模型,無需附加的排序和過濾屬性的規(guī)則。 所有屬性都可開箱即用。請注意,這種方法有利有弊:
isActive
、isDeleted
?或者其他影響到UI的方法, 你也需要在這個(gè)類中復(fù)制他們。你可以在一個(gè)單獨(dú)頁面中使用多個(gè)網(wǎng)格視圖,但是一些額外的配置是必須的,為的就是它們相互之間不干擾。 當(dāng)使用多個(gè)網(wǎng)格視圖實(shí)例的時(shí)候,你必須要為生成的排序和分頁對象配置不同的參數(shù)名,以便于每個(gè)網(wǎng)格視圖有它們各自獨(dú)立的排序和分頁。 你可以通過設(shè)置 yii\data\Sort::sortParam 和 yii\data\Pagination::pageParam,對應(yīng)于數(shù)據(jù)提供者的 yii\data\BaseDataProvider::$sort 和 yii\data\BaseDataProvider::$pagination 實(shí)例。
假如我們想要同時(shí)顯示?Post
?和?User
?模型,這兩個(gè)模型已經(jīng)在?$userProvider
?和?$postProvider
?這兩個(gè)數(shù)據(jù)提供者中準(zhǔn)備好, 具體做法如下:
use yii\grid\GridView;
$userProvider->pagination->pageParam = 'user-page';
$userProvider->sort->sortParam = 'user-sort';
$postProvider->pagination->pageParam = 'post-page';
$postProvider->sort->sortParam = 'post-sort';
echo '<h1>Users</h1>';
echo GridView::widget([
'dataProvider' => $userProvider,
]);
echo '<h1>Posts</h1>';
echo GridView::widget([
'dataProvider' => $postProvider,
]);
注意: 這部分正在開發(fā)中。
待定
更多建議: