はじめに
前回 でLaravelのMVCのうちモデルとコントローラーについて見てきたので今回はViewについて簡単にまとめてLaravelの基本を終え、成果物に進んでいきたいと思う。
View
前回でも述べた通りViewはアプリケーションの見た目の部分を担うファイル群である。
もちろんPHPではなく、マークアップ言語であるHTMLで書くのだがLaravelにはデフォルトでテンプレート・エンジンのBladeが実装されているのでそれを使ってHTMLを書いていくことになる。
では、見ていこう。ちなみにここから先はBootstrapの知識がある前提で話をするのでご注意を。
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta charset="utf-8">
<meta lang>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<title></title>
</head>
<body>
{{-- @section('content')~@endsectionで囲った部分が入る --}}
@yield('content')
</body>
</html>
Bladeを使用するときの特徴としてViewにあたるファイルは必ずファイル名.blade.php
という形で名前をつけなければならない。
内容自体は、一見よく見るHTMLの記述だがテンプレート・エンジンの特徴として、1つの基本ページを軸にして複数のページにそのフォーマット使い回せるというものがある。
言葉で説明するより見たほうが早いので次のファイルを見てみる。
@php
$title = __('テストデータ一覧');
@endphp
{{-- layout.blade.phpの継承 --}}
@extends('sampleuser/layout')
{{-- @endsectionまでの部分が@yield('content')に代入される。--}}
@section('content')
<div class="container ops-main">
<h3 class="ops=title text-center">{{ $title }}</h3>
<div class="row">
<table class="table table-striped">
<thead>
<tr>
<th>{{ __('ID')}}</th>
<th>{{ __('UserName')}}</th>
</tr>
</thead>
<tbody>
@foreach($sampleusers as $sampleuser)
<tr>
<td>{{ $sampleuser->id }}</td>
<td><a href="/sampleuser/{{ $sampleuser->id }}/edit">{{ $sampleuser->user_name }}</a></td>
<!-- <td>
<form action="/sampleuser/{{ $sampleuser->id }}" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<button type="submit" class="btn btn-xs btn-danger" aria-label="left Align"><span class="glyphicon glyphicon-trash"></span></button>
</form>
</td> -->
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@endsection
こちらは、前回で定義したindexメソッドが実行されたときに表示されるページなのだがDOCTYPE宣言やmetaタグなどの記述がない。
これは各ページのbladeにはそのページごとの要素を書き、それをlayout.blade.phpに挿入するような形でページを表示するからである。
具体的に見ていこう。
@php~@endphp
ここで囲んだ領域はPHPの記述となる。
Viewの領域には処理は基本的には書かないが今回はページのタイトル名を変数の形にして書き換えしやすくするために使用している。
@extends()
引数に設定したファイルに後述する@secition~@endsectionで囲んだ部分を@yield()以下に挿入する役割を表す。
引数は(bladeが入っているフォルダ名/挿入先のファイル名)
または、(bladeが入っているフォルダ名.挿入先のファイル名)
といったような形で定義する。
@yield()、@section()~@endsection、@include()
挿入先のファイルに@yield()
を記載し、挿入するHTML記述を@section()~@endsection
で囲む形で使う。
両者は引数で紐付けされるので、@yield()
と@section()
の引数は同じ引数に設定する。
@include
は引数に設定したファイル及びそのファイルで設定した後述の@if~endif
等の条件付けに基づいて挿入する箇所を変えるというもの。詳しくは後述。
@if~@endif、@foreach()~@endforeach
囲った範囲にお馴染みのif文・foreach文の条件付けを行える。
以下を見れば仕組みがわかると思う。
@php
$title = __('Edit');
@endphp
@extends('sampleuser.layout')
@section('content')
@include('sampleuser/registform', ['target' => 'update'])
@endsection
まず、こちらはeditメソッドとupdateメソッドが実行されるページのblade。
sectionまでは一緒だが@includeがある。
つまり、sampleuserディレクトリにあるregistform.blade.phpにおいて、条件付けされている部分は、$targetの値がupdateだった場合の部分を挿入するということになる。
同じくcreate.blade.phpも
@php
$title = __('Regist');
@endphp
@extends('sampleuser.layout')
@section('content')
@include('sampleuser/registform', ['target' => 'store'])
@endsection
今度は$targetの値がstoreになっている以外はeditのものと一緒。
つまり、一つのファイルに条件付けを行っておくことであるページの一部分だけ変更した2つのページを作ることができるということである。
registform.blade.phpを見てみると
{{-- __付きは多言語対応させるための記述である --}}
<div class="container">
<h1>{{ $title }}</h1>
@if($target == 'store')
<form action="{{ url('sampleuser' )}}" method="post">
@csrf
@method('POST')
@elseif($target == 'update')
<form action="{{ url('sampleuser/'. $sampleuser->id) }}" method="post">
@csrf
@method('PUT')
@endif
<div class="form-group">
<label for="user_name">{{ __('UserName') }}</label>
<input id="user_name" type="text" class="form-control" name="user_name" required autofocus>
</div>
<div class="form-group">
<label for="email">{{ __('Email')}}</label>
<input id="email" type="email" class="form-control" name="email" required>
</div>
@if($target == 'store')
<div class="form-group">
<label for="password">{{ __('Password')}}</label>
<input id="password" type="password" class="form-control" name="password" required>
</div>
<div class="form-group">
<label for="password_confirmed">{{ __('Confirm Password')}}</label>
<input id="password_confirmed" type="password" class="form-control" name="password_confirmed" required>
</div>
@endif
<button type="submit" name="submit" class="btn btn-primary">{{ __('submit') }}</button>
</form>
</div>
formタグの部分及び、form-groupの一部に条件づけが行われていることがわかる。
これは、まずformが扱うリクエストメソッドの種類が両者で違うためである。
前回のルーティングを思い出してほしいが、storeメソッドが着火するためのリクエストメソッドはPOSTであり、updateメソッドのそれはPUTであった。
@method()
の部分でそれを指定している。
なので、同じフォームでも2種類書かなければいけないのだが2つもフォームを書くのは面倒なので、最初のformタグの部分で条件付けをしておけば、あとのform-groupの内容は使い回せばいいだけになり楽になる。
さらに加えて条件付けをすることで、登録の際はパスワードが必要だが、編集画面でパスワードを編集できるようにするには危ないので外しておきたいということから今回は登録と編集画面で表示するform-groupの内容を変えている。
@csrfはCSRF対策のための記述。
以上がViewの基本であり、いわゆるテンプレート・エンジンと呼ばれ、その一種であるBladeの働きである。
最後にcomponentについてまとめておく。
{{-- コンポーネントはボタンなどの部品を定義してViewで共通部品として実装するための仕組み。ここでは削除ボタン --}}
{{-- url()にはスロットから渡された配列が代入される変数を指定しておく。この場合URIがsampleuser/任意のidの値ということになる。 --}}
<form style="display:inline" action="{{ url($table.'/'.$id) }}" method="post">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger">
{{ __('Delete') }}
</button>
</form>
@php
$title = __('テストデータ').': '.$sampleuser->user_name;
@endphp
@extends('sampleuser.layout')
@section('content')
<div class="container">
<h1>{{ $title }}</h1>
{{-- 編集・削除ボタン。削除ボタンはcomponentを用いている。 --}}
<div>
<a href="{{ url('sampleuser/'.$sampleuser->id.'/edit') }}" class="btn btn-primary">
{{ __('Edit') }}
</a>
{{-- エイリアスを用いた記述。slotの第一引数の変数に第2引数に指定した配列を渡す --}}
@deletebutton
@slot('table', 'sampleuser')
@slot('id', $sampleuser->id)
@enddeletebutton
</div>
{{-- ユーザー1件の情報 --}}
<dl class="row">
<dt class="col-md-2">{{ __('ID') }}</dt>
<dd class="col-md-10">{{ $sampleuser->id }}</dd>
<dt class="col-md-2">{{ __('UserName') }}</dt>
<dd class="col-md-10">{{ $sampleuser->user_name }}</dd>
<dt class="col-md-2">{{ __('Password') }}</dt>
<dd class="col-md-10">{{ $sampleuser->password }}</dd>
<dt class="col-md-2">{{ __('Email') }}</dt>
<dd class="col-md-10">{{ $sampleuser->email }}</dd>
<dt class="col-md-2">{{ __('isEmailConfirmed') }}</dt>
<dd class="col-md-10">{{ $sampleuser->isEmailConfirmed }}</dd>
<dt class="col-md-2">{{ __('Token') }}</dt>
<dd class="col-md-10">{{ $sampleuser->token }}</dd>
<dt class="col-md-2">{{ __('TokenExpire') }}</dt>
<dd class="col-md-10">{{ $sampleuser->tokenExpire }}</dd>
<dt class="col-md-2">{{ __('LoginFailureCount') }}</dt>
<dd class="col-md-10">{{ $sampleuser->loginFailureCount }}</dd>
<dt class="col-md-2">{{ __('LoginFailureDateTime') }}</dt>
<dd class="col-md-10">{{ $sampleuser->loginFailureDatetime }}</dd>
<dt class="col-md-2">{{ __('DeleteFlag') }}</dt>
<dd class="col-md-10">{{ $sampleuser->deleteFlag }}</dd>
</dl>
</div>
@endsection
参考
Laravel入門 - 使い方チュートリアル
Laravel超入門 開発環境の構築(VirtualBox + Vagrant + Homestead + Composer)
Laravel5.7: usersのCRUD機能を実装する
Laravelで作るRESTなWebアプリ
Vagrant + VirtualBox でLaravel5.8環境構築メモ
よく使うMySQLコマンド集
Bladeでcomponentを利用する