Yii は、データを表示するために使用できるウィジェットのセットを提供しています。DetailViewウィジェットは単一レコードのデータを表示するために使用できる一方、ListViewとGridViewは、ページネーション、ソート、フィルタリングなどの機能を提供するデータレコードのリストまたはテーブルを表示するために使用できます。
DetailViewウィジェットは、単一のデータモデルの詳細を表示します。
これは、モデルを通常の形式(例えば、各モデル属性がテーブルの行として表示される)で表示するのに最適です。モデルは、yii\base\Modelのインスタンスまたはサブクラス(アクティブレコードや連想配列など)のいずれかです。
DetailViewは、どのモデル属性を表示する必要があるか、また、どのように書式設定する必要があるかを決定するために$attributesプロパティを使用します。利用可能な書式設定オプションについては、フォーマッタセクションを参照してください。
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,
'contentOptions' => ['class' => 'bg-red'], // HTML attributes to customize value tag
'captionOptions' => ['tooltip' => 'Tooltip'], // HTML attributes to customize label tag
],
'created_at:datetime', // creation date formatted as datetime
],
]);
yii\widgets\GridView がモデルのセットを処理するのとは異なり、DetailView は 1 つだけ処理することに注意してください。したがって、ほとんどの場合、$model は表示する唯一のモデルであり、ビュー内で変数として利用できるため、クロージャを使用する必要はありません。
ただし、いくつかのケースではクロージャを使用すると便利になることがあります。たとえば、`visible` が指定されていて、それが `false` と評価された場合に `value` の計算を防ぎたい場合などです。
echo DetailView::widget([
'model' => $model,
'attributes' => [
[
'attribute' => 'owner',
'value' => function ($model) {
return $model->owner->name;
},
'visible' => \Yii::$app->user->can('posts.owner.view'),
],
],
]);
ListViewウィジェットは、データプロバイダからのデータを表示するために使用されます。各データモデルは、指定されたビューファイルを使用してレンダリングされます。ページネーション、ソート、フィルタリングなどの機能をすぐに利用できるため、エンドユーザーに情報を表示する場合と、データ管理UIを作成する場合の両方に便利です。
一般的な使用法は次のとおりです。
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>
上記のビューファイルでは、現在のデータモデルは$model
として利用できます。さらに、以下の変数が利用可能です。
$key
: mixed, データアイテムに関連付けられたキー値。$index
: integer, データプロバイダによって返されるitems配列内のデータアイテムのゼロベースのインデックス。$widget
: ListView, このウィジェットのインスタンス。各ビューに追加のデータを渡す必要がある場合は、$viewParamsプロパティを使用して、次のようにキーと値のペアを渡すことができます。
echo ListView::widget([
'dataProvider' => $dataProvider,
'itemView' => '_post',
'viewParams' => [
'fullView' => true,
'context' => 'main-page',
// ...
],
]);
これらは、ビュー内で変数としても利用できます。
データグリッドまたはGridViewは、Yiiで最も強力なウィジェットの1つです。システムの管理セクションを迅速に構築する必要がある場合に非常に役立ちます。データプロバイダからデータを取得し、一連の列を使用して各行をレンダリングし、表形式でデータを表示します。
テーブルの各行は単一のデータアイテムのデータを表し、列は通常、アイテムの属性を表します(一部の列は属性または静的テキストの複雑な式に対応する場合があります)。
GridViewを使用するために必要な最小限のコードは次のとおりです。
use yii\grid\GridView;
use yii\data\ActiveDataProvider;
$dataProvider = new ActiveDataProvider([
'query' => Post::find(),
'pagination' => [
'pageSize' => 20,
],
]);
echo GridView::widget([
'dataProvider' => $dataProvider,
]);
上記のコードでは、まずデータプロバイダを作成し、次にGridViewを使用して、データプロバイダから取得したすべての行のすべての属性を表示します。表示されたテーブルには、すぐに使用できるソートとページネーションの機能が備わっています。
グリッドテーブルの列は、yii\grid\Columnクラスによって構成されます。これらのクラスは、GridView構成のcolumnsプロパティで構成されます。列の種類と設定に応じて、データを異なる方法で表示できます。デフォルトのクラスはyii\grid\DataColumnであり、モデル属性を表し、ソートとフィルタリングが可能です。
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
// Simple columns defined by the data contained in $dataProvider.
// Data from the model's column will be used.
'id',
'username',
// More complex one.
[
'class' => 'yii\grid\DataColumn', // can be omitted, as it is the default
'value' => function ($data) {
return $data->name; // $data['name'] for array data, e.g. using SqlDataProvider.
},
],
],
]);
構成のcolumns部分が指定されていない場合、Yiiはデータプロバイダのモデルの可能なすべての列を表示しようとすることに注意してください。
グリッド列は、さまざまな列クラスを使用することでカスタマイズできます。
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
[
'class' => 'yii\grid\SerialColumn', // <-- here
// you may configure additional properties here
],
以下で説明するYiiが提供する列クラスに加えて、独自の列クラスを作成できます。
各列クラスはyii\grid\Columnを拡張するため、グリッド列を構成する際に設定できるいくつかの共通オプションがあります。
contentを使用すると、行のデータを返す有効なPHPコールバックを渡すことができます。形式は次のとおりです。
function ($model, $key, $index, $column) {
return 'a string';
}
配列を渡すことで、さまざまなコンテナHTMLオプションを指定できます。
データ列は、データの表示とソートに使用されます。これはデフォルトの列タイプであるため、使用時にクラスの指定を省略できます。
データ列の主な設定は、formatプロパティです。その値は、formatter
アプリケーションコンポーネント(デフォルトではFormatter)のメソッドに対応します。
echo GridView::widget([
'columns' => [
[
'attribute' => 'name',
'format' => 'text'
],
[
'attribute' => 'birthday',
'format' => ['date', 'php:Y-m-d']
],
'created_at:datetime', // shortcut format
[
'label' => 'Education',
'attribute' => 'education',
'filter' => ['0' => 'Elementary', '1' => 'Secondary', '2' => 'Higher'],
'filterInputOptions' => ['prompt' => 'All educations', 'class' => 'form-control', 'id' => null]
],
],
]);
上記では、text
はyii\i18n\Formatter::asText()に対応します。列の値は最初の引数として渡されます。2番目の列の定義では、date
はyii\i18n\Formatter::asDate()に対応します。列の値は、ここでも最初の引数として渡され、「php:Y-m-d」が2番目の引数値として使用されます。
利用可能なフォーマッタのリストについては、データフォーマットに関するセクションを参照してください。
データ列を構成するには、columnsのAPIドキュメントに記載されているショートカット形式もあります。
filterおよびfilterInputOptionsを使用して、フィルター入力のHTMLを制御します。
デフォルトでは、列ヘッダーはyii\data\Sort::link()によってレンダリングされます。yii\grid\Column::$headerを使用して調整できます。ヘッダーテキストを変更するには、上記の例のようにyii\grid\DataColumn::$labelを設定する必要があります。デフォルトでは、ラベルはデータモデルから設定されます。詳細については、yii\grid\DataColumn::getHeaderCellLabel()を参照してください。
アクション列には、各行の更新や削除などのアクションボタンが表示されます。
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
[
'class' => 'yii\grid\ActionColumn',
// you may configure additional properties here
],
構成できる使用可能なプロパティは次のとおりです。
{view}
はコールバックbuttons['view']
の結果に置き換えられます。コールバックが見つからない場合、トークンは空の文字列に置き換えられます。デフォルトのトークンは{view} {update} {delete}
です。buttonsは、ボタンレンダリングコールバックの配列です。配列キーはボタン名(中括弧なし)であり、値は対応するボタンレンダリングコールバックです。コールバックは、次の署名を使用する必要があります。
function ($url, $model, $key) {
// return the button HTML code
}
上記のコードでは、$url
は列がボタン用に作成するURL、$model
は現在の行に対してレンダリングされるモデルオブジェクト、$key
はデータプロバイダ配列内のモデルのキーです。
visibleButtonsは、各ボタンの表示条件の配列です。配列キーはボタン名(中括弧なし)であり、値はブール値のtrue
/false
または匿名関数です。この配列でボタン名が指定されていない場合は、デフォルトで表示されます。コールバックは、次の署名を使用する必要があります。
function ($model, $key, $index) {
return $model->status === 'editable';
}
または、ブール値を渡すこともできます。
[
'update' => \Yii::$app->user->can('update')
]
チェックボックス列には、チェックボックスの列が表示されます。
GridViewにCheckboxColumnを追加するには、次のようにcolumns構成に追加します。
echo GridView::widget([
'id' => 'grid',
'dataProvider' => $dataProvider,
'columns' => [
// ...
[
'class' => 'yii\grid\CheckboxColumn',
// you may configure additional properties here
],
],
ユーザーはチェックボックスをクリックしてグリッドの行を選択できます。選択した行は、次のJavaScriptコードを呼び出すことで取得できます。
var keys = $('#grid').yiiGridView('getSelectedRows');
// keys is an array consisting of the keys associated with the selected rows
連番列は、1
から始まり、前方に向かう行番号をレンダリングします。
使い方は次のとおり簡単です。
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'], // <-- here
// ...
注:このセクションは開発中です。
データをフィルタリングするには、GridViewには、通常はGridViewテーブルのフィルターフィールドから取得される検索条件を表すモデルが必要です。アクティブレコードを使用する場合の一般的な方法は、必要な機能を提供する検索モデルクラスを作成することです(これはGiiによって生成できます)。このクラスは、GridViewテーブルにフィルターコントロールを表示するための検証ルールと、検索条件を処理する調整されたクエリを持つデータプロバイダを返すsearch()
メソッドを定義します。
Post
モデルの検索機能を追加するために、次の例のようにPostSearch
モデルを作成できます。
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
class PostSearch extends Post
{
public function rules()
{
// only fields in rules() are searchable
return [
[['id'], 'integer'],
[['title', 'creation_date'], 'safe'],
];
}
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
public function search($params)
{
$query = Post::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
// load the search form data and validate
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
// adjust the query by adding the filters
$query->andFilterWhere(['id' => $this->id]);
$query->andFilterWhere(['like', 'title', $this->title])
->andFilterWhere(['like', 'creation_date', $this->creation_date]);
return $dataProvider;
}
}
この関数をコントローラで使用して、GridViewのdataProviderを取得できます。
$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' => [
// ...
],
]);
ほとんどの場合、GridViewヘッダーフィルターを使用するだけで十分ですが、別のフィルターフォームが必要な場合は、簡単に追加できます。次の内容を含む部分ビュー_search.php
を作成できます。
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
/* @var $this yii\web\View */
/* @var $model app\models\PostSearch */
/* @var $form yii\widgets\ActiveForm */
?>
<div class="post-search">
<?php $form = ActiveForm::begin([
'action' => ['index'],
'method' => 'get',
]); ?>
<?= $form->field($model, 'title') ?>
<?= $form->field($model, 'creation_date') ?>
<div class="form-group">
<?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
<?= Html::submitButton('Reset', ['class' => 'btn btn-default']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
これを次のようにindex.php
ビューに含めます。
<?= $this->render('_search', ['model' => $searchModel]) ?>
注:Giiを使用してCRUDコードを生成する場合、別のフィルターフォーム(
_search.php
)はデフォルトで生成されますが、index.php
ビューではコメントアウトされています。コメントを外すと、すぐに使用できます!
別のフィルターフォームは、GridViewに表示されていないフィールドでフィルター処理する必要がある場合、または日付範囲などの特別なフィルター条件の場合に役立ちます。日付範囲でフィルター処理するために、検索モデルにDB以外の属性createdFrom
とcreatedTo
を追加できます。
class PostSearch extends Post
{
/**
* @var string
*/
public $createdFrom;
/**
* @var string
*/
public $createdTo;
}
次のようにsearch()
メソッドでクエリ条件を拡張します。
$query->andFilterWhere(['>=', 'creation_date', $this->createdFrom])
->andFilterWhere(['<=', 'creation_date', $this->createdTo]);
そして、フィルターフォームに代表的なフィールドを追加します。
<?= $form->field($model, 'creationFrom') ?>
<?= $form->field($model, 'creationTo') ?>
GridViewでアクティブレコードを表示する場合、投稿者のid
だけでなく、投稿者の名前など、関連する列の値を表示する場合があるかもしれません。これは、Post
モデルにauthor
という名前のリレーションがあり、投稿者モデルに属性name
がある場合、yii\grid\GridView::$columnsで属性名をauthor.name
として定義することで行います。これにより、GridViewは投稿者の名前を表示しますが、ソートとフィルタリングはデフォルトでは有効になりません。この機能を追加するには、前のセクションで紹介したPostSearch
モデルを調整する必要があります。
関連する列でソートを有効にするには、関連するテーブルを結合し、データプロバイダのソートコンポーネントにソートルールを追加する必要があります。
$query = Post::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
// join with relation `author` that is a relation to the table `users`
// and set the table alias to be `author`
$query->joinWith(['author' => function($query) { $query->from(['author' => 'users']); }]);
// since version 2.0.7, the above line can be simplified to $query->joinWith('author AS author');
// enable sorting for the related column
$dataProvider->sort->attributes['author.name'] = [
'asc' => ['author.name' => SORT_ASC],
'desc' => ['author.name' => SORT_DESC],
];
// ...
フィルタリングにも上記のようなjoinWith呼び出しが必要です。また、属性とルールに検索可能な列を次のように定義する必要があります。
public function attributes()
{
// add related fields to searchable attributes
return array_merge(parent::attributes(), ['author.name']);
}
public function rules()
{
return [
[['id'], 'integer'],
[['title', 'creation_date', 'author.name'], 'safe'],
];
}
search()
では、別のフィルター条件を次のように追加します。
$query->andFilterWhere(['LIKE', 'author.name', $this->getAttribute('author.name')]);
情報:上記では、リレーション名とテーブルエイリアスに同じ文字列を使用していますが、エイリアスとリレーション名が異なる場合は、エイリアスを使用する場所とリレーション名を使用する場所に注意する必要があります。これに対する簡単なルールは、データベースクエリの構築に使用されるすべての場所でエイリアスを使用し、
attributes()
やrules()
などの他のすべての定義でリレーション名を使用することです。たとえば、投稿者リレーションテーブルにエイリアス
au
を使用する場合、joinWithステートメントは次のようになります。
$query->joinWith(['author au']);
エイリアスがリレーション定義で定義されている場合、
$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], ];
また、ソートのdefaultOrderを指定する場合、エイリアスの代わりにリレーション名を使用する必要があります。
$dataProvider->sort->defaultOrder = ['author.name' => SORT_ASC];
情報:
joinWith
およびバックグラウンドで実行されるクエリの詳細については、リレーションとの結合に関するアクティブレコードのドキュメントを確認してください。
より高速で便利な別のアプローチ、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
次に、このビューを表すActiveRecordを作成する必要があります。
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 [
// define here your rules
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
// define here your attribute labels
];
}
}
その後、ソート属性とフィルタリング属性を特別に指定しなくても、このUserViewアクティブレコードを検索モデルで使用できます。すべての属性はすぐに使用できます。このアプローチにはいくつかの長所と短所があることに注意してください。
isActive
、isDeleted
などのUIに影響を与えるメソッドがある場合は、このクラスにもそれらを複製する必要があります。1つのページで複数のGridViewを使用できますが、互いに干渉しないように追加の構成が必要です。GridViewの複数のインスタンスを使用する場合、生成されたソートリンクとページネーションリンクに異なるパラメータ名を構成して、各GridViewが個別のソートとページネーションを持つようにする必要があります。これを行うには、データプロバイダーのsortParamとpageParamをsortおよびpaginationインスタンスに設定します。
Post
モデルとUser
モデルをリスト表示したいと仮定し、$userProvider
と$postProvider
に2つのデータプロバイダーを既に準備してあります。
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,
]);
Pjaxウィジェットを使用すると、ページ全体をリロードする代わりに、ページの特定の部分を更新できます。フィルターを使用するときにGridViewコンテンツのみを更新するために使用できます。
use yii\widgets\Pjax;
use yii\grid\GridView;
Pjax::begin([
// PJax options
]);
Gridview::widget([
// GridView options
]);
Pjax::end();
Pjaxは、Pjaxウィジェット内のリンク、およびPjax::$linkSelectorで指定されたリンクにも機能します。ただし、これはActionColumnのリンクにとっては問題になる可能性があります。これを防ぐには、ActionColumn::$buttonsプロパティを編集するときに、HTML属性data-pjax="0"
をリンクに追加します。
2.0.5以降、GiiのCRUDジェネレーターには、Webインターフェースまたはコマンドラインのいずれかを介して使用できる$enablePjax
というオプションがあります。
yii gii/crud --controllerClass="backend\\controllers\PostController" \
--modelClass="common\\models\\Post" \
--enablePjax=1
これにより、GridViewまたはListViewウィジェットをラップするPjaxウィジェットが生成されます。
タイプミスを見つけた場合や、このページを改善する必要があると思われる場合は?
githubで編集する !
「個別のフィルターフォーム」セクションの最後のコードにエラーがあります。
<?= $form->field($model, 'creationFrom') ?> <?= $form->field($model, 'creationTo') ?>
下記である必要があります
<?= $form->field($model, 'createdFrom') ?> <?= $form->field($model, 'createdTo') ?>
私にとって、ListViewとGridViewで最も便利なのは、リンクまたはボタンのようなものを介して「詳細」画面を開くことです。これは、「アクション」列以外ではあまり扱われていません。ほとんどの場合、新しい列ではなく、クリックするためのテキストリンクだけが必要です。上記のいずれかでそれが可能だと思いますが、何であるか、どうすればよいかはあまり明確ではありません。
コメントするには、サインアップまたはログインしてください。