47歳でやむなくセミリタイア

病気のためセミリタイアをすることに。現在は週20時間程度のバイトをしています。その他、雑多なことを記録として書いています。

Yii2の使い方: リレーションを持つモデルをGridViewで表示する

Yii2の使い方。自分用のメモです。

リレーションを持つモデル、たとえば社員と支店のテーブルがあって、社員のテーブルにその社員がどの支店に属しているかが支店番号で入れられているようなものをGridViewで表示する方法です。

データーベース

こんな感じのデータベースです。

CREATE TABLE `t_employee` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `branch_id` INT(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `t_branch` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO t_branch(id, name) VALUES(1,'東京'),(2,'大阪');
INSERT INTO t_employee(name,branch_id) VALUES('山田',1),('鈴木',1),('佐藤',2),('田中',2),('吉田',1);

以下のような表になります。

名前 支店名
山田 東京
鈴木 東京
佐藤 大阪
田中 大阪
吉田 東京

giiでCRUDを作る

Yii2の使い方: Giiを使ってCRUDコードを作成する (+ Pretty URL) - 47歳でやむなくセミリタイア」で書いた、Giiを使ってデータベースからModel(Employee.phpとBranch.php)とCRUD(EmployeeController.php/EmployeeForm.phpとview/employee)を作ります。
この状態でGridViewを表示すると以下のようなものになります。
f:id:ekutajp:20191103174351p:plain
リレーションを設定していないので、支店番号がそのまま表示されています。これを支店名が表示されるようにします。

viewで支店名を表示するよう設定

最初にGridViewで支店名が評されるようにします。
models/Employee.phpにリレーションを定義します。

    public function getBranch()
    {
        return $this->hasOne(Branch::className(), ['id' => 'branch_id']);
    }

views/employee/index.phpのcolumn指定のbranch_id を以下のように書き換える。

        'columns' => [
            ['class' => 'yii\grid\SerialColumn'],
            'id',
            'name',
            [
                'attribute' => 'branch_name',
                'value' => 'branch.name',
            ],
        ],

ここまででも、GridViewに支店名が表示されるのですが、これでは一行ごとにデーターベースのクエリが発生してしまうので、一度のクエリで済ませられるように、models/EmployeeForm.phpにjoinWith()を追加します。これは検索やソートにも必要です。

    public function search($params)
    {
        $query = Employee::find()->joinWith('branch');

検索ができるようにする

上記だけだと、支店名は表示されますが、検索やソートができません。まず検索ができるようにします。
models/EmployeeForm.phpのrules()からbranch_idを削除して、branch_nameを追加します。

    public function rules()
    {
        return [
            [['id'], 'integer'],
            [['name', 'branch_name'], 'safe'],
        ];
    }

同じくmodels/EmployeeForm.phpのsearch()の検索条件からbranch_idを削除して、branch_nameを追加します。これで検索ができるようになりました。

ソートができるようにする

最後にソートの設定をします。
models/EmployeeForm.phpのsearch()で、$dataProviderに、ソート設定を追加してやります。

        $dataProvider = new ActiveDataProvider([
            'query' => $query,
        ]);
        $dataProvider->sort->attributes['branch_name'] = [
                'asc' => ['t_branch.name' => SORT_ASC],
                'desc' => ['t_branch.name' => SORT_DESC],
        ];

結果

以下のように、「Branch ID」の列が、「Branch Name」となって、支店名が表示されるようになっています。ソートや検索も使えるようになりました。
f:id:ekutajp:20191103181009p:plain