3 フォロワー

データウィジェット

Yii は、データを表示するために使用できるウィジェットのセットを提供しています。DetailViewウィジェットは単一レコードのデータを表示するために使用できる一方、ListViewGridViewは、ページネーション、ソート、フィルタリングなどの機能を提供するデータレコードのリストまたはテーブルを表示するために使用できます。

DetailView

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

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

データグリッドまたは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を拡張するため、グリッド列を構成する際に設定できるいくつかの共通オプションがあります。

  • headerを使用すると、ヘッダー行のコンテンツを設定できます。
  • footerを使用すると、フッター行のコンテンツを設定できます。
  • visibleは、列を表示するかどうかを定義します。
  • 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]
        ],
    ],
]);

上記では、textyii\i18n\Formatter::asText()に対応します。列の値は最初の引数として渡されます。2番目の列の定義では、dateyii\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
        ],

構成できる使用可能なプロパティは次のとおりです。

  • controllerは、アクションを処理する必要があるコントローラのIDです。設定されていない場合は、現在アクティブなコントローラが使用されます。
  • templateは、アクション列の各セルを構成するために使用されるテンプレートを定義します。中括弧で囲まれたトークンは、コントローラアクションID(アクション列のコンテキストではボタン名とも呼ばれます)として扱われます。これらは、buttonsで指定された対応するボタンレンダリングコールバックに置き換えられます。たとえば、トークン{view}はコールバックbuttons['view']の結果に置き換えられます。コールバックが見つからない場合、トークンは空の文字列に置き換えられます。デフォルトのトークンは{view} {update} {delete}です。
  • buttonsは、ボタンレンダリングコールバックの配列です。配列キーはボタン名(中括弧なし)であり、値は対応するボタンレンダリングコールバックです。コールバックは、次の署名を使用する必要があります。

    function ($url, $model, $key) {
        // return the button HTML code
    }
    

    上記のコードでは、$urlは列がボタン用に作成するURL、$modelは現在の行に対してレンダリングされるモデルオブジェクト、$keyはデータプロバイダ配列内のモデルのキーです。

  • urlCreatorは、指定されたモデル情報を使用してボタンURLを作成するコールバックです。コールバックの署名は、yii\grid\ActionColumn::createUrl()と同じである必要があります。このプロパティが設定されていない場合、ボタンURLはyii\grid\ActionColumn::createUrl()を使用して作成されます。
  • 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以外の属性createdFromcreatedToを追加できます。

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ビューを使用する

より高速で便利な別のアプローチ、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アクティブレコードを検索モデルで使用できます。すべての属性はすぐに使用できます。このアプローチにはいくつかの長所と短所があることに注意してください。

  • 異なるソート条件やフィルタリング条件を指定する必要はありません。すべてがすぐに動作します。
  • データサイズ、実行されるSQLクエリの数(各リレーションに対して追加のクエリは不要)のため、はるかに高速になる可能性があります。
  • これは単なるSQLビュー上のシンプルなマッピングUIであるため、エンティティにあるドメインロジックが欠けています。したがって、isActiveisDeletedなどのUIに影響を与えるメソッドがある場合は、このクラスにもそれらを複製する必要があります。

1つのページに複数のGridViewを表示する

1つのページで複数のGridViewを使用できますが、互いに干渉しないように追加の構成が必要です。GridViewの複数のインスタンスを使用する場合、生成されたソートリンクとページネーションリンクに異なるパラメータ名を構成して、各GridViewが個別のソートとページネーションを持つようにする必要があります。これを行うには、データプロバイダーのsortParampageParamsortおよび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を使用する

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"をリンクに追加します。

GiiでPjaxを使用するGridView/ListView

2.0.5以降、GiiのCRUDジェネレーターには、Webインターフェースまたはコマンドラインのいずれかを介して使用できる$enablePjaxというオプションがあります。

yii gii/crud --controllerClass="backend\\controllers\PostController" \
  --modelClass="common\\models\\Post" \
  --enablePjax=1

これにより、GridViewまたはListViewウィジェットをラップするPjaxウィジェットが生成されます。

さらに読む

タイプミスを見つけた場合や、このページを改善する必要があると思われる場合は?
githubで編集する !