初めてのLaravel 5.1 : (16) Formの作成

今回はフォームを作成して、記事をデータベースに登録してみます。

laravelcollective/html パッケージの追加

Laravel のViewでFormを記述するには直接HTMLを記述する方法とヘルパー関数を使う方法があります。この記事では、laravelcollective/html パッケージをインストールして、ヘルパー関数を使用します。このパッケージは、Laravel 4では標準で組み込まれていたのですが、Laravel 5 からは別パッケージになり、ユーザーコミュニティーによってメンテナンスされるようになりました。
http://laravelcollective.com/

同様のパッケージに、illuminate/html があるのですが、こちらはメンテナンスが終了していますので、ご注意ください。

まずは、composer でインストール

composer require laravelcollective/html

config/app.php を編集して、 laravelcollective/html をLaravelに組込みます。

<?php
// config/app.php

return [
    // サービス・プロバイダーの登録
    'providers' => [

        // ...

        Collective\Html\HtmlServiceProvider::class,  // 追加
    ],

    // ファサードの登録
    'aliases' => [

        // ...

        'Form' => Collective\Html\FormFacade::class,  // 追加
        'Html' => Collective\Html\HtmlFacade::class,  // 追加
    ],
];

この辺の設定や仕組みは Laravel ではサービスプロバイダーとか、ファサードと言うのですが、ここでは解説は避けます。laravelcollective/html パッケージを追加するには config/app.php に上記の設定の追加が必要ということだけ、覚えて先に進みたいと思います。どうしても、気になる方はググってみて下さい。


新規記事入力フォームの表示

Routing

ルートを追加します。

<?php
// app/Http/routes.php

// ...
Route::get('articles', 'ArticlesController@index');

// 追加
Route::get('articles/create', 'ArticlesController@create'); // ①

Route::get('articles/{id}', 'ArticlesController@show'); // (a)
// ...

ArticlesController@createへのルートを追加しました。
注意点として、上記の①は (a) より先に追加します。そうしないと、”articles/create” にGETリクエストが来た時に、”articles/{id}”の方が先にマッチしてしまい、ArticlesController@show が実行されてしまいます。ルートは記述した順に、上からマッチングされます。

Controller

ArticlesController.php に createメソッドを実装します。
中身はビューを表示しているだけです。

<?php namespace AppHttpControllers;
// app/Http/Controllers/ArticlesController.php

// ...

class ArticlesController extends Controller
{

    // ...

    public function create()
    {
        return view('articles.create');
    }
}

View

create.blade.php を新規に作成します。

// resources/views/articles/create.blade.php

@extends('layout')

@section('content')
    <h1>Write a New Article</h1>

    <hr/>

    {!! Form::open() !!}
        <div class="form-group">
            {!! Form::label('title', 'Title:') !!}
            {!! Form::text('title', null, ['class' => 'form-control']) !!}
        </div>
        <div class="form-group">
            {!! Form::label('body', 'Body:') !!}
            {!! Form::textarea('body', null, ['class' => 'form-control']) !!}
        </div>
        <div class="form-group">
            {!! Form::label('published_at', 'Publish On:') !!}
            {!! Form::input('date', 'published_at', date('Y-m-d'), ['class' => 'form-control']) !!}
        </div>    
        <div class="form-group">
            {!! Form::submit('Add Article', ['class' => 'btn btn-primary form-control']) !!}
        </div>
    {!! Form::close() !!}
@endsection

新しい、表記が出てきました。

1つ目は {!! XXXX !!} という表記です。これは blade テンプレートの表記で、PHPで評価した結果を表示する時に使用します。以前に同じような表記で、{{ XXXX }}を使いましたが、{!! XXXX !!} の方はエスケープ処理を行われず、{{ XXXX }} の方はエスケープ処理を行うという違いがあります。今回はFormのHTMLをPHPで生成しているので、エスケープ処理を行わないように、{!! XXXX !!} を使っています。

2つ目は Form::XXXX という表記です。この部分で最初に追加インストールした laravelcollective/html パッケージ使用しています。一見するとFormクラスのstaticメソッドをコールしているように見えますが、実は Collective\Html\FormBuilder クラスのインスタンスメソッドをコールしています。ここではFormクラスというalias(別名)を使って、簡素に’Collective\Html\FormBuilder’のインスタンスにアクセスしているという理解でよいかと思います。この仕組みをファサードといいます。ここではファサードの詳細は割愛して進めます。

  • Form::open() formの開始タグを生成
  • Form::close() formの終了タグを生成
  • Form::label() labelタグを生成
  • Form::input() inputタグを生成
  • Form::text() input[type=text]タグを生成
  • Form::textarea() textareaタグを生成
  • Form::submit() input[type=submit]タグを生成

詳細は下記のAPIリファレンスで確認することができます。
http://laravelcollective.com/docs/5.1/html

それから、class=”xxxx”の指定は、前回導入したBootstrap3の classを指定しています。これを指定するとフォームの表示がかっこ良くなります。

ここで、生成されたFormのHTMLを確認してみます。
http://localhost:8000/articles/create にアクセスし、ブラウザの機能でページのソースを表示します。

<form method="POST" action="http://localhost:8000/articles/create" accept-charset="UTF-8">
    <input name="_token" type="hidden" value="pEUyvKqFqjlcEfh2lvIkGEeI3rWAAwdbgo3XicvW">

    <div class="form-group">
        <label for="title">Title:</label>
        <input class="form-control" name="title" type="text" id="title">
    </div>

    <div class="form-group">
        <label for="body">Body:</label>
        <textarea class="form-control" name="body" cols="50" rows="10" id="body"></textarea>
    </div>

    <div class="form-group">
        <label for="published_at">Publish On:</label>
        <input class="form-control" name="published_at" type="date" value="2015-03-04" id="published_at">
    </div>

    <div class="form-group">
        <input class="btn btn-primary form-control" type="submit" value="Add Article">
    </div>
</form>

methodにはPOSTが設定されました。
actionにはカレントURLが設定されています。これは後で変更します。
<input name="_token" type="hidden"… が自動的に挿入されました。これはCSRF対策の為に自動で挿入されるようになっています。


新規記事の保存

Formが Submit された時の、DBへの保存処理を実装します。

Routing

ルートを追加します。

<?php
// app/Http/routes.php

// ...
Route::get('articles', 'ArticlesController@index');
Route::get('articles/create', 'ArticlesController@create');
Route::get('articles/{id}', 'ArticlesController@show');
// 追加
Route::post('articles', 'ArticlesController@store');

// ...

ArticlesController@storeへのルートを追加しました。
get ではなくpost を追加しています。

今まで、言われるがままに使っていた Route::XXX ですが、実はこれもファサードです。実態は Illuminate\Routing\Router です。Laravel 標準搭載のファサードなので、はじめから config/app.php に定義されています。

Controller

ArticlesController.php に storeメソッドを実装します。

<?php namespace AppHttpControllers;

use AppArticle;
use App\Http\ControllersController;

class ArticlesController extends Controller {

	// ...

	public function create() {
		return view('articles.create');
	}

	public function store() {
		// ①フォームの入力値を取得
		$inputs = \Request::all();

		// ②マスアサインメントを使って、記事をDBに作成
		Article::create($inputs);

		// ③記事一覧へリダイレクト
		return redirect('articles');
	}
}

① \Request::all() でフォームの入力値を全て取得しています。
このRequest クラスもファサードで、実態は Illuminate/Http/Request です。
コントローラの名前空間でファサードクラスを使うには、グローバルクラスとして指定する必要があるので、クラス名の前に \ (バックスラッシュ)を付けるのをお忘れなく。
Requestの詳細は公式サイトのドキュメントを参照ください。

http://laravel.com/docs/5.1/requests
http://laravel.com/api/5.1/Illuminate/Http/Request.html

②以前にやったマスアサインメント機能を使って、Articlesテーブルにデータを作成しています。Article モデルで fillable変数の設定をお忘れなく。

③いままでのコントローラメソッドでは、view()メソッドを使って、ビューを表示していましたが、ここでは redirect()を使って、記事一覧のURLへリダイレクトさせています。

View

先ほど作成した、create.blade.php を修正します。

// resources/views/articles/create.blade.php

// ...

{!! Form::open(['url' => 'articles']) !!}

// ...

Form::open() に 引数を渡し、urlを指定しました。

生成されたFormのHTMLを確認してみます。

<form method="POST" action="http://localhost:8000/articles" accept-charset="UTF-8">
  ...

action の url が変更されました。これで submit ボタンを押した時に、ArticlesController@storeが実行されます。


新規作成ボタン

記事一覧に、記事の新規作成ボタンを表示します。

// resources/views/articles/index.blade.php

@extends('layout')

@section('content')
    <h1>Articles</h1>

    <hr/>

    {!! link_to('articles/create', '新規作成', ['class' => 'btn btn-primary']) !!}

    @foreach($articles as $article)
        ...
        ...
    @endforeach
@stop

link_to を使って、’articles/create’へのリンクタグを作成します。bootstrap3のclassを設定して、リンクタグをボタンの様に表示します。


動作確認

  • http://localhost:8000/articles へアクセス
  • 新規作成ボタンをクリック
  • 記事データを入力
  • Add Article ボタン(submit) を押して記事を追加
  • 記事一覧が表示され、追加した記事のタイトルがあれば、成功!

入力チェックは、次回に…


まとめ

以下の事が出来るようになりました

  • laravelcollective/html パッケージの追加
  • Formの作成と表示
  • Request::all() でフォームの入力値取得
  • ファサードの使い方
  • View -> Controller -> Model の流れでの DBへのデータ保存
  • link_toヘルパーを使った、リンクタグの作成

初めてのLaravel 5.1 : (16) Formの作成」への1件のフィードバック

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中