LumenでDBと連携した簡単なapiを作ってみる

> The stunningly fast micro-framework by Laravel.

LumenはLaravelの小さい版です.
Laravelはフルスタックなフレームワークであるのに対し，Lumenはマイクロフレームワークです．

いくつかあるPHPフレームワークの中でLaravelがいいなぁっていう理由は[Laravelの環境構築からちょっと動かすまでの話](http://qiita.com/shu920921/items/6236882abc8e2849bb39)で少し書きました．

ただ，簡単なアプリケーションや，apiを作成し，実行するにはちょっと重いなぁっていうのがよく言われてる話でした．

そこでLaravelらしさたっぷりの軽量なLumenを試してみよう！というわけです．


## 環境

|項目|バージョン|
|:---:|:---:|
|OS|macOS Sierra ver.10.12.5|
|php|5.6|

## 前提
Composerが入っている
入ってない人は[こちらの記事](http://qiita.com/shu920921/items/6236882abc8e2849bb39)を参考にしてください．

## 導入

```bash:Lumen入手
composer global require "laravel/lumen-installer"
```

## 実装
### プロジェクト作成
```bash:作成
$ composer create-project --prefer-dist laravel/lumen news
```
Laravelのプロジェクト作成とほぼ一緒です．
ちなみになんですが，これはプロジェクト名がnewsということです．

### 環境設定
Laravelではプロジェクト作成の際に`.env`ファイルが作成されるが，Lumenでは作成されないので，`.env.example`をコピーするところから始めましょう．

```text:.env
APP_ENV=local
APP_DEBUG=true
APP_KEY=SomeRandomKey!!!

### ここを適宜変更！
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
###

CACHE_DRIVER=memcached
QUEUE_DRIVER=sync

### ここもあとで使う
VERSION=v1
```

MySQLからニュースに関する情報を持ってくることにします．
今回使用するデータベースの名前はnewsとしました．

### DBのMigration
ターミナルから

```
$ php artisan make:migration create_articles_table --create=articles
```

すると，`database/migrations`に`タイムスタンプ_create_articles_table.php`が作成されます．

そのファイルをちょこっと編集

```php:database/migrations/2017_06_12_131529_create_article_table.php
<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateArticleTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->increments('id');
　　　　　　 //ここ追加！
            $table->string('title');
            $table->text('contents');
　　　　　　 //
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('articles');
    }
}
```

Migrationする(ターミナルから)

```
$ php artisan migrate
Migration table created successfully.
Migrated: 2017_06_12_131529_create_article_table
```

DBを見てみると，

```text:テーブル確認
mysql> show tables;
+----------------+
| Tables_in_news |
+----------------+
| articles       |
| migrations     |
+----------------+
2 rows in set (0.00 sec)
```

入ってますね．
ダミーデータをSeedするやり方もLumenには用意されてますが，今回はとりあえずこのままDBからinsertしちゃいます．

入れました．

```text:データ挿入後
mysql> select * from articles;
+----+--------+-----------+------------+------------+
| id | title  | contents  | created_at | updated_at |
+----+--------+-----------+------------+------------+
|  1 | title1 | contents1 | NULL       | NULL       |
|  2 | title2 | contents2 | NULL       | NULL       |
|  3 | title3 | contents3 | NULL       | NULL       |
+----+--------+-----------+------------+------------+
3 rows in set (0.00 sec)
```

しまった．．．
titleとcontentsしかinsertしてないからtimestampのところがnullになってしまった．．．．
このまま行きますwww

Seedとかアプリケーションからの挿入だとちゃんと入ります．

### エンドポイント決める

Routingに関しては，`app/Http/routes.php`に記述
今回は記事一覧とその記事の詳細を見れるapiを作ることにします．(今回はgetするだけですすみません．．)

```php:app/Http/routes.php
<?php

$app->get(env('VERSION').'/articles', 'ArticleController@get');

$app->get(env('VERSION').'/articles/{id}', 'ArticleController@getById');
```

`$app->get(env('VERSION').'/articles', 'ArticleController@get');`は`v1/news`というアクセスに対して，`app/Http/controllers/ArticleController`の`get`メソッドを実行するということです．

`env()`は前に色々記述した`.env`ファイルの中身を参照するものです．
key:VERSIONのvalueはv1でしたよね．

### モデル作成

```php:Article.php
<?php
/**
 * Created by PhpStorm.
 * User: shu920921
 * Date: 2017/06/12
 * Time: 22:22
 */

namespace App;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{

    protected $table = 'articles';
}
```

ぶっちゃけこれなくてもなんとかなる．
あとでORMとして[Eloquent](https://laravel.com/docs/5.4/eloquent#eloquent-model-conventions)を用いるのですが，モデルがあった方がわかりやすいので．．

デフォルトだと`Article`モデルにはDBの`articles`テーブルの中身がマッピングされる？みたいです．
なのでここの記述はモデル名とテーブル名が異なるときとか，フィールドとDBのカラム名・カラム数が異なる場合とかにいろいろ記述する感じですかね．

### ORMを使用する
`bootstrap/app.php`にて，`$app->withEloquent();`のコメントアウトを外す．それだけ．

### Controllerの作成

```php:app/Http/Controllers/ArticleController.php
<?php
/**
 * Created by PhpStorm.
 * User: shu920921
 * Date: 2017/06/12
 * Time: 21:58
 */

namespace App\Http\Controllers;

use App\Article;

class ArticleController extends Controller
{
    public function get()
    {
        $articles = Article::all();
        return response()->json($articles);
    }

    public function getById($id)
    {
        $article = Article::find($id);
        return response()->json($article);
    }
}
```

`$articles = Article::all();`らへんが`Eloquent`を使用したところです．
いろいろ使い方がありそうなので詳しくは[Eloquent](https://laravel.com/docs/5.4/eloquent#eloquent-model-conventions)を参照して頂きたいです．


Responseに関してですが，[Lumen公式](https://lumen.laravel.com/)とか色々見たけどこういう書き方してるのはなかった気がするからもしかして間違ってるかもしれないっす

### 実行！

```実行
$ php -S localhost:8000 -t public
```

記事一覧：
[http://localhost:8000/v1/articles](http://localhost:8000/v1/articles)

```json:記事一覧
[{"id":1,"title":"title1","contents":"contents1","created_at":null,"updated_at":null},{"id":2,"title":"title2","contents":"contents2","created_at":null,"updated_at":null},{"id":3,"title":"title3","contents":"contents3","created_at":null,"updated_at":null}]
```

記事詳細：
[http://localhost:8000/v1/articles/1](http://localhost:8000/v1/articles/1)

```json:記事詳細
{"id":1,"title":"title1","contents":"contents1","created_at":null,"updated_at":null}
```

responseの返し方は怪しかったが無事動いている．