タイトル: クイックスタート & チュートリアル(中級者向け)
当記事ではLaravelを使用してWebアプリケーションを作成します。
アプリの作成を通してLaravelの以下の項目を説明します。
・データベース
・Eloqunetモデル
・Eloquentリレーション
・ルーティング
・認証
・コントローラー
・ビュー
・バリデーション
・依存注入
・認可
・Bladeテンプレート
※Laravelの導入が済んでいない場合はこちらを参照。
※XAMPPを使用するのでXAMPPの導入が済んでいない場合はこちらを参照。
インストール
「quickstart」という名前のプロジェクトを新規に作成しましょう。
composer create-project laravel/laravel quickstart --prefer-dist |
データベースの準備
■データベースの作成
XAMPPのControl PanelからphpMyAdminを起動しましょう。
phpMyAdminを開いたら「New」ボタンを押して「test」データーベースを作成しましょう。
■ユーザーの作成
「test」データベースを選択した状態で以下のコマンドを実行してデーターベースユーザーを作成しましょう。
GRANT ALL PRIVILEGES ON test.* TO testUser@localhost IDENTIFIED BY 'testPass'; |
■データーベースの接続設定
Laravel内にあるデータベースの接続設定を変更します。
ルートフォルダ直下の「.env」ファイルの以下の部分を変更しましょう。
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=test DB_USERNAME=testUser DB_PASSWORD=testPass |
■テーブルの作成
データベースのマイグレーション機能を用いてテーブルを作成してみましょう。
今回は「user」と「task」テーブルを使用します。
「user」はLaravelインストール時にデフォルトで定義されています。
「task」テーブルを作成しましょう。
ルートディレクトリに移動して以下のコマンドを実行します。
php artisan make:migration create_tasks_table --create=tasks |
「database\migrations」配下にファイルが新規作成されたことを確認できます。
ファイルの中身を見てみましょう。
public function up() { Schema::create('tasks', function (Blueprint $table) { $table->increments('id'); $table->timestamps(); }); } |
これはデフォルトの定義です。
このファイルを編集し、タスクの名前を保存するstringカラムと、tasksとusersテーブルを結びつけるuser_idカラムを追加しましょう。
以下の様にテーブル定義を変えます。
public function up() { Schema::create('tasks', function (Blueprint $table) { $table->increments('id'); $table->timestamps(); }); } |
tasksテーブルにカラムを追加してみましょう。
以下の例ではstring型のnameというカラムを追加しています。
public function up() { Schema::create('tasks', function (Blueprint $table) { $table->increments('id'); $table->integer('user_id')->unsigned()->index(); $table->string('name'); $table->timestamps(); }); } |
ファイルを書き換えただけではテーブルの構造は変化しません。
ファイルを保存して以下のコマンドを実行しましょう。
php artisan migrate |
※デフォルトのテーブルでkey関連のエラーが発生した場合は「database\migrations」配下にある該当テーブルファイルの「->unique()」や「->index()」の記述を削除しましょう。
Eloqunetモデル
次にDBからデータの保存、取得をする際に利用するEloqunetというORMを作成しましょう。
※「ORM(O/R Mapping)」とは
O/Rは「Object/Relational」の略で、オブジェクトとリレーショナルデータベースのデータの間をマッピングする技術のこと。
「user」と「task」のモデルを使用しますが、「user」はデフォルトで作成されています。
以下のコマンドを実行して「Task」というモデルを作成します。
php artisan make:model Task |
モデルとなるクラスは、指定した名前でプロジェクトの「app」フォルダ内に作成されるので確認しましょう。
【Task.php】の中身
<?php
namespace App; use Illuminate\Database\Eloquent\Model; class Task extends Model |
モデルに対して「複数代入」ができるようname属性を登録します。
以下の様に内容を書き変えておきましょう。
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Task extends Model |
Eloqunetリレーション
「User」と「Task」のデータの紐づけを行います。
「User」と「Task」は1対多の関係にします。
まず「User」の定義に以下の内容を追記します。(※黄色い部分)
<?php namespace App; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable /** /** |
まず「Task」の定義を以下のように書き換えます。
<?php namespace App; use App\User; class Task extends Model /** |
ルーティング
ルーティングとはコントローラとURLを対応させる仕組みです。
※コントローラーについては後述。
「app/Http/routes.php」のファイルにルーティングの定義をします。
※Laravel5.3以降は、「routes」フォルダ配下にある「web.php」がそれに該当します。
「app/Http/routes.php」もしくは「routes/web.php」の内容を確認してみましょう。
<?php
Route::get('/', function () { |
「/」にアクセスすると「welcome」ビューを表示するという意味です。
認証
Laravelでログイン認証システムを実装しましょう。
認証には「app/Http/Controllers/Auth/AuthController」を使用します。
※Laravel5.?以降は、「app/Http/Controllers/Auth/」フォルダ配下にあるファイル群がそれに該当します。
ユーザー登録/ログイン画面はコマンドで一括で作成することが出来ます。
以下のコマンドを実行しましょう。
php artisan make:auth |
「app/Http/routes.php」もしくは「routes/web.php」の内容を確認してみましょう。
下記の内容が追記されています。
※追記されていない、もしくは違う記述の場合は対応するLaravelのバージョンのドキュメントを参照してください。
Auth::routes();
Route::get('/home', 'HomeController@index')->name('home'); |
認証画面を開いてみましょう。
ルートディレクトリ上で以下のコマンドを実行してサーバーを起動します。
php artisan serve |
「http://localhost:8000/login」にアクセスしてみましょう。
認証画面が開かれます。
コントローラー
「app/Http/Controllers」に新しいコントローラーを作成しましょう。
今回作成するのはタスクコントローラーです。
以下のコマンドを実行します。
php artisan make:controller TaskController |
「TaskController」の中身は空です。
「app/Http/routes.php」もしくは「routes/web.php」に「TaskController」を実行する記述をします。
とりあえず以下の実装をしておきましょう。
Route::get('/tasks', 'TaskController@index'); Route::post('/task', 'TaskController@store'); Route::delete('/task/{task}', 'TaskController@destroy'); |
ルートの認証化
タスク関連のページはログインしていなければアクセス出来ない仕様にします。
「app/Http/Controllers/TaskController」に以下の記述をしましょう。
<?php namespace App\Http\Controllers; use App\Http\Requests; class TaskController extends Controller
|
「middleware('auth')」とすることで要認証と出来ます。
ビューについて
Laravelのビューは「resources/views」に保管します。
例えば「return view('welcome');」と定義したのは「resources/views/welcome.blade.php」を表示するということです。
↓が今回作るビューの完成形です。(※今回CSSはいじらないのであくまでイメージです)
レイアウトの作成
LaravelはBladeテンプレートを使用することでページ間の特徴を共有できます。
今回はレイアウトを「resources/views/layouts/app.blade.php」として定義します。
「.blade.php」拡張子とすることでBladeテンプレートエンジンをするとフレームワークに指示を出します。
「resources/views/layouts/app.blade.php」を確認しましょう。
<!DOCTYPE html> |
「@yield('content')」は「contentセクション」を持つ子ビューを挿入するという意味です。
子ビューの作成
それでは「contentセクション」を持つ子ビューを作成しましょう。
※先ほど作ったのはレイアウトで今回はビューです。
「TaskController」のindexメソッドに対応する「resources/views/tasks/index.blade.php」を定義します。
※CSSは省きます
<!-- resources/views/tasks/index.blade.php --> @extends('layouts.app') @section('content') <!-- Bootstrapの定形コード… --> <div class="panel-body"> <!-- 新タスクフォーム --> <!-- タスク名 --> <div class="col-sm-6"> <!-- タスク追加ボタン --> <!-- TODO: Current Tasks --> |
「@extends('layouts.app')」は先ほど作成した「resources/views/layouts/app.blade.php」レイアウトを使用するという意味です。
「@section('content')」から「@endsection」の内容を、先ほどのレイアウトで定義した「@yield('content')」の部分に挿入します。
「@include('common.errors')」は「resources/views/common/errors.blade.php」のテンプレートを使用するという意味です。
(このテンプレートは後ほど作成します。)
「TaskController」に以下のindexメソッドを定義してこのビューを返すようにしましょう。
/** |
バリデーション(入力値チェック)
子ビューの入力値をチェックする処理を実装します。
値の追加はPOSTメソッドで行います。新たに「TaskController@store」を追加します。
このフォームでは、nameフィールドの入力が必須で、内容が255文字以下であることを確認します。
バリデーションに失敗したら、ユーザを「/tasks」のURLへリダイレクトし、同時に以前の入力とエラーをsessionへフラッシュデータとして保存するようにします。
/** // タスクの作成処理… |
これは「name」フィールドの入力値に何かしらの値が入力されていて、かつ255字以内であることをチェックしています。
バリデーションが失敗した場合のリダイレクト処理を記載していないことに気づくでしょう。
自動的に直前のページにリダイレクトする仕組みです。
かつ、sessionへフラッシュデータの保存も自動で行われます。
エラーの表示
次は$errors変数は子ビューの「@include('common.errors')」の部分で表示させるようにしましょう。
「resources/views/common/errors.blade.php」を作成して以下の実装をしましょう。
<!-- resources/views/common/errors.blade.php -->
@if (count($errors) > 0) <br><br> <ul> |
データベースへの値の追加
次は値をデータベースに追加する処理を記載します。「TaskController」に以下のstoreメソッドの続きを記載します。
/** $request->user()->tasks()->create([ return redirect('/tasks'); |
今回使用するcreateメソッドは属性の配列を受け取り、データベースへ保存する前に、関連するモデルの外部キー値を自動的に設定します。
createメソッドは、$request->user()でアクセスできる現在の認証済みユーザのIDを指定したタスクのuser_idプロパティへ自動的に設定します。
データベースから値を取得
保存した値を取得する処理を実装します。
「TaskController@index」の処理を以下の様に変更しましょう。
/** return view('tasks.index', [ |
これでも動作しますが、全データアクセスに対して利用するTaskRepositoryをLaravelの依存注入能力を使い、「TaskController」に注入することにしましょう。
依存注入
「Task」モデルとの全アクセスロジックを持つ、「TaskRepository」を定義します。
「app/Repositories」ディレクトリを作成し、「TaskRepository」ファイルを作成しましょう。
以下の様に実装しましょう。
<?php namespace App\Repositories; use App\User; class TaskRepository |
リポジトリー注入
実際にリポジトリーを注入してみましょう。
「TaskController 」を以下の内容に書き換えます。
<?php namespace App\Http\Controllers; use App\Task; class TaskController extends Controller
$this->tasks = $tasks; /** $request->user()->tasks()->create([ return redirect('/tasks'); |
ビューに値を表示
データベースから取得した値をビューに表示しましょう。
「resources/views/tasks/index.blade.php」を以下の内容に書き換えましょう。
(※黄色が追加した部分です)
<!-- resources/views/tasks/index.blade.php --> @extends('layouts.app') @section('content') <!-- Bootstrapの定形コード… --> <div class="panel-body"> <!-- 新タスクフォーム --> <!-- タスク名 --> <div class="col-sm-6"> <!-- タスク追加ボタン --> <!-- 現在のタスク --> <div class="panel-body"> <!-- テーブルヘッダ --> <!-- テーブル本体 --> <td> |
「$tasks」が0件でない場合、foreach文で回して一件ずつ「name」を表示します。
データベースの値の削除
先ほど追加したコードの「<!-- TODO: 削除ボタン -->」の部分に、以下のコードを追加して削除ボタンを追加しましょう。
<form action="{{ url('task/'.$task->id) }}" method="POST"> <button type="submit" id="delete-task-{{ $task->id }}" class="btn btn-danger"> |
削除ボタンをクリックすると、DELETEでリクエストします。
formタグ内ではPOSTを使用していますが、これはHTMLのフォームが許容しているのがGETとPOSTのみなので、とりあえず記載しているだけです。
実際はDELETEのリクエストとなります。
ボタンがクリックされると、DELETE 「/task」リクエストがアプリケーションに送信され、TaskController@destroyメソッドが起動されます。
認可
実装予定のdestroyメソッドを見てみましょう。
Route::delete('/task/{task}', 'TaskController@destroy');
public function destroy(Request $request, Task $task) { // } |
ルート中の{task}変数が、コントローラメソッド中の$task変数定義と一致するため、
Laravelの暗黙的モデル結合により、対応するタスクモデルのインスタンスが自動的に依存注入されます。
このままだと「/tasks/{task}」のURLへランダムなタスクIDを渡すことで、悪意のあるリクエストを仕込むことが可能です。
Taskインスタンスが実際に認証済みユーザが所有していることを確認するため、Laravelの認可機能を使う必要があります。
ポリシー
認証ロジックを単純で小さなクラスへ系統立てるため、Laravelは「ポリシー」を使っています。
通常、各ポリシーはモデルに対応しています。
では、コマンドを使用して「TaskPolicy」を作成しましょう。「app/Policies/TaskPolicy.php」として生成されます。
php artisan make:policy TaskPolicy |
次にdestroyメソッドをポリシーへ追加します。
このメソッドはUserインスタンスとTaskインスタンスを引数に取ります。
このメソッドはシンプルにユーザのIDがタスクのuser_idと一致するかを調べるだけです。
実際、全ポリシーメソッドはtrueかfalseを返す必要があります。
<?php namespace App\Policies; use App\User; class TaskPolicy /** |
最後にTaskモデルをTaskPolicyと関連付ける必要があります。
「app/Providers/AuthServiceProvider.php」ファイルの$policiesプロパティに一行加えることで可能です。
これによりTaskインスタンスに対するアクションを認可したい場合に毎回使われるべきポリシーをLaravelに指定しています。
/** |
アクションの認可
これでポリシーが書き上がりましたので、destroyメソッドで使用しましょう。
Laravelの全コントローラーから、AuthorizesRequestトレイトにより提供されているauthorizeメソッドを呼び出せます。
「TaskController」に以下の内容を追記しましょう。
/** * // タスクの削除処理... |
データベースの値削除
「TaskController」のdestroyメソッドに以下の内容を追記しましょう。
/** $task->delete(); return redirect('/tasks'); |
これで今回のWebアプリ作成は完了となります。
お疲れさまでした。