イントロダクション

このクイックスタートガイドではデータベースマイグレーション、Eloqunet ORM、ルーティング、バリデーション、ビュー、Bladeテンプレートといった、Laravelフレームワークの基本を紹介します。Laravelフレームワークや一般的なPHPフレームワークに全く触れたことのない初心者の方にとって、よい入門となるでしょう。既にLaravelや他のフレームワークを使用しているのでしたら、より上級者向けに書かれたもう一つのクイックスタートが適しています。

Laravelの持つ機能の基本的な部分を試せるように、完了したいタスク全てを管理できるシンプルなタスクリストを構築してみます。(典型的なToDoリスト)このプロジェクトの最終の完全なソースコードはGitHubから取得可能です。

インストール

もちろん、最初にLararavelフレームワークを真新しくインストールする必要があります。Homestead仮想マシーンか、フレームワークを実行するために選択したローカルのPHP環境を使用します。ローカル環境が整ったら、Composerを使用しLaravelフレームワークをインストールできます。

composer create-project laravel/laravel quickstart --prefer-dist

このクイックスタートの残りの部分をただ読み進めることもできますが、ソースコードをダウンロードしてローカルマシーンで実行したい場合は、Gitリポジトリーをクローンし、依存パッケージをインストールします。

git clone https://github.com/laravel/quickstart-basic quickstart
cd quickstart
composer install
php artisan migrate

ローカル開発環境の構築についてのドキュメントは、Homesteadインストールのドキュメントを参照してください。

データベースの準備

データベースマイグレーション

最初に全タスクを保持しておくためのデータベーステーブルを定義する、マイグレーション(migration:移行)を使ってみましょう。Laravelのデータベースマイグレーションはスラスラ書ける記述的なPHPコードを用いて、データベーステーブルの構造を定義し修正するための簡単な方法を提供しています。チームメンバーへ個別で用意しているデータベースのコピーへカラムを各自自分で追加するように伝える代わりに、あなたがソース管理にPushしたマイグレーションを実行してもらえます。

では、全タスクを保持するデータベーステーブルを構築しましょう。Artisan CLIは様々なクラスの生成に利用でき、Laravelプロジェクトを構築するためにたくさんタイプする手間を省いてくれます。今回はtasksテーブルのために、新しいデータベースマイグレーションをmake:migrationコマンドを使って生成します。

php artisan make:migration create_tasks_table --create=tasks

マイグレーションはプロジェクトのdatabase/migrationsディレクトリーの中に設置されます。お分かりでしょうが、make:maigrationコマンドは、マイグレーションファイルへ自動増分IDとタイムスタンプの追加を始めに定義しています。このファイルを編集し、タスクの名前を保存するstringカラムを追加しましょう。

<?php

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

class CreateTasksTable extends Migration
{
    /**
     * マイグレーション実行
     *
     * @return void
     */
    public function up()
    {
        Schema::create('tasks', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * マイグレーションの巻き戻し
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('tasks');
    }
}

マイグレーションを実行するには、migrate Artisanコマンドを使います。Homesteadを使っている場合、ホストからは直接データベースへ接続できないため、このコマンドは仮想マシーンで実行してください。

php artisan migrate

このコマンドは全データベーステーブルを生成します。お好きなクライアントを使用し、データベーステーブルを調べてもらえば、マイグレーションで定義したカラムを含んだ新しいtasksテーブルを見つけることができるでしょう。次に、タスクを表すEloquent ORMモデルを定義しましょう!

Eloquentモデル

EloquentはLaravelのデフォルトORM(object-relational mapper)です。Eloquentは明確に定義された「モデル」を用いることで、苦労せずにデータベースへのデータ保存/取得を行わせてくれます。通常各Eloquentモデルは、一つのデータベーステーブルに対応します。

では、作ったばかりのtasksデータベーステーブルに対応するTaskモデルを定義してみましょう。このモデルを生成するために、再度Artisanコマンドを使用します。この場合はmake:modelコマンドを使用します。

php artisan make:model Task

このモデルはアプリケーションのappディレクトリーに設置されます。デフォルトではこのクラスは空です。データベーステーブルはモデルの複数形の名前だと想定されているため、Eloquentモデルがどのテーブルに対応するかを明確に宣言する必要はありません。ですから、この場合Taskモデルはtasksデータベーステーブルと対応していると想定しています。空のモデルは次のようになっています。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Task extends Model
{
    //
}

アプリケーションにルートを追加してから、Eloquentモデルについて更に学びましょう。もちろん、ご自由にEloquentの完全なドキュメントを読んで、更に情報を学んでもかまいません。

Routing

ルートのスタブを定義

次に、アプリケーションにいくつかルートを追加しましょう。ルートはユーザーがページにアクセスするために指定するURLを実行するコントローラーか無名関数を指定するために使用します。Laravelの全ルートはデフォルトで、新しいプロジェクトに必ず含まれているapp/Http/routes.phpファイルの中で定義します。

このアプリケーションでは、最低3つのルートが必要になることがわかっています。全タスクをリスト表示するルート、新しいタスクを追加するルート、既存のタスクを削除するルートです。では、app/Http/routes.phpファイルでこれらのルートを全部スタブ(空の代用コード)で定義しましょう。

<?php

use App\Task;
use Illuminate\Http\Request;

/**
 * 全タスク表示
 */
Route::get('/', function () {
    //
});

/**
 * 新タスク追加
 */
Route::post('/task', function (Request $request) {
    //
});

/**
 * 既存タスク削除
 */
Route::delete('/task/{id}', function ($id) {
    //
});

ビューの表示

次に/ルートを完成させましょう。このルートでは、新しいタスクを追加するフォームを含み、同時に現在の全タスクをリストするHTMLテンプレートを表示しましょう。

Laravelの全HTMLテンプレートはresources/viewsディレクトリーに設置されます。ルートからこれらのテンプレートの一つを返すためにviewヘルパーが使えます。

Route::get('/', function () {
    return view('tasks');
});

もちろん、このビューは実際に定義する必要がありますので、早速とりかかりましょう!

レイアウトとビューの作成

このアプリケーションは新しいタスクを追加するためのフォームを含み、同時に現在のタスクをリストするビューを一つだけ持ちます。ビューを想像するために役立つように、基本的なBootstrapのCSSスタイルを適用した、最終段階のアプリケーションのスナップショットをご覧ください。

アプリケーションイメージ

レイアウト定義

ほとんど全てのアプリケーションでは同じレイアウトをページに渡り共有します。たとえばこのアプリケーションは全ページ(一つ以上のページが存在する場合)で表示する、典型的なトップナビバーがあります。LaravelはBladeテンプレートを使い、こうしたページ間共通のフューチャーを簡単に共有できるようになっています。

前に説明したように、Laravelの全ビューはresources/viewsに設置されます。ですから新しいレイアウトビューもresources/views/layouts/app.blade.phpとして定義します。.blade.php拡張子はビューを表示するときにBladeテンプレートエンジンを使用することをフレームワークへ指示します。もちろんLaravelでも普通のPHPテンプレートが使用できます。しかしBladeなら簡潔できれいなテンプレートを書くための便利なショートカットが利用できます。

app.blade.phpビューは以下のような構成になるでしょう。

// resources/views/layouts/app.blade.php

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Laravel Quickstart - Basic</title>

        <!-- CSSとJavaScript -->
    </head>

    <body>
        <div class="container">
            <nav class="navbar navbar-default">
                <!-- ナビバーの内容 -->
            </nav>
        </div>

        @yield('content')
    </body>
</html>

レイアウトの@yield('content')の部分に注目です。これはレイアウトを拡張する全部の子ページが、自身のコンテンツを親へ注入できる場所を指定するための特別なBladeディレクティブ(指定子)です。次に、このレイアウトを使用しメインコンテンツを表示する、子のビューを定義しましょう。

子ビューの定義

素晴らしい。アプリケーションのレイアウトは完成しました。次に新しいタスクを作成するためのフォームと、存在する全タスクを同時に表示するビューを定義する必要があります。resources/views/tasks.blade.phpを定義しましょう。

Bootstrap CSSの定形コードを省いて、重要な部分に焦点を当てましょう。完全なソースコードはGitHubからダウンロードできることは覚えておいてください。

// resources/views/tasks.blade.php

@extends('layouts.app')

@section('content')

    <!-- Bootstrapの定形コード… -->

    <div class="panel-body">
        <!-- バリデーションエラーの表示 -->
        @include('common.errors')

        <!-- 新タスクフォーム -->
        <form action="/task" method="POST" class="form-horizontal">
            {{ csrf_field() }}

            <!-- タスク名 -->
            <div class="form-group">
                <label for="task" class="col-sm-3 control-label">Task</label>

                <div class="col-sm-6">
                    <input type="text" name="name" id="task-name" class="form-control">
                </div>
            </div>

            <!-- タスク追加ボタン -->
            <div class="form-group">
                <div class="col-sm-offset-3 col-sm-6">
                    <button type="submit" class="btn btn-default">
                        <i class="fa fa-plus"></i> タスク追加
                    </button>
                </div>
            </div>
        </form>
    </div>

    <!-- TODO: 現在のタスク -->
@endsection

簡単な説明

先に進む前に、このテンプレートについて多少説明しましょう。最初に@extendsディレクティブにより、resources/views/layouts/app.blade.phpに定義したレイアウトを使用することをBladeに指示しています。@section('content')から@endsectionの間のコンテンツが、app.blade.phpレイアウトの中の@yield('content')ディレクティブの場所に挿入されます。

これでアプリケーションの基本レイアウトとビューが定義できました。このビューフォームを/ルートで実行することを思い出してください。

Route::get('/', function () {
    return view('tasks');
});

次に、フォーム入力を処理し、データベースに新しいタスクを追加するPOST /taskルートのコードを追加しましょう。

注意: @include('common.errors)ディレクティブはresources/views/common/errors.blade.phpのテンプレートをロードします。このテンプレートは定義していませんが、すぐに行います!

タスク追加

バリデーション

これでビューにフォームが用意できましたので、フォームの入力の正当性を確認し(バリデーション)、新しいタスクを作成するPOST /taskルートへコードを追加しましょう。最初に、入力のバリデーションです。

このフォームでは、nameフィールドの入力が必須で、内容が255文字以下であることを確認しましょう。バリデーションに失敗したら、ユーザーを/のURLへリダイレクトし、同時に以前の入力とエラーをsessionへフラッシュデータとして保存します。

Route::post('/task', function (Request $request) {
    $validator = Validator::make($request->all(), [
        'name' => 'required|max:255',
    ]);

    if ($validator->fails()) {
        return redirect('/')
            ->withInput()
            ->withErrors($validator);
    }

    // タスク作成…
});

$errors変数

一休みして、この例の->withErrors($validator)の部分について解説しましょう。->withErrors($validator)の呼び出しは、指定されたバリデター(validator)インスタンスのエラーをフラッシュデータとしてセッションへ保存し、ビューの中で$errors変数としてアクセスできるようにしてくれます。

フォームのバリデーションエラーを表示するために@include('common.errors')ディレクティブをビューで使用したことを思い出してください。common.errorsによりバリデーションエラーを同じ形式で、全ページに渡り簡単に表示できるようにしています。このビューの内容を定義しましょう。

// resources/views/common/errors.blade.php

@if (count($errors) > 0)
    <!-- フォームのエラーリスト -->
    <div class="alert alert-danger">
        <strong>おや?何かがおかしいようです!</strong>

        <br><br>

        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

注意: $errors変数は全てのLaravelビューの中で参照できます。バリデーションエラーが存在しない場合は、ViewErrorBagの空のインスタンスです。

タスク作成

これで入力のバリデーションは処理できました。新しいタスクを実際に作成するためにルート処理の定義を続けましょう。新しくタスクを生成したら、ユーザーを/のURLへリダイレクトします。タスクを作成するには、新しいEloquentモデルに対しプロパティーを生成し、値を設定した後に、saveメソッドを使用します。

Route::post('/task', function (Request $request) {
    $validator = Validator::make($request->all(), [
        'name' => 'required|max:255',
    ]);

    if ($validator->fails()) {
        return redirect('/')
            ->withInput()
            ->withErrors($validator);
    }

    $task = new Task;
    $task->name = $request->name;
    $task->save();

    return redirect('/');
});

いいですね!これでタスクを作成できるようになりました。次に存在する全タスクをリストするビューを追加していきましょう。

既存タスクの表示

最初に、/ルートを編集し、既存の全タスクをビューに渡しましょう。view関数は第2引数に、ビューで使用するデータを配列で受け付けます。配列のキーはビューの中で変数となります。

Route::get('/', function () {
    $tasks = Task::orderBy('created_at', 'asc')->get();

    return view('tasks', [
        'tasks' => $tasks
    ]);
});

データを渡したら、tasks.blade.phpビューの中でタスクを反復処理し、テーブルとして表示します。とても早く通常のPHPコードにコンパイルできる@foreach Blade構造文で簡単にループが記述できます。

@extends('layouts.app')

@section('content')
    <!-- タスクフォームの作成… -->

    <!-- 現在のタスク -->
    @if (count($tasks) > 0)
        <div class="panel panel-default">
            <div class="panel-heading">
                現在のタスク
            </div>

            <div class="panel-body">
                <table class="table table-striped task-table">

                    <!-- テーブルヘッダー -->
                    <thead>
                        <th>Task</th>
                        <th>&nbsp;</th>
                    </thead>

                    <!-- テーブルボディー -->
                    <tbody>
                        @foreach ($tasks as $task)
                            <tr>
                                <!-- タスク名 -->
                                <td class="table-text">
                                    <div>{{ $task->name }}</div>
                                </td>

                                <td>
                                    <!-- TODO: 削除ボタン -->
                                </td>
                            </tr>
                        @endforeach
                    </tbody>
                </table>
            </div>
        </div>
    @endif
@endsection

タスクアプリケーションはほとんど完成です。しかし、終了した既存タスクを削除する手段がありません。次に実装しましょう。

タスク削除

削除ボタンの追加

コード中、削除ボタンを設置する場所に"TODO"を残してあります。では、tasks.blade.phpビューのタスクリストの各行に、削除ボタンを追加しましょう。小さなボタンひとつのフォームをリストの各タスクごとに作成します。ボタンがクリックされると、DELETE /taskリクエストがアプリケーションに送信されます。

<tr>
    <!-- タスク名 -->
    <td class="table-text">
        <div>{{ $task->name }}</div>
    </td>

    <!-- 削除ボタン -->
    <td>
        <form action="/task/{{ $task->id }}" method="POST">
            {{ csrf_field() }}
            {{ method_field('DELETE') }}

            <button>タスク削除</button>
        </form>
    </td>
</tr>

見せかけのメソッドの説明

削除ボタンフォームのmethodPOSTを使用しているのにかかわらず、定義しているルートはRoute::deleteである点に注目です。HTMLフォームはGETPOST HTTP動詞のみを許しています。そのため、フォームのDELETEリクエストを見せかける手段が必要になります。

フォームの中でmethod_field('DELETE')関数の結果を出力することにより、DELETEリクエストへ見せかけることができます。Laravelはこれを認識し、実際のHTTPリクエストメソッドをオーバーライドします。生成されるフィールドは次の内容です。

<input type="hidden" name="_method" value="DELETE">

タスク削除

最後に指定したタスクを実際に削除するロジックをルートへ追加しましょう。IDでモデルを取得し、モデルが存在しない場合は404例外を投げるEloquentのfindOrFailメソッドが使えます。モデルを取得したら、deleteメソッドを使用すれば、そのレコードを削除できます。レコードが削除されたら、ユーザーを/のURLへリダイレクトします。

Route::delete('/task/{id}', function ($id) {
    Task::findOrFail($id)->delete();

    return redirect('/');
});