laravel5.4でscaffoldしたい : laralib/l5scaffold

# laralib/l5scaffold

- packagist
    - https://packagist.org/packages/laralib/l5scaffold

# scaffold simple table

```:console
$ php artisan make:scaffold AdminUser \
      --schema="name:string, mail:string" \
      --ui="bs3"
```

```:console
$ php artisan route:list

+--------+----------+----------+------+---------+--------------+
| Domain | Method   | URI      | Name | Action  | Middleware   |
+--------+----------+----------+------+---------+--------------+
|        | GET|HEAD | /        |      | Closure | web          |
|        | GET|HEAD | api/user |      | Closure | api,auth:api |
+--------+----------+----------+------+---------+--------------+
```

## 生成ファイル一覧

### views

- resources/views/admin_users/create.blade.php
- resources/views/admin_users/edit.blade.php
- resources/views/admin_users/index.blade.php
- resources/views/admin_users/show.blade.php
- resources/views/error.blade.php
- resources/views/layout.blade.php

### controllers

- app/Http/Controllers/AdminUserController.php

### models

- app/AdminUser.php

### routes

_none_

### migrates

- database/migrations/2017_05_29_081101_create_adminusers_table.php

### tests

_none_

#### fixtures

_none_

### etc

- database/seeds/AdminUserTableSeeder.php


## 総感

routeは生成されないので自分で手作業する必要がある。CRUDなviewは生成されているっぽいが、testcaseやfixtureは生成されていない。モデルの内容に則さない形でseeder的なファイルが生成されているがテンプレートにするには不親切な感じ。しかし、今一番マシなライブラリのような気もする。それでもRESTで画面が用意されView用のコードも最小限でも生成されるのでlaravelのblade初学者には嬉しいと思う。

routeのrailsとの差異は小さいが、Nameの使い方がややこしい。

| Method    | URI                    | Name                | Rails Name         |
| --------- | ---------------------- | ------------------- | ------------------ |
| POST      | api/admin_users        | admin_users.store   | admin_users#create |
| GET       | api/admin_users/create | admin_users.create  | admin_users#new    |


具体的に生成ファイルされたファイル一覧は右記参照。https://github.com/laravel-scaffold-trial/laralib-l5scaffold/pull/1


## 追記

### 手動でrouteを追加

```php:routes/web.php
Route::resource('admin_users', 'AdminUserController');
```
`reoutes/api.php`に書くと、`admin_users.create`を呼ぶときにエラーする

```:console
$ php artisan route:list

+--------+-----------+-----------------------------------+---------------------+--------------------------------------------------+--------------+
| Domain | Method    | URI                               | Name                | Action                                           | Middleware   |
+--------+-----------+-----------------------------------+---------------------+--------------------------------------------------+--------------+
|        | GET|HEAD  | /                                 |                     | Closure                                          | web          |
|        | GET|HEAD  | admin_users                       | admin_users.index   | App\Http\Controllers\AdminUserController@index   | web          |
|        | POST      | admin_users                       | admin_users.store   | App\Http\Controllers\AdminUserController@store   | web          |
|        | GET|HEAD  | admin_users/create                | admin_users.create  | App\Http\Controllers\AdminUserController@create  | web          |
|        | GET|HEAD  | admin_users/{admin_user}          | admin_users.show    | App\Http\Controllers\AdminUserController@show    | web          |
|        | PUT|PATCH | admin_users/{admin_user}          | admin_users.update  | App\Http\Controllers\AdminUserController@update  | web          |
|        | DELETE    | admin_users/{admin_user}          | admin_users.destroy | App\Http\Controllers\AdminUserController@destroy | web          |
|        | GET|HEAD  | admin_users/{admin_user}/edit     | admin_users.edit    | App\Http\Controllers\AdminUserController@edit    | web          |
|        | GET|HEAD  | api/user                          |                     | Closure                                          | api,auth:api |
+--------+-----------+-----------------------------------+---------------------+--------------------------------------------------+--------------+
```

### sqliteでは正常に動かなかった

急遽mysqlをセットアップして`php artisan serve`したら接続出来た。laravel5.4はsqliteが使えないのかな・・？

# scaffold relation table

### migrationでrelationは出来たがviewは未実装らしい

オブジェクトの関係は下記のとおり

```puml
Book "1..*"---"1" Shelf
```

~~ほぼ手書き同様の書き方でforeign keyは定義できたけど~~、ソース読んだら、今回の場合は`shelf_id:integer:foreign`で良いらしいと分かった。scaffoldのviewの方ではbookからshelfは参照出来ず、bookを作成できなかった。

```:console
$ php artisan make:scaffold Shelf \
              --schema="title:string"
```
```php
public function up()
{
    Schema::create('shelves', function(Blueprint $table) {
      $table->increments('id');
      $table->string('title');
      $table->timestamps();
    });
}
```

```:console
$ php artisan make:scaffold Book \
              --schema="title:string, shelf_id:integer:foreign"
```
```php
public function up()
{
  Schema::create('books', function(Blueprint $table) {
    $table->increments('id');
    $table->string('title');
    $table->integer('shelf_id')->unsigned();
    $table->foreign('shelf_id')->references('id')->on('shelves');
    $table->timestamps();
  });
}
```
~~もうほぼ決め打ちなんだから、`shelf:references`で全部生成してくれも良さそうな気がする。~~やっぱrails偉大だわ。 よく考えてみれば外部キー名は任意なので、railsの慣習から外部キー名を`モデル_id`としたいだけで、hogeでもfugaでも良かった（なので、`shelf:integer:foreign`と書いても問題ない。が、色々と後々がややこしくなるので`モデル_id`が推奨か）。`shelf_id:integer:foreign:deleteOn('cascade')`とかも通るんじゃないだろうか。

参考：https://laravel.com/docs/5.4/migrations#foreign-key-constraints


```php:routes/web.php
Route::resource('books', 'BookController');
Route::resource('shelves', 'ShelfController');
```
作者がissuesで*Routeはマニュアルなんだよ*、って言い訳ぶっこいてるけど、viewsを生成しておいてRouteに手を付けない訳がないので、単に時間が足りてなくて未実装なだけだと思ってる。なので、そのうち実装されるんだと思ってる。

```:console
$ php artisan route:list

--------+-----------+----------------------+-----------------+----------------------------------------------+--------------+
| Domain | Method    | URI                  | Name            | Action                                       | Middleware   |
+--------+-----------+----------------------+-----------------+----------------------------------------------+--------------+
|        | GET|HEAD  | /                    |                 | Closure                                      | web          |
|        | GET|HEAD  | api/user             |                 | Closure                                      | api,auth:api |
|        | GET|HEAD  | books                | books.index     | App\Http\Controllers\BookController@index    | web          |
|        | POST      | books                | books.store     | App\Http\Controllers\BookController@store    | web          |
|        | GET|HEAD  | books/create         | books.create    | App\Http\Controllers\BookController@create   | web          |
|        | GET|HEAD  | books/{book}         | books.show      | App\Http\Controllers\BookController@show     | web          |
|        | PUT|PATCH | books/{book}         | books.update    | App\Http\Controllers\BookController@update   | web          |
|        | DELETE    | books/{book}         | books.destroy   | App\Http\Controllers\BookController@destroy  | web          |
|        | GET|HEAD  | books/{book}/edit    | books.edit      | App\Http\Controllers\BookController@edit     | web          |
|        | GET|HEAD  | shelves              | shelves.index   | App\Http\Controllers\ShelfController@index   | web          |
|        | POST      | shelves              | shelves.store   | App\Http\Controllers\ShelfController@store   | web          |
|        | GET|HEAD  | shelves/create       | shelves.create  | App\Http\Controllers\ShelfController@create  | web          |
|        | GET|HEAD  | shelves/{shelf}      | shelves.show    | App\Http\Controllers\ShelfController@show    | web          |
|        | PUT|PATCH | shelves/{shelf}      | shelves.update  | App\Http\Controllers\ShelfController@update  | web          |
|        | DELETE    | shelves/{shelf}      | shelves.destroy | App\Http\Controllers\ShelfController@destroy | web          |
|        | GET|HEAD  | shelves/{shelf}/edit | shelves.edit    | App\Http\Controllers\ShelfController@edit    | web          |
+--------+-----------+----------------------+-----------------+----------------------------------------------+--------------+

```

### viewで作成、更新できるように実装する

１対多が１セットしかないので、手間ではないが・・

```php:app/Book.php
class Book extends Model
{
...
    public function shelf()
    {
      return $this->belongsTo('App\Shelf');
    }
}
```
```php:app/Shelf.php
class Shelf extends Model
{
...
    public function books()
    {
      return $this->hasMany('App\Book');
    }
}
```
books()は要らないかも。

```php:app/Http/Controllers/BookController.php
  public function create()
  {
    $shelves = Shelf::get();
    return view('books.create', compact('shelves'));
  }

  public function edit($id)
  {
    $book = $this->model->findOrFail($id);
    $shelves = Shelf::get();
    return view('books.edit', compact('book', 'shelves'));
  }
```
```html:resources/views/books/create.blade.php
          <label for="shelf_id-field">Shelf_id</label>
          <select name="shelf_id" class="form-control">
            @foreach($shelves as $shelf)
              <option value="{{$shelf->id}}">{{$shelf->title}}</option>
            @endforeach
          </select>
```
```html:resources/views/books/edit.blade.php
          <label for="shelf_id-field">Shelf_id</label>
          <select name="shelf_id" class="form-control">
            @foreach($shelves as $shelf)
              @if($shelf->id == $book->shelf->id) <!-- App\Book#shelf()にbelongsTo('App\Shelf')を記述しているのでbookからshelfを特定出来る -->
                <option value="{{$book->shelf->id}}" selected>{{$book->shelf->title}}</option>
              @else
                <option value="{{$shelf->id}}">{{$shelf->title}}</option>
              @endif
            @endforeach
          </select>
```

- 参考: https://readouble.com/laravel/5.4/ja/eloquent-relationships.html#one-to-many
- 参考: https://readouble.com/laravel/5.4/ja/blade.html