前回は記事の新規登録後に表示される記事一覧を修正しました。今回は、記事の編集画面を追加します。編集画面のフォームは新規登録画面のフォームとほぼ同じな為、View の Partial 機能を使って、フォームを共通部品化してみます。
Routing
ルートを追加します。
// routes/web.php Route::get('articles', 'ArticlesController@index'); Route::get('articles/create', 'ArticlesController@create'); Route::get('articles/{id}', 'ArticlesController@show'); Route::post('articles', 'ArticlesController@store'); Route::get('articles/{id}/edit', 'ArticlesController@edit'); // 追加 Route::patch('articles/{id}', 'ArticlesController@update'); // 追加
ArticlesController@edit と ArticlesController@update へのルートを追加しました。update の方は get ではなく patch にしているので、お間違えなく。
Controller
ArticlesController に edit と update メソッドを追加します。
// app/Http/Controllers/ArticlesController.php public function edit($id) { $article = Article::findOrFail($id); return view('articles.edit', compact('article')); } public function update(ArticleRequest $request, $id) { $article = Article::findOrFail($id); $article->update($request->validated()); return redirect(url('articles', [$article->id])); } }
edit は今までに学んで内容で作成でき、特に新しい要素はありません。
update の方は、$request と $id を引数で受け取っています。$request は以前にやった Form Request を継承した ArticleRequest クラスを使用しています。Form Request を使うことで、フォームの入力データのチェックとエラーがあった時の前画面へのリダイレクトを自動的に行なってくれます。 update メソッド内では $id に対応する記事を取得し、入力されたデータで記事を update して、記事表示画面にリダイレクトしています。
View
edit.blade.php を作成します。以前に作成した create.blade.php をコピーして修正します。
// resources/views/articles/edit.blade.php @extends('layout') @section('content') <h1>Edit: {{ $article->title }}</h1> <hr/> @if ($errors->any()) <ul class="alert alert-danger"> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> @endif {!! Form::model($article, ['method' => 'PATCH', 'url' => ['articles', $article->id]]) !!} <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', $article->published_at->format('Y-m-d'), ['class' => 'form-control']) !!} </div> <div class="form-group"> {!! Form::submit('Edit Article', ['class' => 'btn btn-primary form-control']) !!} </div> {!! Form::close() !!} @endsection
create.blade.php から修正したのは以下の4点になります。
- ページタイトルに記事のタイトルを表示
- Form タグの作成を From::open から Form::model に変更。
$article の値をフォームに紐付ける為に Form::model を使用します。
METHOD に PATCH を指定し、url へは $article の idをパラメータとして引き渡します。 - published_at の入力項目の初期値を date(‘Y-m-d’)から $article->publieshed_at の値に変更。$article->published_at は Article クラスで日付ミューテーターを指定している為、参照すると Carbon クラスのインスタンスが返ってきます。format()メソッドで文字列に変換して初期値とします。
- submit ボタンのタイトルを ‘Edit Article’ に変更
ここで、WWW ブラウザで html://localhost:8000/articles/{id}/edit にアクセスして生成される form のソースを確認してみます。
※ URL の {id} 部分は DB の articles テーブルに実在するデータの id に置き換えてください
... <form method="POST" action="http://localhost:8000/articles/1" accept-charset="UTF-8"> <input name="_method" type="hidden" value="PATCH"> ...
WWW ブラウザでは form の method は GET と POST にしか対応していないため、hidden を使って、Laravel に PATCH メソッドであることを伝えています。
ここでは、laravelcollective/html パッケージの Form ファサードを使って、Form を生成した為、method を指定する hidden 項目は自動で挿入されました。Form ファサードを使わず、手動で form タグを記述する場合は、自分で hidden 項目を記述する必要があります。その場合は Blade テンプレートの @method ディレクティグを使用します。CSRF トークンを埋め込む @csrf ディレクティブも同時に使います。
<form action="/foo/bar" method="POST"> @method('PATCH') @csrf ... </form>
Form の method 指定についてはこちらを参照してください。
https://laravel.com/docs/5.7/routing#form-method-spoofing
View Partial
ここまでで、記事の編集機能は実装できましたが、新規記事作成フォームと、記事編集フォームで同じコードが重複しているで、Viewの Partial 機能を使って共通化します。
エラー表示の Partial 化
form_errors.blade.php を作成します。
// resources/views/errors/form_errors.blade.php @if ($errors->any()) <ul class="alert alert-danger"> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> @endif
form_errors.blade.php を使用するように、edit.blade.php を修正します。
// resources/views/articles/edit.blade.php @extends('layout') @section('content') <h1>Edit: {!! $article->title !!}</h1> <hr/> @include('errors.form_errors') {!! Form::model($article, ['method' => 'PATCH', 'url' => ['articles', $article->id]]) !!} ... ... {!! Form::close() !!} @endsection
@include を使って、form_errors.blade.php を参照します。form_errors.blade.php は resources/views 以下の errors ディレクトリに作成した為、’errors.form_errors’と指定します。
この様に、@include することを目的に切り出した blade テンプレートファイルを Laravelでは Partial と呼んでいます。
Form 部分の Partial 化と、Partial への値の渡し方
form.blade.php を作成します。
// resources/views/articles/form.blade.php <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', $published_at, ['class' => 'form-control']) !!} </div> <div class="form-group"> {!! Form::submit($submitButton, ['class' => 'btn btn-primary form-control']) !!} </div>
published_at の初期値は、$publishd_at 変数が渡されることを想定しています。また、submit ボタンのタイトルも $submitButton 変数が渡されることを想定しています。
form.blade.php を使用するように、edit.blade.php を修正します。
// resources/views/articles/edit.blade.php @extends('layout') @section('content') <h1>Edit: {!! $article->title !!}</h1> <hr/> @include('errors.form_errors') {!! Form::model($article, ['method' => 'PATCH', 'url' => ['articles', $article->id]]) !!} @include('articles.form', ['published_at' => $article->published_at->format('Y-m-d'), 'submitButton' => 'Edit Article']) {!! Form::close() !!} @endsection
@include を使って、form.blade.php を参照しています。published_at と submitButton の値を引き渡しています。
編集ボタンの追加
最後に、記事の表示画面に、編集ボタンを追加しておきます。
// resources/views/articles/show.blade.php @extends('layout') @section('content') <h1>{{ $article->title }}</h1> <hr/> <article> <div class="body">{{ $article->body }}</div> </article> <br/> <div> <a href="{{ action('ArticlesController@edit', [$article->id]) }}" class="btn btn-primary" > 編集 </a> <a href="{{ action('ArticlesController@index') }}" class="btn btn-secondary float-right" > 一覧へ戻る </a> </div> @endsection
編集ボタンとして、a タグで “articles/{id}/edit” へのリンクを追加しました。
a タグに Bootstrap の class 指定をしてボタンとして表示しています。
action() ヘルパー関数を使って URL を生成しています。
同様に一覧ボタンへ戻るも追加しました。
動作確認
ここまでで、記事の編集画面が完成しました。動作確認をしてみます。
- http://localhost:8000/articles にアクセスして記事を選択して表示
- 記事の表示画面で編集ボタンをクリック
- 記事を変更
- 表示画面で記事の内容が変更されていることを確認
演習
create.blade.php も edit.blade.php と同様に、partial を使うように修正してみてください。
まとめ
以下の事が出来るようになりました。
- Form::model を使って、データをフォームに紐付ける
- Partial を使った、ビューの部品化
- Partial への値の渡し方