Laravelでカレンダーアプリを例に開発の流れを紹介します。
#最初にアプリの雛形を作ります
laravel new cal_lara
cd cal_lara
##タイムゾーンやロケールは次のように設定します
timezone' => 'Asia/Tokyo',
'locale' => 'ja',
##DB接続内容を設定します
編集するファイル:.env
#休日モデルを作成します
アプリが扱うリソースの名前を決めて、その名前でモデルクラスを作成します。カレンダーアプリなので、休日を扱うリソース(テーブル)を持たせます。
php artisan make:model Holiday
##マイグレーション(DBテーブルの用意)も行っておきます
php artisan make:migration Holiday
出来上がったファイルの中にholidaysテーブルのスキーマ定義を書きます。
class Holiday extends Migration {
public function up() {
Schema::create('holidays', function (Blueprint $table) {
$table->increments('id');
$table->date('day');
$table->string('description');
$table->timestamps();
});
}
public function down() {
Schema::drop('holidays');
}
}
##マイグレーション実行します
php artisan migrate
マイグレーションをやり直したい場合は次の通りです。
php artisan migrate:refresh
#カレンダーコントローラーを作ります
php artisan make:controller CalendarController
まずは休日の入力と表示のメソッドを作ります。
use App\Holiday;
use Illuminate\Http\Request;
class CalendarController extends Controller
{
public function getHoliday(Request $request)
{
// 休日データ取得
$list = Holiday::all();
return view('calendar.holiday', ['list' => $list]);
}
public function postHoliday(Request $request)
{
// POSTで受信した休日データの登録
$holiday = new Holiday();
$holiday->day = $request->day;
$holiday->description = $request->description;
$holiday->save();
// 休日データ取得
$list = Holiday::all();
return view('calendar.holiday', ['list' => $list]);
}
}
Viewは後ほど用意しますが、入力、表示ともに同じViewを使うようにします。
##ルーティング情報を設定します
ルーティングにコントローラークラス@メソッドを定義します。
Route::get('/holiday','CalendarController@getHoliday');
Route::post('/holiday','CalendarController@postHoliday');
#ビュー(Blade)を作ります
mkdir resources/views/calendar
Viewではコントローラーに対して日付と説明を送信するフォーム部分と、コントローラーから休日一覧を受け取り、その結果を表示する部分の2つの機能を持たせます。
<html>
<head>
<title>休日データ</title>
</head>
<body>
<h1>休日</h1>
<!-- 休日入力フォーム -->
<form method="POST" action="/holiday">
{{csrf_field()}}
日付: <input type="text" name="day"> [YYYY/MM/DD]
説明: <input type="text" name="description">
<input type="submit">
</form>
<!-- 休日一覧表示 -->
<table>
<tr>
<th>日付</th>
<th>説明</th>
<th>作成日</th>
<th>更新日</th>
</tr>
@foreach($list as $val)
<tr>
<td>{{$val->day}}</td>
<td>{{$val->description}}</td>
<td>{{$val->created_at}}</td>
<td>{{$val->updated_at}}</td>
</tr>
@endforeach
</table>
</body>
</html>
ここまで作ったら、動かしてみましょう。休日データが登録できて、一覧取得できるはずです。
php artisan serve --port 8080
URLアドレス:http://[servername]/holiday
##レイアウトを分割し、ついでにJQuery/Bootstrap導入します
レイアウトファイルを作り、HTMLの共通部分はこのファイルに書くようにします。
<!DOCTYPE HTML>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>@yield('title')</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
@yield('content')
</div>
</body>
</html>
先ほど作ったBladeファイルを下記のように変更します。
@extends('layout')
@section('title', '休日設定')
@section('content')
<h1>休日設定</h1>
<!-- 休日入力フォーム -->
<form method="POST" action="/holiday">
<div class="form-group">
{{csrf_field()}}
<label for="day">日付[YYYY/MM/DD] </label>
<input type="text" name="day" class="form-control" id="day">
<label for="description">説明</label>
<input type="text" name="description" class="form-control" id="description">
</div>
<button type="submit" class="btn btn-primary">登録</button>
</form>
<!-- 休日一覧表示 -->
<table class="table">
<thead>
<tr>
<th scope="col">日付</th>
<th scope="col">説明</th>
<th scope="col">作成日</th>
<th scope="col">更新日</th>
</tr>
</thead>
<tbody>
@foreach($list as $val)
<tr>
<th scope="row">{{$val->day}}</th>
<td>{{$val->description}}</td>
<td>{{$val->created_at}}</td>
<td>{{$val->updated_at}}</td>
</tr>
@endforeach
</tbody>
</table>
@endsection
@extends
で “layout”
(layout.blade.php) を継承するよう指示しています。
@section(‘content’)
から @endsection
までが、layout ビューの @yield(‘content’)
の箇所に流し込む部分になります。
ここでbootstrapのCSSを使うようにし画面をリッチにします。
参考:
https://getbootstrap.com/docs/4.0/content/tables/
##JQueryで日付入力を便利にします
日付(YYYY/MM/DD)の入力をポップアップカレンダーから選択して日付入力できるようにしてみましょう。
次のコードを書きます。(<body>
タグの中ならどこでもいいです)
・・(一部抜粋)・・
<script>
$( function() {
$( "#day" ).datepicker({dateFormat: 'yy-mm-dd'});
} );
</script>
そして日付の入力をするフォームのid属性をつけます。(bootstrapの適用の時id="day"と入れたのでそれを使います)
<input type="text" id="day">
参考:
http://jqueryui.com/datepicker/
ここまで作ったら、動かしてみましょう。休日一覧が綺麗に表示され、日付入力時にカレンダーから日付が選択できるはずです。
php artisan serve --port 8080
URLアドレス:http://[servername]/
#カレンダーの表示処理を作ります
カレンダー処理を行うクラスをComposerでオートロードするようにします。
以下のようなクラスを作成します。
namespace App;
class Calendar
{
private $html;
public function showCalendarTag($m, $y)
{
$year = $y;
$month = $m;
if ($year == null) {
// システム日付を取得する。
$year = date("Y");
$month = date("m");
}
$firstWeekDay = date("w", mktime(0, 0, 0, $month, 1, $year)); // 1日の曜日(0:日曜日、6:土曜日)
$lastDay = date("t", mktime(0, 0, 0, $month, 1, $year)); // 指定した月の最終日
// 日曜日からカレンダーを表示するため前月の余った日付をループの初期値にする
$day = 1 - $firstWeekDay;
$this->html = <<< EOS
<h1>{$year}年{$month}月</h1>
<table class="table table-bordered">
<tr>
<th scope="col">日</th>
<th scope="col">月</th>
<th scope="col">火</th>
<th scope="col">水</th>
<th scope="col">木</th>
<th scope="col">金</th>
<th scope="col">土</th>
</tr>
EOS;
// カレンダーの日付部分を生成する
while ($day <= $lastDay) {
$this->html .= "<tr>";
// 各週を描画するHTMLソースを生成する
for ($i = 0; $i < 7; $i++) {
if ($day <= 0 || $day > $lastDay) {
// 先月・来月の日付の場合
$this->html .= "<td> </td>";
} else {
$this->html .= "<td>" . $day . "</td>";
}
$day++;
}
$this->html .= "</tr>";
}
return $this->html .= '</table>';
}
}
HTMLタグをコードに埋め込み、指定の年月のカレンダーを表として出力するshowCalendarTagメソッドを作ります。
プロジェクトディレクトリ直下にあるcomposer.jsonのautoload.files
へ以下のようにこのCalendarクラスのファイル・パスを追加します。
・・(一部抜粋)・・
"autoload": {
"classmap": [
...
],
"psr-4": {
"App\\": "app/"
},
"files": [
"app/Calendar.php"
]
},
その後、以下のComposerコマンドを実行します。
composer dump-autoload
これでCalendarクラスが使えるようになりました。
コントローラーでカレンダーの表示のためのCalendarクラスをインスタンス化し、メソッドを呼び出します。
use App\Calendar;
・・(一部抜粋)・・
public function index(Request $request)
{
$cal = new Calendar();
$tag = $cal->showCalendarTag($request->month,$request->year);
return view('calendar.index', ['cal_tag' => $tag]);
}
##ルーティング情報はコントローラークラス@メソッドを定義します
Route::get('/','CalendarController@index');
Viewではコントローラーから受け取る結果(カレンダー表)を表示します
@extends('layout')
@section('title', 'カレンダー')
@section('content')
{!!$cal_tag!!}
@endsection
##カレンダーと休日一覧の画面の行き来を行います
先ほど作った休日一覧画面のholiday.blade.phpファイルに下記を追加
<a href="{{ url('/') }}">カレンダーに戻る</a>
先ほど作ったカレンダー画面のindex.blade.phpファイルに下記を追加
<a href="{{ url('/holiday') }}">休日設定</a>
ここまで作ったら、動かしてみましょう。カレンダーが表示され、休日一覧画面との行き来ができるはずです。
php artisan serve --port 8080
URLアドレス:http://[servername]/
##カレンダーに休日情報を入れます
Calendarクラスで休日データをもらうようにします。
まずインスタンス変数を作り、コンストラクタで受け取るようにします。
・・(一部抜粋)・・
private $holidays;
function __construct($holidays) {
$this->holidays = $holidays;
}
日付を入れる行: $this->html .= "<td>" . $day . "</td>";
を下記のように書き換え、日付に応じて休日の情報を表示できるようにします。
・・(一部抜粋)・・
$this->html .= "<td>" . $day ." ";
$target = date("Y-m-d", mktime(0, 0, 0, $month, $day, $year));
foreach($this->holidays as $val) {
if ($val->day == $target) {
$this->html .= $val->description;
break;
}
}
$this->html .= "</td>";
コントローラーのindexでは
・・(一部抜粋)・・
$list = Holiday::all();
$cal = new Calendar($list);
とCalendarクラスのインスタンス化の時に休日のデータを渡すようにします。
ここまで作ったら、再度動かしてみましょう。カレンダーが表示され、休日が表示できるはずです。(休日データを登録してくださいね)
php artisan serve --port 8080
URLアドレス:http://[servername]/
##カレンダーの月めくりを行います
Calendarクラスの中で前月と翌月の年月の計算を行い、ボタンを表示できるようにします。
次のコードを表示すべき$yearと$monthが確定したのちの適切な箇所に追加します。
・・(一部抜粋)・・
// 前月
$prev = strtotime('-1 month',mktime(0, 0, 0, $month, 1, $year));
$prev_year = date("Y",$prev);
$prev_month = date("m",$prev);
// 翌月
$next = strtotime('+1 month',mktime(0, 0, 0, $month, 1, $year));
$next_year = date("Y",$next);
$next_month = date("m",$next);
そしてHTMLの年月の表示部分のところで、前月と翌月のリンクボタンを表示します。
・・(一部抜粋)・・
$this->html = <<< EOS
<h1>
<a class="btn btn-primary" href="/?year={$prev_year}&month={$prev_month}" role="button"><前月</a>
{$year}年{$month}月
<a class="btn btn-primary" href="/?year={$next_year}&month={$next_month}" role="button">翌月></a>
</h1>
ここまで作ったら、再度動かしてみましょう。カレンダーが表示され、月めくりできるはずです。
php artisan serve --port 8080
URLアドレス:http://[servername]/
##休日の修正ができるようにします
休日一覧の日付をクリックするとそのデータを編集できるようにします。
ルーティング情報で編集のアクションを定義します。
Route::get('/holiday/{id}','CalendarController@getHolidayId');
コントローラーのなかの表示と編集のメソッドを書き換えます。
・・(一部抜粋)・・
class CalendarController extends Controller
{
public function getHoliday(Request $request)
{
// 休日データ取得
$data = new Holiday();
$list = Holiday::all();
return view('calendar.holiday', ['list' => $list,'data' => $data]);
}
public function getHolidayId($id)
{
// 休日データ取得
$data = new Holiday();
if (isset($id)) {
$data = Holiday::where('id', '=', $id)->first();
}
$list = Holiday::all();
return view('calendar.holiday', ['list' => $list, 'data' => $data]);
}
public function postHoliday(Request $request)
{
// POSTで受信した休日データの登録
if (isset($request->id)) {
$holiday = Holiday::where('id', '=', $request->id)->first();
$holiday->day = $request->day;
$holiday->description = $request->description;
$holiday->save();
} else {
$holiday = new Holiday();
$holiday->day = $request->day;
$holiday->description = $request->description;
$holiday->save();
}
// 休日データ取得
$data = new Holiday();
$list = Holiday::all();
return view('calendar.holiday', ['list' => $list, 'data' => $data]);
}
}
Viewに次のコードを書きます。
編集のためにIDをHiddenで送信できるようにし、各フォームに編集するべき内容を入れるようにします。
・・(一部抜粋)・・
<form method="POST" action="/holiday">
<div class="form-group">
{{csrf_field()}}
<label for="day">日付[YYYY/MM/DD] </label>
<input type="text" name="day" class="form-control" id="day" value="{{$data->day}}">
<label for="description">説明</label>
<input type="text" name="description" class="form-control" id="description" value="{{$data->description}}">
</div>
<button type="submit" class="btn btn-primary">登録</button>
<input type="hidden" name="id" value="{{$data->id}}">
</form>
・・
<!-- 日付のリンクをつける -->
<th scope="row"><a href="{{ url('/holiday/'.$val->id) }}">{{$val->day}}</a></th>
ここまで作ったら、再度動かしてみましょう。休日が修正できるはずです。
php artisan serve --port 8080
URLアドレス:http://[servername]/
##休日の削除ができるようにします
Viewに次のコードを書き削除のためのボタンを追加します。
休日一覧の<table>
に新しい列を作るため<td>
のなかに次のフォームを追加します。
・・(一部抜粋)・・
<td><form action="/holiday" method="post">
<input type="hidden" name="id" value="{{$val->id}}">
{{ method_field('delete') }}
{{csrf_field()}}
<button class="btn btn-default" type="submit">Delete</button>
</form></td>
ルーティング情報で削除のアクションを定義します
Route::delete('/holiday','CalendarController@deleteHoliday');
コントローラーのなかに削除のメソッドを書き加えます。
・・(一部抜粋)・・
public function deleteHoliday(Request $request)
{
// DELETEで受信した休日データの削除
if (isset($request->id)) {
$holiday = Holiday::where('id', '=', $request->id)->first();
$holiday->delete();
}
// 休日データ取得
$data = new Holiday();
$list = Holiday::all();
return view('calendar.holiday', ['list' => $list, 'data' => $data]);
}
ここまで作ったら、再度動かしてみましょう。休日が削除できるはずです。
php artisan serve --port 8080
URLアドレス:http://[servername]/
#バリデーションを行います
コントローラーのなかのpostHolidayメソッドの中で次のコードを追加します。
・・(一部抜粋)・・
public function postHoliday(Request $request)
{
$validatedData = $request->validate([
'day' => 'required|date_format:Y-m-d',
'description' => 'required',
]);
バリデーション結果のメッセージを表示するためにViewに次のコードを書きます。
・・(一部抜粋)・・
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
ここまで作ったら、再度動かしてみましょう。休日のフォームで空のときバリデーションが機能し、登録できないはずです。
php artisan serve --port 8080
URLアドレス:http://[servername]/
#日本語化のため
resources/lang/ja/validation.phpを上記URLで取得したvalidation.phpで置き換えます。
フォーム項目名の日本語化は同ファイルのattributesで定義します。
・・(一部抜粋)・・
'attributes' => [
'day' => '日付',
'description' => '説明',
],
以上、これで完了です。