LaravelのCRUDコード生成ツールを作って開発効率が爆上げした

# 作ったもの
LaravelのCRUDコード＆Testコードをmigrationの項目から自動生成できるツールです。

【URL】
https://7k095m9l6q.csb.app/

【画面】
![スクリーンショット 2019-08-12 20.28.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246680/ba16ec0d-4470-e260-fa6a-8d7b41b8492f.png)
　↓
![スクリーンショット 2019-08-12 20.26.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246680/5660e40b-48cf-39c7-5422-1f00f27e4b27.png)


以下の構成のコードが作れます。（具体的な内容は後で紹介）

* Controller
* Service
* TestCase

▼おまけのコード

* Vue.jsのsample
* bladeのsample
* Routing (API)のsample

# 利用シーン／メリット

* CRUD処理の実装が簡単になる
* Serviceクラスに実処理を書いてControllerを肥大化させないようにする
* 自動生成なのでタイプミスによるバグがなくなる
* UnitTestをして正しく動くことを確認できる
* インストール不要、ブラウザからいつでも利用可能 （無料）

実際利用してから新規機能の**開発効率が5倍くらい**上がりました。

# なぜ作ったのか
**「早く、動くモノを作る」**ためにどうしたらいいのかを考えた。
DB設計して、基本的なCRUDができるようになるための実装はルーティン作業だと気づいた。

【これまでの実装フロー】
①DB設計
　↓
②migration作成
　↓
③Modelクラス実装
　↓
④Controller実装（create, get, update, delete..) ★
　↓
⑤Service実装（create, get, update, delete..) ★
　↓
⑥フロント実装（js, bladeなど）
　↓
⑦テスト：データの取得→表示、新規作成や更新ができることを確認
　↓
⑧バグを修正して仕上げる

一通り実装してからテストをすると、大抵どこかタイプミスがあったり、引数が間違っていたり、記述ミスがあったりしてエラーで動かないことが多い。
でもやろうとしていることは単純な処理なので、ここに時間を費やしてしまうのは時間のムダである。
データの項目名／型が違うだけで、あとは基本全て同じ動き(=実装)になる。

機械的に決まるコード（考えなくてもいいコード）なら自動化してしまえ！ということで、本ツールを作った。

# どうやって作ったか
以下のFWと環境でオンライン上で完結させた。
FW ： [Vuetify.js](https://vuetifyjs.com/ja/)
環境： [codesandbox](https://codesandbox.io/dashboard)

[>>完成コード](https://codesandbox.io/s/github/narith-minami/laravel-crud-and-test-code-generator)

ロジックは文字の連結だけで済むのでjsが動けばよかった。
スタイルの調整とかも面倒なので、マテリアルデザインが内包されたVueのフレームワークである「Vuetify.js」を使ってみた。

# 開発期間
12時間くらいで完成（週末の合間に実装）


# 使い方
使い方はめちゃくちゃ簡単です。

1. Model名を入力
2. updateのキーを入力
3. selectのキーを入力

入力前
![スクリーンショット 2019-08-12 23.19.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246680/1616a978-3613-842d-15c7-7f006dd43a1d.png)

入力後
![スクリーンショット 2019-08-12 23.20.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246680/8e0f34e4-f290-a419-f66c-72dbc6daf2d2.png)

4-1. カラムを入力

入力前
![スクリーンショット 2019-08-12 23.20.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246680/5b327226-bf07-f656-0a94-08ffed01d39f.png)

入力後
![スクリーンショット 2019-08-12 23.21.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246680/248e885a-5c2e-59a4-bb5e-75d54d2bb508.png)

カラムは一個ずる入れるのは面倒ですよね。
migrationがすでにできてるから、そこから一発でバチン！と一括入力することもできます。

(1) migrationの項目定義部分をコピー
![スクリーンショット 2019-08-12 23.27.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246680/a1f66067-7a02-d8ce-1f34-e8ab9cd84586.png)

(2) テキストエリア欄にペースト
![スクリーンショット 2019-08-12 23.28.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246680/4b646f33-fc7a-091b-ec9f-c7537b20aa88.png)
　　↓
![スクリーンショット 2019-08-12 23.29.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246680/bc4f31c7-03b3-e897-ca78-e056313d1122.png)

(3) CHECKボタンをクリック
id(increments)とtimestampsを除外して読み取ります
![スクリーンショット 2019-08-12 23.30.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246680/13fb30c0-80aa-f22f-3348-f590b0af8076.png)

## 生成されるコード
### Controller

以下のコードができるので、COPYボタンでコピーしてControllerに貼り付けます

```php
	private $postService;

	public function __construct(PostService $postService)
	{
		$this->postService = $postService;
		$this->middleware('auth');
	}

	public function createPost()
	{
		$this->middleware('auth');
		// $user_id = Auth::user()->id; // if you need login userId
		$user_id = request('userId');
		$title = request('title');
		$body = request('body');
		$this->postService->createPost($user_id, $title, $body);
		return ['code' => '200']; // TODO
	}

	public function updatePost()
	{
		$this->middleware('auth');
		// $user_id = Auth::user()->id; // if you need login userId
		$id = request('id');
		$user_id = request('userId');
		$title = request('title');
		$body = request('body');
		$this->postService->updatePost($id, $user_id, $title, $body);
		return ['code' => '200']; // TODO
	}

	public function getPost($userId)
	{
		$data = $this->postService->getPost($userId);
		return ['code' => '200', 'data' => $data]; // TODO
	}

```

### Service

同様にServiceクラスにコピペしましょう

```php
public function createPost($user_id, $title, $body)
{
	$model = new Post();
	$model->user_id = $user_id;
	$model->title = $title;
	$model->body = $body;
	$model->save();
	return $model;
}

public function updatePost($id, $user_id, $title, $body)
{
	$model = Post::updateOrCreate(
		['id' => $id],
		['user_id' => $user_id, 'title' => $title, 'body' => $body]);
	return $model;
}

public function getPost($user_id)
{
	$model = Post::where('user_id', $user_id)->first();
	return $model;
}
```
その他実装点を**Note:**に書いているので忘れずに書きましょう。
![スクリーンショット 2019-08-12 23.35.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246680/f37c2ec5-b361-b53f-ccf3-3982eb88465a.png)

## TestCase
artisanの<code>make:test</code>でテストクラスを作ってそちらにコピペ。

```
$ php artisan make:test PostTest --unit
```

```php
private $postService;

public function setUp()
{
	$this->postService = new \App\Services\PostService();
	parent::setUp();
}

public static function tearDownAfterClass()
{
	Post::where('user_id', 99999)->delete();
}

public function testCreatePost()
{
	$user_id = 9999; //＊＊おかしなところはちょっと修正してください
	$user_id = 10; //＊＊おかしなところはちょっと修正してください
	$title = 'This is title';
	$body = 'This is body';

	$result = $this->postService->createPost($user_id, $title, $body);
	$model = Post::where('user_id', $user_id)->first();

	$this->assertSame($model->user_id, $user_id);
	$this->assertSame($model->title, $title);
	$this->assertSame($model->body, $body);
}

public function testGetPost()
{
	$user_id = 9999; //＊＊おかしなところはちょっと修正してください
	$user_id = 10; //＊＊おかしなところはちょっと修正してください
	$title = 'This is title';
	$body = 'This is body';

	$model = $this->postService->getPost($user_id);

	$this->assertSame($model->user_id, $user_id);
	$this->assertSame($model->title, $title);
	$this->assertSame($model->body, $body);
}

public function testUpdatePost()
{
	$id = 9999;
	$user_id = 100;
	$title = 'This is title[update]';
	$body = 'This is body[update]';

	$result = $this->postService->updatePost($id, $user_id, $title, $body);
	$model = Post::where('user_id', $user_id)->first();

	$this->assertSame($model->user_id, $user_id);
	$this->assertSame($model->title, $title);
	$this->assertSame($model->body, $body);
}

```
Note:も忘れずに
![スクリーンショット 2019-08-12 23.40.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246680/173d2261-cb0b-1c7d-8cd9-31a6ab86b173.png)

## おまけのコード
### vue.js
![スクリーンショット 2019-08-12 23.43.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246680/4b2378ef-b4f7-4775-0530-725cf45f794c.png)

### api.php (Routing)
![スクリーンショット 2019-08-12 23.44.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246680/6992e5a8-7611-dcb1-ee30-c99bdaa0144e.png)
（deleteとupdate忘れた）

### bladeとその他作業メモ
![スクリーンショット 2019-08-12 23.44.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246680/c59dad3f-9684-8a59-cbdc-e8015536a224.png)

# ツール利用後の開発フロー

【これまでの実装フロー】
①DB設計
　↓
②migration作成
　↓
③Modelクラス作成
　↓
④Controller/Service/TestCaseクラス作成
　↓
⑤ツールを利用してコードをコピペ ★
　↓
⑥テスト(1)：Unitテストで動作検証（＊ここで正常に動けばServiceクラスはOK） ★
　↓
⑦フロント実装（js,bladeなど）
　↓
⑧テスト(2)：画面からの疎通確認できれば完了
　↓
⑨バグを修正して仕上げる（基本バグは出ない）

# 終わりに
本ツールはあくまで自分の作業を簡単にするために作ったものなので、必ずしも他の人にも便利なものとは限らないです。
クラス設計とか構成がそもそも違うとか、思想が違うとかこだわりがそれぞれあると思うので、もし使えるなら使ってみてくださいというくらいです。

大事なことは「いかに**作業時間を減らしつつ、品質を下げず、早くリリース**するか」を考えて、自分の作業を簡単にするための外部のツールを導入してみたり、自分で開発してみたり、いろんな工夫をすることがプログラミング業務において重要なことだと思います。

Enjoy!!