Laravel-adminで1対多を色々な形で表示してみる

# 概要
Laravel-adminの1対多で結びついているデータを色々な形で表示してみました．

# 環境
Laravel 5.3 , Laravel-admin 1.6.9

# モデル

```php:Author.php
class Author extends Model
{
    public function books() {
        return $this->hasMany(Book::class,'author_id')->orderBy('id','asc');
    }
}
```

```php:Book.php
class Book extends Model
{
    protected $fillable=['title','author_id','page','subtitle','price'];

    public function author() {
        return $this->belongTo(Author::class,'author_id');
    }
}

```

# 通常の使用
公式ドキュメントなどにあるように実装するとこのような画面が出来上がります．
子のテーブルのカラムが少ない場合はこれで十分使えると思います．


![ノーマルモード.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431996/199fc5e2-908a-4888-b333-cb2fdf873695.png)

```php:AuthorController.php
protected function form()
{
    $form = new Form(new Author);

    $form->tab('氏名',function($form) {
        $form->hidden('id');
        $form->text('first_name', '名');
        $form->text('last_name', '氏');
    })->tab('本',function($form) {
        $form->hasMany('books','BOOK',function(Form\NestedForm $nestedForm) {
            $nestedForm->hidden('id');
            $nestedForm->text('title','タイトル');
            $nestedForm->text('subtitle','サブタイトル');
            $nestedForm->number('page','ページ数');
            $nestedForm->currency('price','価格');
        });
    });

    return $form;
}
```

# タブモード
ノーマルモードのフォーム1つ1つをタブに入れて表示しています．子のカラムが増えても1ページに1つのレコードが表示されるため，ノーマルモードに比べて下に伸びにくくなっています．
一方で，親が子を多く持つとタブの数が増加するため，このようなときには使いづらくなります．また，目的のレコードが探しづらいという短点もあります．

![タブモード.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431996/14e0bd47-412f-d3b7-b3a1-37251fe3ddf3.png)

```php:AuthorController.php
protected function form()
{
    $form = new Form(new Author);

    $form->tab('氏名',function($form) {
        $form->hidden('id');
        $form->text('first_name', '名');
        $form->text('last_name', '氏');
    })->tab('本',function($form) {
        $form->hasMany('books','BOOK',function(Form\NestedForm $nestedForm) {
            $nestedForm->hidden('id');
            $nestedForm->text('title','タイトル');
            $nestedForm->text('subtitle','サブタイトル');
            $nestedForm->number('page','ページ数');
            $nestedForm->currency('price','価格');
        })->useTab();
    });

    return $form;
}
```

# デーブルモード
laravel-admin 1.6.10にて追加された機能．上記の2つに比べてスッキリとしたデザインで使いやすいと思います．
しかし，子のカラムが増えると横幅が足りなくなり，入力フォームが非常に小さくなることがあります．

![テーブルモード.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431996/28b385ce-9d1c-9c7d-1949-605d607cd0ba.png)

```php:AuthorController.php
protected function form()
{
    $form = new Form(new Author);

    $form->tab('氏名',function($form) {
        $form->hidden('id');
        $form->text('first_name', '名');
        $form->text('last_name', '氏');
    })->tab('本',function($form) {
        $form->hasMany('books','BOOK',function(Form\NestedForm $nestedForm) {
            $nestedForm->hidden('id');
            $nestedForm->text('title','タイトル');
            $nestedForm->text('subtitle','サブタイトル');
            $nestedForm->number('page','ページ数');
            $nestedForm->currency('price','価格');
        })->useTable();
    });

    return $form;
}
```

# index画面の埋めこみ
index画面にあるgridをそのままフォームに埋め込んだものとなっています．
index画面を埋め込んでいるため動作はindex画面に準じたもので，他のフォームとは独立した編集画面として動作します．
例えばindex画面と同様に編集を行うと，送信ボタンを押さずともデータベースが更新され，新規ボタンを押すとBookControllerのcreateメソッドに飛びます．
あくまで表示だけにとどめて，新規・編集機能は上記の3つのどれかで実装するのが良いと思われます．

![grid埋めこみ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431996/8c346f9b-e25f-0864-442e-d54b447f6753.png)

```php:AuthorController.php
protected function form($id = null)
{
    if($id) {
        //Bookのgird画面のHTMLレンダリングを先に行う
        $html = '';

        //Book用のgridを作成する
        $grid = new Grid(new Book);
        $grid->setName('BOOK')
            ->setTitle('本')
            ->setRelation(Author::find($id)->books())
            ->resource('/admin/books');

        $grid->title('タイトル')->editable();
        $grid->subtitle('サブタイトル')->editable();
        $grid->page('ページ数')->editable();
        $grid->price('価格')->editable();

        //ボタンを無効
        $grid->disableExport();
        $grid->disableFilter();
        $grid->disablePagination();
        $grid->disableRowSelector();
        $grid->tools(function ($tools) {
            $tools->disableRefreshButton();
        });

        //操作を無効化
        $grid->actions(function ($actions) {
            $actions->disableView();
            $actions->disableEdit();
            });

        $html = $grid->render();
    }

    $form = new Form(new Author);

    $form->tab('氏名',function($form) {
        $form->hidden('id');
        $form->text('first_name', '名');
        $form->text('last_name', '氏');
    })->tab('本',function($form) use ($html) {
        $form->html(function() use ($html) {
            return $html;
        })->setWidth(12, 0);
    });

    return $form;
}
```

### まとめ
4つの表示方法を紹介しましたが，いずれも一長一短で状況に応じて使い分けるのが良いと思います．
また，index画面の埋めこみはかなりトリッキーな実装をしているので，ここまでするなら素直にbladeを書いたほうが良い気もします．