Riot.js 3.3 と Lumen 5.4 でつくる 初めてのSPA バックエンド編
はじめに
最近 Riot が気になっていたので、
Laravel製軽量フレームワーク Lumen 5.4 と Riot 3.3 で簡単なブログを作ってみることにした。
今回はバックエンド編。
ここでは DB や API をさくっと作っていく。
ダミーテキストはWebtoolsのダミーテキストジェネレータで作成している。
これを使えば日本語・英語・数字混合のダミーテキストが作れる。
他のエントリーはこちら。
スポンサーリンク
作るもの
いろいろ頑張って最終的にこんな感じのブログを作る。
- 記事一覧の表示(カテゴリーの絞り込みあり)
- 記事詳細の表示
- 記事の新規作成・更新
記事一覧
記事詳細
記事編集
記事保存
前提
- Lumen 5.4.5
- Riot.js 3.3.1
手順
- ファサードと Eloquent ORM を使えるようにする
- テーブルの作成
- モデルの作成
- ルーティングの作成
- コントローラの作成
- データの挿入
1. ファサードと Eloquent ORM を使えるようにする
ファサードと Eloquent ORM を使えるようにするため、 bootstarp/app.php
の
// $app->withFacades(); // $app->withEloquent();
の部分のコメントをはずしておく。
2. テーブルの作成
3つのテーブルを作成する。
- posts
- categories
- posts_categories
まずはマイグレートファイルの作成。
ドキュメントルートに移動してコマンドを実行。
$ php artisan make:migration create_posts_table --create posts $ php artisan make:migration create_categories_table --create categories $ php artisan make:migration create_posts_categories_table --create posts_categories
database/migrations
ディレクトリ以下に現在日時のマイグレートファイルが作成されるので、
それぞれテーブル定義を書いていく。
posts テーブル
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreatePostsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('posts', function (Blueprint $table) { $table->increments('id'); $table->string('title'); $table->text('text'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('posts'); } }
categories テーブル
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateCategoriesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('categories', function (Blueprint $table) { $table->increments('id'); $table->string('name', 100); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('categories'); } }
posts_categories テーブル
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreatePostsCategoriesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('posts_categories', function (Blueprint $table) { $table->increments('id'); $table->integer('post_id'); $table->integer('category_id'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('posts_categories'); } }
テーブル定義ができたらマイグレートを実行してテーブルを作成する。
$ php artisan migrate
3つのテーブルができた!
mysql> desc posts; +------------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+------------------+------+-----+---------+----------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | title | varchar(255) | NO | | NULL | | | text | text | NO | | NULL | | | created_at | timestamp | YES | | NULL | | | updated_at | timestamp | YES | | NULL | | +------------+------------------+------+-----+---------+----------------+ mysql> desc categories; +------------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+------------------+------+-----+---------+----------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | name | varchar(100) | NO | | NULL | | | created_at | timestamp | YES | | NULL | | | updated_at | timestamp | YES | | NULL | | +------------+------------------+------+-----+---------+----------------+ mysql> desc posts_categories; +-------------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+------------------+------+-----+---------+----------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | post_id | int(11) | NO | | NULL | | | category_id | int(11) | NO | | NULL | | | created_at | timestamp | YES | | NULL | | | updated_at | timestamp | YES | | NULL | | +-------------+------------------+------+-----+---------+----------------+
3. モデルの作成
app の直下にモデルを作成する。
app/Post.php
app/Category.php
app/PostsCategory.php
の3つのモデルを作成。
Posts.php
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Post extends Model { protected $fillable = [ 'title', 'text' ]; }
Category.php
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Category extends Model { protected $fillable = [ 'name' ]; }
PostsCategory.php
<?php namespace App; use Illuminate\Database\Eloquent\Model; class PostsCategory extends Model { protected $fillable = [ 'post_id', 'category_id' ]; }
4. ルーティングの作成
routes/web.php
に API のルーティングを追記する。
$app->group(['prefix' => 'api/'. env('API_VERSION', 'v0')], function ($app) { $app->get('posts', 'PostController@index'); $app->get('posts/{id: \d+}', 'PostController@show'); // {param: 正規表現} とすることで正規表現に一致するパラメータのみ許可する。 $app->post('posts', 'PostController@create'); $app->put('posts/{id: \d+}', 'PostController@update'); $app->get('categories', 'CategoryController@index'); });
また、env('API_VERSION', 'v0')
のところで API のバージョンを指定しているため、
.env
に API_VERSION
の定数を追記しておく。
API_VERSION=v1
5. コントローラの作成
app/Http/Controllers
にコントローラを作成する。
app/Http/Controllers/PostController.php
app/Http/Controllers/CategoryController.php
の2つのコントローラを作成。
PostController.php
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use DB; use App\Post; use App\Category; use App\PostsCategory; class PostController extends Controller { /** * 記事一覧を取得する。 * * @param Request $request * @return string */ public function index(Request $request) { $post = Post::orderBy('id', 'desc'); if (!empty($request['category'])) { $category = Category::where('name', $request['category'])->first(); if (empty($category)) abort(404); $postIds = PostsCategory::where('category_id', $category->id) ->get(['post_id']) ->toArray(); $ids = []; foreach ($postIds as $key => $value) { array_push($ids, $value['post_id']); } $post->whereIn('id', $ids); } $post = $post->get(); if (empty($post)) abort(404); foreach ($post as $key => $value) { $post[$key]->categories = $this->getCategories($value->id); } return response()->json($post); } /** * 特定の記事を取得する。 * * @param int $id * @return string */ public function show($id) { $post = Post::find($id); if (empty($post)) abort(404); $post->categories = $this->getCategories($post->id); return response()->json($post); } /** * 記事を作成する。 * * @param Request $request * @return string */ public function create(Request $request) { $post = new Post; $post->title = $request->title; $post->text = $request->text; if ($post->save()) { if (isset($request->categories) && is_array($request->categories)) { foreach ($request->categories as $key => $value) { $postsCategory = new PostsCategory; $postsCategory->post_id = $post->id; $postsCategory->category_id = $value; $postsCategory->save(); } } return response()->json(true); } else { abort(501); } } /** * 記事を更新する。 * * @param Request $request * @param int $id * @return string */ public function update(Request $request, $id) { if (empty($id)) abort(404); $post = Post::find($id); if (empty($post)) abort(404); $post->title = $request->title; $post->text = $request->text; if ($post->save()) { PostsCategory::where('post_id', $post->id)->delete(); if (isset($request->categories) && is_array($request->categories)) { foreach ($request->categories as $key => $value) { $postsCategory = new PostsCategory; $postsCategory->post_id = $post->id; $postsCategory->category_id = $value; $postsCategory->save(); } } return response()->json(true); } else { abort(501); } } /** * 特定の記事が属しているカテゴリーを取得する。 * * @param int $post_id * @return array $categories */ private function getCategories($post_id) { $query = 'select pc.post_id, pc.category_id, (select name from categories as c where c.id=pc.category_id) as category_name from posts_categories as pc where pc.post_id=?'; $rawCategries = DB::select($query, [$post_id]); $categories = []; if (!empty($rawCategries)) { foreach ($rawCategries as $key => $value) { array_push($categories, $value->category_name); } } return $categories; } }
CategoryController.php
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Category; class CategoryController extends Controller { /** * カテゴリー一覧を取得する。 * * @return string */ public function index() { $data = Category::orderBy('id', 'asc')->get(); if (empty($data)) abort(404); return response()->json($data); } }
6. データの挿入
categories テーブルにマスターデータを挿入しておく。
insert into categories (name) values ('Tech'), ('Book'), ('Hobby'), ('Others');
また、posts テーブルと posts_categories テーブルにはダミーデータを入れておくとつなぎこみ時に便利。
insert into posts (title, text) values ('Lorem ipsum dolor si', 'これはダミーテキストです。フォントやレイアウトを確認するために入れています。Lorem ipsum dolor sit amet, consectetur.これはダミーテキストです。フォントやレイアウトを確認するために入れています。Lorem ipsum dolor sit amet, consec'), ('Lorem ipsum dolor si', 'これはダミーテキストです。フォントやレイアウトを確認するために入れています。Lorem ipsum dolor sit amet, consectetur.これはダミーテキストです。フォントやレイアウトを確認するために入れています。Lorem ipsum dolor sit amet, consec'),('Lorem ipsum dolor si', 'これはダミーテキストです。フォントやレイアウトを確認するために入れています。Lorem ipsum dolor sit amet, consectetur.これはダミーテキストです。フォントやレイアウトを確認するために入れています。Lorem ipsum dolor sit amet, consec'),('Lorem ipsum dolor si', 'これはダミーテキストです。フォントやレイアウトを確認するために入れています。Lorem ipsum dolor sit amet, consectetur.これはダミーテキストです。フォントやレイアウトを確認するために入れています。Lorem ipsum dolor sit amet, consec'); insert into posts_categories (post_id, category_id) values (1, 1), (1, 2), (2, 1), (2, 3), (2, 4), (3, 1), (4, 1), (4, 2), (4, 3), (4, 4);
まとめ
Lumen で ブログシステムのバックエンドを作成した。
Lumen は API だけを作るときとかは簡単に作れるので便利。
関連記事
スポンサーリンク