目次
はじめに
Laravel6.0でテーブルと1:1の入力画面を作成する手順を整理します。
DBテーブル構築は「マイグレーション」、DB操作は「Eloquent」モデルを用います。
最初から難しいことやると混乱するので、まずは最低限から。
それでも、Laravel6.0でお作法通りにつくるには、以下の手順を踏む必要があります。
とりあえず、説明用に、仕様っぽいことだけ決めときます。
入力項目は以下の3つだけにします。
- コード:半角英数
- 氏名:漢字
- カナ氏名:全角カナ
手順を確認するのが目的なので、バリデーションは行いません。
画面に登録ボタンを置いて、押したらDBに更新する。
ただ、それだけやります。
作成するViewとコントローラの名称は以下にします。
アクセスするURLは以下にします。
とりあえず、ログインなしにダイレクトに表示するようにします。
作成するテーブル名は以下にします。
- dummy_items
注意が必要な点として、DBアクセスにEloquentモデルを使う場合は、名前の制約に注意する必要があるので、上記のテーブル名も、モデルの制約にしたがってます。
1.DBテーブルのマイグレーション
入力項目に対応したテーブルを生成します。
Laravelでテーブルを生成するお作法にそって、マイグレーションします。
手順としては。
- php artisan make:migrationコマンドで、マイグレーション用ソース生成
- ソースのup()とdown()メソッドに必要な項目定義などを追記する。
- php artisan migrateコマンドでデータベースに反映する
です。
マイグレーション用ソース生成
マイグレーション用ソース生成です。
名前は作成するテーブル名に「create」をつける必要があります。
生成に成功すると、以下のテーブルにソースコードが生成されま
database\migrations
生成されたファイル名には、テーブル名に日付_時刻_が付いてます。
例えば、「2019_10_25_234455_create_dummy_items.php」みたいな感じです。
このファイル名は変更しません。
変更しても良いですが、面倒なだけで、メリットは何もありませんから。
生成されたソースはこんな感じです。
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateDummyItems extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('dummy_items', function (Blueprint $table) { $table->bigIncrements('id'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('dummy_items'); } }
up()とdown()という2つのメソッドがあります。
up()は新しいテーブル、カラム、インデックスをデータベースに追加する時に実行するメソッドです。
up()には
$table->bigIncrements('id');
$table->timestamps();
がデフォルトでセットされてます。
ここに、新たに項目の定義を追加していけばよいというわけです。
down()はup()で行った操作を元に戻す時に実行するメソッドです。
こちらは自動生成された時にすでに「 Schema::dropIfExists('dummy_items');」が定義されていますので、そのままで大丈夫です。
ソースのup()とdown()メソッドに必要な項目定義などを追記する
up()にテーブル・カラムを追加していきます。
項目に対するカラム名は以下にします。
- コード => c_code
- 氏名 => c_name
- カナ氏名 => c_kana_name
そうすると以下のようになります。
public function up() { Schema::create('dummy_items', function (Blueprint $table) { $table->bigIncrements('id'); $table->char('c_code', 10); $table->string('c_name'); $table->string('c_kana_name'); $table->timestamps(); }); }
見た通りではありますが、いくつかポイントがあります。
Eloquent ORM規約:テーブル
データ操作に「Eloquent ORM」を使うので、その「モデル規約」に従う必要があるからです。
規約に従うポイントを整理していきます。
まず、テーブル名です。
dummy_items
と複数形にしています。
これは「Eloquent ORM」がテーブルを探すデフォルトの動作が
他の名前を明示的に指定しない限り、クラス名を複数形の「スネークケース」にしたものが、テーブル名として使用されます。
だからです。
必然的に、対応するModelクラス名は「DummyItem」に決まります。
Eloquent ORM規約:キー
次が主キーの制約です。
$table->bigIncrements('id');
は自動インクリメントする主キーで、これは必須です。
かつ、カラム名は「id」固定です。
一部抜粋すると。
Eloquentは更にテーブルの主キーがidというカラム名であると想定しています。
さらに、Eloquentは主キーを自動増分される整数値であるとも想定しています。
つまり、デフォルト状態で主キーは自動的にintへキャストされます。
ということだからです。
Eloquent ORM規約:タイムスタンプ
続けて。
タイムスタンプの制約です。
$table->timestamps();
名前指定がありませんが、これで「 created_at」と「updated_at」という2つのカラムを作ります。
これもLaravel標準の「Eloquent ORM」を使うには重要なポイントです。
デフォルトでEloquentはデータベース上に存在するcreated_at(作成時間)とupdated_at(更新時間)カラムを自動的に更新します。
からです。
down()について
前にも書いたように、down()は今回、生成されたままで変更しません。
public function down() { Schema::dropIfExists('dummy_items'); }
こちらはシンプルにテーブルがあるかチェックして、あればドロップするだけです。
これで一旦定義はOKとします。
php artisan migrateコマンドでデータベースに反映する
ソースに記述を追加できたら、以下のコマンドを実行します。
php artisan migrate
これにより、データベースにテーブルを作成します。
それだけなのですが。
ひとつ補足します。
既にマイグレーション済のソースが残っている場合です。
上記のコマンドでは特に対象のソースを指定しません。
なので、単純に実行したら、既にマイグレーション済のものも再実行されてテーブルが消えてしまうのではないか?・・と心配になります。
でも、心配ありません。
実は、一度実行したソース名がテーブルmigrationsに記録されています。
ここにある限り、再実行されません。
実際、MySQL(MariaDB)に接続して、migrationsテーブルをSelectするとこんな感じになってます。
マイグレーションのソースのファイル名を下手に変更したら、面倒なことになる理由がここにあります。
マイグレーションの結果生成されたテーブルはこうです。
いちおう、想定通りにはできてます。
2.Eloquentモデルの作成
先ほど生成したテーブルに対応する Eloquentモデルを作ります。
Eloquentモデルについての説明を引用すると。
それぞれのデータベーステーブルは関連する「モデル」と結びついています。
モデルによりテーブル中のデータをクエリできますし、さらに新しいレコードを追加することもできます。
ということですが「ふーん」という感じです。
まあ。
やってみればわかるでしょう・ということですすめます。
まず、artisanコマンドで、スケルトンのソースを生成します。
対象テーブルが「dummy_items」なので、テーブル名制約に従えば、モデルクラスの名前は必然的に「DummyItem」に決まります。
実行すると、「app」フォルダに「DummyItem.php」ができます。
<?php namespace App; use Illuminate\Database\Eloquent\Model; class DummyItem extends Model { // }
とりあえず、今回やる程度のことなら、Modelに関してはこれで終わりです。
中身が空なので、本当に大丈夫か?って心配になりますが、テーブル名制約にそって正しい名前でモデルクラスができていれば、これだけで、テーブルへのアクセスができるということなのですね。
なので次にいきます。
3.コントローラクラス作成
別に特殊なコントローラを作るわけではないので、ダイレクトに作ってもよいのですが、手順として、以下のようにコマンドで生成します。
これで、「app\Http\Controllers」フォルダに、DummyController.phpができます。
生成されただけだと、こんな感じです。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class DummyController extends Controller { // }
ここに以下を追加していきます。
- モデルを利用するためのuse文
- データベースを更新するstore()メソッド
修正後のソースはこちらです。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\DummyItem; class DummyController extends Controller { public function store(Request $request) { $code = $request->code; $name = $request->name; $kana = $request->kana; $dummyItem = new DummyItem; $dummyItem->c_code = $code; $dummyItem->c_name = $name; $dummyItem->c_kana_name = $kana; $dummyItem->save(); $msg = "登録プログラムで。「" .$code . " " . $name . " " . $kana . "」を登録しました。"; return view('dummy', compact( 'msg' )); } }
ポイントを補足します。
画面の入力値は、Requestオブジェクトから取得します。
つまり。
入力画面にあたる「dummy.blade.php」の<input>タグのnameは
- code
- name
- kana
にしないといけない・・ということがここで決まります。
前に生成したDummyItemモデルをstore()内でnewしています。
このクラス自体はほぼ空ですが、名前付けルールに従って自動的に「dummy_items」テーブルを参照しにいきます。
なので。
DummyItemクラスのどこにも定義されていない、テーブルのカラム「c_code」「c_name」「c_kana_name」に対して代入もできてしまいます。
値をセットして「save()メソッド」を実行します
これで、キー項目「id」および「 created_at」と「updated_at」には自動的に値がセットされます。
確認画面をわざわざ作るのが面倒なので、最後は、入力画面にreturnしてます。
一応、処理したことがわかるように、メッセージだけセットしてます。
4.ルート設定
コントローラクラスのstoreメソッドと、初期入力画面にする「dummy.blade.php」に対してルートを設定します。
routes\web.phpに以下を追加します。
Route::get('/dummy', function () { return view('dummy'); }); Route::post('/newdummy', 'DummyController@store')->name('newdummy');
上が初期表示。
下が、コントローラのstore()メソッドの呼び出しです。
formの中で指定しやすいように「->name('newdummy')」を使って、名前付きルートにしています。
5.入力画面作成
最後に入力画面です。
resources/viewsに「dummy.blade.php」を作成します。
今回は、ポイントを明確にするため、コード・氏名・カナ名を入力し、登録ボタンを押すと、元の画面に戻り「登録しました」的メッセージを表示するだけの画面にします。
viewにおける確認ポイントは3つです。
- Form利用時には「@csrf」ディレクティブが必須
- Formの「action="{{ route('newdummy') }}"」
- 確認画面と入力画面を併用する場合に必要な{{ $msg ?? '' }}の書き方
Form利用時には「@csrf」ディレクティブが必須
まず。
@csrfディレクティブです。
Formを使う場合、これは必須です。
定義していないと、フォームの送信時にLaravelのCSRF保護ミドルウェアに対象にしてもらえず、セキュリティ的な問題が残ります。
Formの「action="{{ route('newdummy') }}"」
「action="{{ route('newdummy') }}"」は、登録ボタンを押した時に実行されるものです。
route('newdummy')は、前のルート定義で、DummyControllerのstore()メソッドに紐づけられていますので、それが実行されるわけです。
確認画面と入力画面を併用する場合に必要な{{ $msg ?? '' }}の書き方
横着して入力画面と確認画面を併用しています。
つまり。
$msgという変数は、確認画面として使う時・・つまりコントローラクラスからReturnされた時・・しか定義されていません。
なので。
{{ $msg }} と書くと、「$msgは未定義です」とエラーになって、初期画面表示ができなくなります。
そんな時は{{ $msg ?? '' }}と書いておくと、$msgが未定義でもエラーになりません。
old()構文
inputタグのvalueのところでold()構文を使っています。
これはバリデーションエラーの時みたいに、リダイレクトで戻ってきた時に、セッションから入力値を復元して再表示してくれる便利な構文なのですが、今回は、バリデーションを一切していないので、本来なら不要です。
でも。
次回以降にどうせバリデーションいれるから・・ということで、書いてます。
viewのソースです
dummy.blade.php
@extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> <div class="card"> <div class="card-header">サンプル入力</div> <div class="card-body"> <p>{{ $msg ?? '' }}</p> <form method="POST" action="{{ route('newdummy') }}"> @csrf <div class="form-group row"> <label for="code" class="col-md-4 col-form-label text-md-right">コード</label> <div class="col-md-6"> <input id="code" type="text" class="form-control" name="code" value="{{ old('code') }}" required autocomplete="code" autofocus> </div> </div> <div class="form-group row"> <label for="name" class="col-md-4 col-form-label text-md-right">名前</label> <div class="col-md-6"> <input id="name" type="text" class="form-control" name="name" value="{{ old('name') }}" required autocomplete="name"> </div> </div> <div class="form-group row"> <label for="password" class="col-md-4 col-form-label text-md-right">カナ名</label> <div class="col-md-6"> <input id="kana" type="text" class="form-control" name="kana" value="{{ old('kana') }}" required autocomplete="kana"> </div> </div> <div class="form-group row mb-0"> <div class="col-md-6 offset-md-4"> <button type="submit" class="btn btn-primary"> 登録 </button> </div> </div> </form> </div> </div> </div> </div> </div> @endsection
レイアウトを整えるのに、BootstrapのCSS定義を使っています。
そのため<div>タグが増えて、若干長めのソースに見えています。
まあ・・しゃあないですね。
実行イメージ
MySQLを起動します。
プロジェクトフォルダをカレントにして、ビルトインサーバーを動かします。
php artisan serve
で。
にアクセスすると、入力画面が表示されます。
適当に入力します。
登録ボタンを押すと。
こんな感じで、数件登録してみました。
DBの登録状況をみてみると・・
ちゃんとinsertされてます。
今回はこんなところでOKじゃないですかね。
次回以降は、これをベースに少しずつ拡張して、機能を覚えていこうと思います。
ではでは。