今日はウェブアプリをつくりながらモデルのつかいかたを学んでいきましょう!
モデルをつかうとなにがいいんだわん?
データベースの処理を PHP クラスとしてまとめて直感的にデータベースを扱えるところですかね!
SQL 文でデータベースの処理をかかなくてもいいってことかにゃん?
そうですね!データベースの扱いを PHP 構文やファザードを使ってすっきり記述できます!ではやっていきましょう。
こんにちは!あっきーです。
Eloquent ORM を使ったデータベースにまつわる操作の方法をまとめます。実際に Web アプリをつくりながらやっていきますので Laravel の基本操作も学べます。
今回はお気に入りの漫画を紹介ページのようなアプリをつくっていきましょう。
・モデルでのデータベースのリレーション設定
・マイグレーション、シーディングでのデータベースの初期設定
・コントローラー、ビューテンプレートの基本的使い方
・フォームリクエストを使用したバリデーション設定
完成イメージ
・表示ページ
・登録ページ
・バリデーション
マイグレーションで DB をつくる
初期のセットアップまでは下記の記事の「データベースを作成する」を参考にしてください。
僕の場合は「test」という名前でデータベースを作成しました。
続いてデータベース内にテーブルを作成します。以下3つのテーブルをコマンドで作成します。
・コミックステーブル
ターミナル
1 |
$ php artisan make:migration create_comics_table |
・作者テーブル
ターミナル
1 |
$ php artisan make:migration create_authors_table |
・連載誌テーブル
ターミナル
1 |
$ php artisan make:migration create_magazines_table |
Laravel の規約でテーブル名は複数形にするのじゃ。
テーブル情報の記述
続いてマイグレーションで生成したファイルにテーブルのカラムの情報を記述していきます。
なお省略して「upメソッド」のみの記述ですが、その他の記述はファイル生成時のデフォルトのままで大丈夫です。
database/migrations/2019_02_20_144834_create_comics_table.php
1 2 3 4 5 6 7 8 9 10 11 |
public function up() { Schema::create('comics', function (Blueprint $table) { $table->increments('id'); $table->string('comic_name'); $table->integer('magazine_id'); $table->integer('author_id'); $table->text('description')->nullable(); $table->timestamps(); }); } |
database/migrations/2019_02_20_144932_create_authors_table.php
1 2 3 4 5 6 7 |
{ Schema::create('authors', function (Blueprint $table) { $table->increments('id'); $table->string('author'); $table->timestamps(); }); } |
database/migrations/2019_02_20_145117_create_magazines_table.php
1 2 3 4 5 6 7 8 |
public function up() { Schema::create('magazines', function (Blueprint $table) { $table->increments('id'); $table->string('magazine'); $table->timestamps(); }); } |
マイグレーション実行
ターミナル
1 |
$ php artisan migrate |
シーディング機能でダミーレコードを用意する
まず、以下2つのシーダーファイルをコマンドで作成します。
・連載誌テーブルのシーダーファイル
ターミナル
1 |
$ php artisan make:seeder magazinesTableSeeder |
・作者テーブルのシーダーファイル
ターミナル
1 |
$ php artisan make:seeder authorsTableSeeder |
シードの作成
各ファイルにテーブルのシードを作成する処理を記述していきます。
database/seeds/magazinesTableSeeder.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<?php use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; class magazinesTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { $param = [ 'magazine' => '週刊少年ジャンプ', ]; DB::table('magazines')->insert($param); $param = [ 'magazine' => '週刊ヤングジャンプ', ]; DB::table('magazines')->insert($param); $param = [ 'magazine' => 'モーニング', ]; DB::table('magazines')->insert($param); $param = [ 'magazine' => '週刊少年マガジン', ]; DB::table('magazines')->insert($param); } } |
database/seeds/authorsTableSeeder.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<?php use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; class authorsTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { $param = [ 'author' => '尾田栄一郎', ]; DB::table('authors')->insert($param); $param = [ 'author' => '富樫義博', ]; DB::table('authors')->insert($param); $param = [ 'author' => '井上雄彦', ]; DB::table('authors')->insert($param); $param = [ 'author' => '流石景', ]; DB::table('authors')->insert($param); $param = [ 'author' => 'うえやまとち', ]; DB::table('authors')->insert($param); } } |
シーダーファイルの登録
作成したファイルがシーディング時に実行されるよう「database」フォルダ内の「DatabaseSeeder.php」に登録処理を記述します。
Database\DatabaseSeeder.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?php use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder { /** * Seed the application's database. * * @return void */ public function run() { $this->call([ magazinesTableSeeder::class, authorsTableSeeder::class, ]); } } |
シーディングの実行
・コンポーザーからオートローダを再生成
ターミナル
1 |
$ composer dump-autoload |
・シーディングコマンド
ターミナル
1 |
$ php artisan db:seed |
無事作成できたかコマンドから確認していきましょう。下記コマンドを1つずつ実行してください。
ターミナル
1 2 3 4 |
$ mysql -u root -p mysql> use test; mysql> select * from magazines; mysql> select * from authors; |
・select * from magazines
・select * from authors
マイグレーション・シーディングの再実行
うっかりスペルミスなどでカラムの情報を間違えて記述してしまった場合は各ファイルの記述を変更した上で下記のコマンドを実行することでマイグレーションとシーディングを再実行することができます。
ターミナル
1 |
$ php artisan migrate:refresh |
ターミナル
1 |
$ php artisan migrate:refresh --seed |
マイグレーションからシーディングまでの再実行ですのでシーディング以外でまだデータの登録を行っていない初期段階での実行では有効ですが、すでにデータを複数登録していた場合には適していないので使い分けするといいと思います。
データベースの表示と登録処理
データベースの初期設定は完了しましたのでブラウザでの表示処理を行っていきます。
なお、完成イメージからもわかるように今回はコミックテーブルを表示していますがコミックテーブルにはまだデータが入っていないたブラウザでの表示はされません。
そのため一緒にコミックテーブルにデータを登録していく処理も行います。
のちほど登録処理から追加したデータベースのリレーションを行うために最初は空の状態にしています。
モデルの作成
以下3つのファイルをコマンドより作成します。
・コミックステーブルのモデル
ターミナル
1 |
$ php artisan make:model Comic |
・連載誌テーブルのモデル
ターミナル
1 |
$ php artisan make:model Magazine |
・作者テーブルのモデル
ターミナル
1 |
$ php artisan make:model Author |
テーブル名を複数形にするのに対してモデルは単数形を使うのじゃ
コマンドで生成された各ファイルに処理を記述していきます。
・app/Comic.php
1 2 3 4 5 6 7 8 9 10 11 |
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Comic extends Model { protected $table = 'comics'; protected $guarded = array('id'); } |
app/Magazine.php
1 2 3 4 5 6 7 8 9 10 11 |
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Magazine extends Model { protected $table = 'magazines'; protected $guarded = array('id'); } |
app/Author.php
1 2 3 4 5 6 7 8 9 10 11 |
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Author extends Model { protected $table = 'authors'; protected $guarded = array('id'); } |
共通の処理ですので簡単に説明をします。
1 |
protected $table = 'テーブル名'; |
モデルと関連しているテーブルを指定します。これでモデルからデータベースを扱えるようにします。
1 |
protected $guarded = array('id'); |
データベースでの id は基本は主キーでオートインクリメントでかつ null でないと想定されます。そのため id を保護することにより追加などの処理のさいにデータが null であってもエラーにならず動作させるための記述です。
バリデーションの設定
コントローラーとビューテンプレートのファイルを作成する前に登録処理時のバリデーションファイルをフォームリクエストから作成しておきましょう。
今回の登録処理時に必須項目なデータはコミック名を記入するテキストボックスです。セレクトボックスは初期値でデータベースの最初のカラムを表示するのでとりあえず大丈夫です。
コマンドから以下のファイルを作成しましょう。
ターミナル
1 |
$ php artisan make:request ComicRequest |
作成したファイルにバリデーションの処理を記述していきます。
app/Http/Requests/ComicRequest.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; class ComicRequest extends FormRequest { /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() { return true; } /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { return [ 'comic_name' => 'required', ]; } public function messages() { return [ 'comic_name.required' => ' ※コミック名は必須項目です', ]; } } |
コントローラーの作成
下記コマンドよりコントローラーを作成します。
ターミナル
1 |
$ php artisan make:controller ComicController |
作成されたファイルに処理を記述していきます。
app/HTTP/Controllers/ComicController.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; /* 各モデルを有効にする */ use App\Magazine; use App\Author; use App\Comic; /* バリデーションを有効にする */ use App\Http\Requests\ComicRequest; class ComicController extends Controller { /* 表示ページ */ public function index(Request $request) { /* Comicモデルからデータベースを取得 */ $items = Comic::all(); return view('comic.index', ['items' => $items]); } /* 追加ページ */ public function add(Request $request) { $items = [ 'magazines' => Magazine::all(), 'authors' => Author::all(), ]; return view('comic.add', $items); } /* 追加処理 */ public function create(ComicRequest $request) { $comic = new Comic; $form = $request->all(); unset($form['_token']); $comic->fill($form)->save(); return redirect('/comic'); } } |
ビューテンプレートの作成
以下3つのファイルを作成します。フォルダも作成してディレクトリを分けましょう。
・ベースレイアウト
resources/views/layouts/comicapp.blade.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<html> <head> <title>@yield('title')</title> <style> body {font-size:16pt; color:#999; margin: 5px; } h1 { font-size:50pt; text-align:right; color:#f6f6f6; margin:-20px 0px -30px 0px; letter-spacing:-4pt; } ul { font-size:12pt; } hr { margin: 25px 100px; border-top: 1px dashed #ddd; } .menutitle {font-size:14pt; font-weight:bold; margin: 0px; } .content {margin:10px; } .footer { text-align:right; font-size:10pt; margin:10px; border-bottom:solid 1px #ccc; color:#ccc; } th {background-color:#999; color:fff; padding:5px 10px; } td {border: solid 1px #aaa; color:#999; padding:5px 10px; } </style> </head> <body> <h1>@yield('title')</h1> @section('menubar') <ul> <p class="menutitle">※メニュー</p> <li>@show</li> </ul> <hr size="1"> <div class="content"> @yield('content') </div> <div class="footer"> @yield('footer') </div> </body> </html> |
・表示ページ
resources/views/comic/index.blade.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
@extends('layouts.comicapp') @section('title', 'comic.Index') @section('menubar') @parent インデックスページ @endsection @section('content') <!-- 登録ページに遷移 --> {!! Form::open(['url' => '/comic/add', 'method' => 'get']) !!} {!! Form::submit('登録', ['class' => 'form-control', 'id' => '']) !!} {!! Form::close() !!} <!-- データベースの表示 --> <table> <tr> <th>コミック</th> <th>作者</th> <th>連載誌</th> <th>説明</th> </tr> @foreach($items as $item) <tr> <td>{{$item->comic_name}}</td> <td>{{$item->magazine_id}}</td> <td>{{$item->author_id}}</td> <td>{{$item->description}}</td> </tr> @endforeach </table> @endsection @section('footer') copyright 2017 tuyano. @endsectio |
・登録ページ
resources/views/comic/add.blade.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
@extends('layouts.comicapp') @section('title', 'comic.add') @section('menubar') @parent 登録ページ @endsection @section('content') {!! Form::open(['url' => '/comic/add', 'method' => 'post']) !!} <!-- バリデーション --> @if($errors->has('comic_name')) <p>{{$errors->first('comic_name')}}</p> @endif {{Form::label('comic', 'コミック名')}} {{Form::text('comic_name', old('comic_name'))}} {{Form::label('authors', '作者')}} <select name="author_id"> @foreach($authors as $author) <option value={{$author->id}} @if(old('author_id')==$author->id) selected @endif> {{$author->author}} </option> @endforeach </select> {{Form::label('magazines', '連載誌')}} <select name="magazine_id"> @foreach($magazines as $magazine) <option value={{$magazine->id}} @if(old('magazine_id')==$magazine->id) selected @endif> {{$magazine->magazine}} </option> @endforeach </select> {{Form::label('comic', '説明')}} {{Form::text('description', old('description'))}} {!! Form::submit('登録') !!} {!! Form::close() !!} @endsection @section('footer') copyright 2017 tuyano. @endsection |
Laravel Collective でフォームの作成を行っていますので、基本的な使い方は以下の記事から確認できますので参照してください。
ルーティングの設定
ルーティングを設定します。ルートの記述以外のところは省略しています。
routes/web.php
1 2 3 |
Route::get('comic', 'ComicController@index'); Route::get('comic/add', 'ComicController@add'); Route::post('comic/add', 'ComicController@create'); |
表示確認
これで追加ページで追加したデータが表示ページに表示されます。
登録ページから適当にデータをいくつか登録してみてください。
・https://ドメイン/comic
しかし、作者と連載誌は id で追加しているため数字しか表示されていません。外部キーの id をもとに作者テーブルと連載誌テーブルを紐づけるリレーションの設定を行っていきましょう。
リレーションの設定
今回は従テーブルの「コミックテーブル」から関連する主テーブルである「作者テーブル」と「連載誌テーブル」のレコードを取得する必要があります。
テーブルの主従関係は簡単に言えば外部キーを持っている方が従テーブルです。今回でいえば「magazine_id」と「author_id」です。
従テーブルである「Comicモデル」を以下のように編集します。
app/Comic.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Comic extends Model { protected $table = 'comics'; protected $guarded = array('id'); /* ここから追加 */ public function magazine() { return $this->belongsTo('App\Magazine'); } public function author() { return $this->belongsTo('App\Author'); } } |
表示ページも編集します。@section('content') 内の@foreach~を以下のように編集します。
resources/views/comic/index.blade.php
1 2 3 4 5 6 7 8 |
@foreach($items as $item) <tr> <td>{{$item->comic_name}}</td> <td>{{$item->magazine->magazine}}</td> <td>{{$item->author->author}}</td> <td>{{$item->description}}</td> </tr> @endforeach |
これでComicモデル内のメソッドを使って関連する従テーブルのカラムのデータを参照できるようになりました。
最後にブラウザで表示確認してみましょう。
・https://ドメイン/comic
完成です。お疲れさまでした!
さいごに
最後まで読んでいただきありがとうございます!
Eloquent ORM についての記事ですがアプリをつくりながら Laravel の基本操作を全体的に網羅してみたつもりでしたがいかがでしたしょうか。
今後 Laravel を始める人やなにか作ってみたいひとの参考になれば幸いです。
この記事を気に入っていただけましたらTwitter でもプログラミングのことについてツイートしていますので是非ご一緒にフォローの方もお願いします!
それでは次の記事でまたお会いしましょう!