目次
Laravelの記事一覧は下記
PHPフレームワークLaravelの使い方
Laravelバージョン
動作確認はLaravel Framework 7.19.1で行っています
前提条件
eclipseでLaravel開発環境を構築する。デバッグでブレークポイントをつけて止める。(WindowsもVagrantもdockerも)
本記事は上記が完了している前提で書かれています
プロジェクトの作成もapacheの設定も上記で行っています
Laravelで入力値エラーチェック(validate)を実装する
Laravelでフラッシュデータ(直後のHTTPリクエストの間だけセッションに保存されるデータ)を使う
本記事は上記の内容を理解している前提で書かれています
LaravelでDIを使う
本記事は上記で作成したフォルダとファイルを使用します
Laravelでデータベースを扱う準備をする
Laravelでテーブル作成
Laravelで初期データ投入
本記事は上記ので作成したデータベースとレコードを使用します
モデルクラス(エンティティクラス)作成
(1) コマンドラインで
sample
php artisan make:model Models/Table3
php artisan make:model Models/Table2
xdebugの設定をしているとeclipseが実行していいですかというプロンプトを出すのでOKを押します
eclipseプロジェクトを右クリック→リフレッシュ
/sample/app/Models/Table3.phpが現れます
/sample/app/Models/Table2.phpが現れます
(2) Table3.php修正
/sample/app/Models/Table3.phpを下記に修正
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
class Table3 extends Model
{
protected $connection = 'mysql';
protected $table = 'table3';
protected $primaryKey = 'id';
protected $keyType = 'int';
public $incrementing = true;
public $timestamps = true;
protected $dateFormat = 'Y-m-d H:i:s';
const CREATED_AT = 'create_datetime';
const UPDATED_AT = 'update_datetime';
public function joinTable2()
{
return $this->belongsTo('App\Models\Table2', 'table2_id', 'id');
}
public function scopeIntColMoreThanZero($query)
{
return $query->where('int_col', '>', 0);
}
public function scopeDateColMoreThan($query, $val)
{
return $query->where('date_col', '>', $val);
}
protected static function booted()
{
static::addGlobalScope('Table3_int_col', function (Builder $builder) {
$builder->where('int_col', '=', 1);
});
}
}
・protected $connection = 'mysql';
は接続先データベースです。config/database.phpのconnections配列の要素を記載します。このプロパティを書かなかった場合、config/database.phpのdefaultが使用されます
・protected $table
はこのモデルクラスが表すテーブル名です。このプロパティを書かなかった場合、クラス名を複数形にし、それをスネークケースにしたものが、テーブル名として使用されます(例:Flightクラスの場合、flightsテーブルとなる)。
・protected $primaryKey
はこのモデルクラスが表すテーブルのプライマリーキーです。このプロパティを書かなかった場合、'id'が使用されます
・protected $keyType
はこのモデルクラスが表すテーブルのプライマリーキーの型です。このプロパティを書かなかった場合、'int'が使用されます
・public $incrementing
はこのモデルクラスが表すテーブルのプライマリーキーがオートインクリメントの場合trueにします。このプロパティを書かなかった場合、trueが使用されます
・public $timestamps
はこのモデルクラスが表すテーブルの作成時間カラムと更新時間カラムを自動的に更新する場合trueにします。この機能を使いたくない場合はfalseにします。このプロパティを書かなかった場合、trueが使用されます
・protected $dateFormat
はタイムスタンプのフォーマットです
・const CREATED_AT
は作成時間カラムです。このプロパティを書かなかった場合、'created_at'が使用されます
・const UPDATED_AT
は作成時間カラムです。このプロパティを書かなかった場合、'updated_at'が使用されます
・メソッドの説明は後述するサービスクラスの作成で行います
(3) Table2.php修正
/sample/app/Models/Table2.phpを下記に修正
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Table2 extends Model
{
protected $connection = 'mysql';
protected $table = 'table2';
protected $primaryKey = 'id';
protected $keyType = 'int';
public $incrementing = true;
public $timestamps = false;
}
サービスクラス作成
(1) /sample/app/Services/InterfacesフォルダにTable3Service.php作成
<?php
namespace App\Services\Interfaces;
interface Table3Service
{
public function __construct();
public function select($id, $varchar_col, $int_col, $datetime_col, $date_col, $time_col);
public function insert($table2_id, $varchar_col, $int_col, $datetime_col, $date_col, $time_col);
public function update($id, $table2_id, $varchar_col, $int_col, $datetime_col, $date_col, $time_col);
public function delete($id);
}
(2) /sample/tests/Services/ImplフォルダにTable3ServiceImpl.php作成
<?php
namespace Tests\Services\Impl;
use App\Services\Interfaces\Table3Service;
class Table3ServiceImpl implements Table3Service
{
public function __construct()
{
}
public function select($id, $varchar_col, $int_col, $datetime_col, $date_col, $time_col)
{
}
public function insert($table2_id, $varchar_col, $int_col, $datetime_col, $date_col, $time_col)
{
}
public function update($id, $table2_id, $varchar_col, $int_col, $datetime_col, $date_col, $time_col)
{
}
public function delete($id)
{
}
}
(3) /sample/app/Services/ImplフォルダにTable3ServiceImpl.php作成
<?php
namespace App\Services\Impl;
use App\Services\Interfaces\Table3Service;
use App\Models\Table3;
class Table3ServiceImpl implements Table3Service
{
public function __construct()
{
}
public function select($id, $varchar_col, $int_col, $datetime_col, $date_col, $time_col)
{
$db = Table3::with('joinTable2')
->withoutGlobalScope('Table3_int_col')
->intColMoreThanZero()
->dateColMoreThan('2000-01-01');
if (!is_null($id)) {
$db->where('id', '=', $id);
}
if (!is_null($varchar_col)) {
$db->where('varchar_col', 'like', '%'. addcslashes($varchar_col, '\\_%') . '%');
}
if (!is_null($int_col)) {
$db->where('int_col', '=', $int_col);
}
if (!is_null($datetime_col)) {
$db->where('datetime_col', '=', $datetime_col);
}
if (!is_null($date_col)) {
$db->where('date_col', '=', $date_col);
}
if (!is_null($time_col)) {
$db->where('time_col', '=', $time_col);
}
$recordList = $db->get();
return $recordList;
}
public function insert($table2_id, $varchar_col, $int_col, $datetime_col, $date_col, $time_col)
{
$table = new Table3();
$table->table2_id = $table2_id;
$table->varchar_col = $varchar_col;
$table->int_col = $int_col;
$table->datetime_col = $datetime_col;
$table->date_col = $date_col;
$table->time_col = $time_col;
return $table->save();
}
public function update($id, $table2_id, $varchar_col, $int_col, $datetime_col, $date_col, $time_col)
{
$table = Table3::withoutGlobalScope('Table3_int_col')->find($id);
if (is_null($table)) {
return false;
}
$table->table2_id = $table2_id;
$table->varchar_col = $varchar_col;
$table->int_col = $int_col;
$table->datetime_col = $datetime_col;
$table->date_col = $date_col;
$table->time_col = $time_col;
return $table->save();
}
public function delete($id)
{
$table = Table3::withoutGlobalScope('Table3_int_col')->find($id);
if (is_null($table)) {
return false;
}
return $table->delete();
}
}
これがデータベースにselect、insert、update、deleteしている処理になります
・with('joinTable2')
はTable3モデルクラスのjoinTable2メソッドを適用することになります。joinTable2メソッドの中身はreturn $this->belongsTo('App\Models\Table2', 'table2_id', 'id');
としてあります。これはtable3からtable2(子テーブルから親テーブル)へのleft joinと同じ動きとなります。第一引数が親テーブルのモデル、第二引数が子テーブルのカラム、第三引数が親テーブルのカラムです。逆に親テーブルから子テーブルへの結合をしたい場合はbelongsTo
ではなくhasMany
を使います。また、left joinと同じ動きと書きましたが、実際はleft joinされておらず、select文が2回発行されます。まず、table3へのselectが実行され、取得できたid値をwhereのinに指定したtable2へのselect文が実行されます
・withoutGlobalScope('Table3_int_col')
はTable3モデルクラスのbootedメソッドで設定したwhere句を使用しないようにするメソッドです。Table3モデルクラスのbootedメソッドでは、addGlobalScopeを実行し、第一引数に適当な一意な文字列を与え(withoutGlobalScopeメソッドの引数に指定するものになります)、第二引数にwhere句を作成するクロージャを与えます。このGlobalScopeというのは、このモデルクラスを使用してDBアクセスした場合に自動的にwhere句を付けてくれるものです。論理削除モデルのテーブルを使っている場合、削除フラグのwhere句忘れを防ぐことができます。今回、このサービスクラスではwithoutGlobalScopeを呼んでいるのでTable3クラスのbootメソッドで指定したwhere句は付きませんが、withoutGlobalScopeを呼ばなければ、Table3クラスのbootメソッドで指定したwhere句が自動的に付きます
・intColMoreThanZero()
はTable3モデルクラスのscopeIntColMoreThanZeroメソッドを適用することになります。よく使うwhere句はscopeXXXという名前のメソッドにまとめて書いておき、モデルクラスを使うときにscopeをはずしたメソッド名で実行すれば、scopeXXXに書いたwhere句が適用されます
・dateColMoreThan('2000-01-01')
の説明はintColMoreThanZeroと同じです。引数渡しバージョンです
・find($id)
はプライマリーキーを使ってselectします。プライマリーキーはモデルクラスでprotected $primaryKey
プロパティで設定できます
・save()
はモデルのexistsフラグが立っていない場合、insert、existsフラグが立っている場合、updateします。existsフラグはfindメソッドでレコードを取得した時や、saveメソッドでinsertするとtrueになります。existsフラグはpublicプロパティなので、外からでも変更できます。
・delete()
はモデルのexistsフラグが立っている場合、deleteします
ここで使用していないメソッドは下記で確認できます
Laravel 7.x Eloquent:利用の開始
Laravel 7.x Eloquent:リレーション
また、トランザクションを使用したい場合は下記でできます
Laravel 7.x データベース:利用開始 データベーストランザクション
DI登録
(1) /sample/app/Providers/DiServiceProvider.phpに下記を追記
use App\Services\Interfaces\Table3Service;
(2) /sample/app/Providers/DiServiceProvider.phpのregisterメソッドに下記を追記
app()->singleton(Table3Service::class, $prefix . 'Table3ServiceImpl');
DiServiceProvider.phpはLaravelでDIを使うで作成したファイルです
LaravelでDIを使うでconfig/app.phpのprovidersに登録してあります
フォームリクエストの作成
/sample/app/Http/Requests/Table3Request.php作成
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class Table3Request extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
$method = $this->getMethod();
$idRequire = 'nullable';
$url = $this->url();
$urlArray = explode("/", $url);
$urlTail = array_pop($urlArray);
if ($method === 'POST' && ($urlTail === 'update-orm' || $urlTail === 'delete-orm')) {
$idRequire = 'required';
}
return [
'id' => [$idRequire, 'numeric', 'max:18446744073709551615'],
'table2_id' => ['nullable', 'numeric', 'max:18446744073709551615'],
'varchar_col' => ['nullable', 'max:255'],
'int_col' => ['nullable', 'integer', 'max:2147483647'],
'datetime_col' => ['nullable', 'date_format:Y-m-d H:i:s'],
'date_col' => ['nullable', 'date_format:Y-m-d'],
'time_col' => ['nullable', 'date_format:H:i:s'],
];
}
}
Controllerにメソッド追加
(1) /sample/app/Http/Controllers/SampleController.phpにuse文を追記
use App\Http\Requests\Table3Request;
use App\Services\Interfaces\Table3Service;
(2) /sample/app/Http/Controllers/SampleController.phpにselectOrmメソッド、insertOrmメソッド、updateOrmメソッド、deleteOrmメソッドを追記
public function selectOrm(Table3Request $request, Table3Service $table3Service)
{
if (is_null($request->session()->get('errors'))) {
$request->flash();
}
$id = $request->input('id');
$varchar_col = $request->input('varchar_col');
$int_col = $request->input('int_col');
$datetime_col = $request->input('datetime_col');
$date_col = $request->input('date_col');
$time_col = $request->input('time_col');
$recordList = [];
if ($request->getMethod() === 'POST') {
$recordList = $table3Service->select($id, $varchar_col, $int_col, $datetime_col, $date_col, $time_col);
}
$data = [
'recordList' => $recordList
];
return view('sample.selectOrm', $data);
}
public function insertOrm(Table3Request $request, Table3Service $table3Service)
{
if (is_null($request->session()->get('errors'))) {
$request->flash();
}
$table2_id = $request->input('table2_id');
$varchar_col = $request->input('varchar_col');
$int_col = $request->input('int_col');
$datetime_col = $request->input('datetime_col');
$date_col = $request->input('date_col');
$time_col = $request->input('time_col');
$saved = null;
if ($request->getMethod() === 'POST') {
$saved = $table3Service->insert($table2_id, $varchar_col, $int_col, $datetime_col, $date_col, $time_col);
}
$data = [
'saved' => $saved
];
return view('sample.insertOrm', $data);
}
public function updateOrm(Table3Request $request, Table3Service $table3Service)
{
if (is_null($request->session()->get('errors'))) {
$request->flash();
}
$id = $request->input('id');
$table2_id = $request->input('table2_id');
$varchar_col = $request->input('varchar_col');
$int_col = $request->input('int_col');
$datetime_col = $request->input('datetime_col');
$date_col = $request->input('date_col');
$time_col = $request->input('time_col');
$saved = null;
if ($request->getMethod() === 'POST') {
$saved = $table3Service->update($id, $table2_id, $varchar_col, $int_col, $datetime_col, $date_col, $time_col);
}
$data = [
'saved' => $saved
];
return view('sample.updateOrm', $data);
}
public function deleteOrm(Table3Request $request, Table3Service $table3Service)
{
if (is_null($request->session()->get('errors'))) {
$request->flash();
}
$id = $request->input('id');
$deleted = null;
if ($request->getMethod() === 'POST') {
$deleted = $table3Service->delete($id);
}
$data = [
'deleted' => $deleted
];
return view('sample.deleteOrm', $data);
}
先ほど作成したフォームリクエストを使って入力値を受け取り、先ほど作成したサービスクラスでデータベースアクセス処理を行っています
この記事では入力画面と完了画面を同じメソッドで処理していますが、これはメソッドを分けているとサンプルコードが長くなり、記事が見にくくなるので1つのメソッドで処理しているだけです
実際の開発ではif ($request->getMethod() === 'POST')
というif文など使わずにメソッドを分けましょう
(3) /sample/routes/web.phpに下記を追記
Route::match(['get', 'post'],'sample/select-orm', 'SampleController@selectOrm');
Route::match(['get', 'post'],'sample/insert-orm', 'SampleController@insertOrm');
Route::match(['get', 'post'],'sample/update-orm', 'SampleController@updateOrm');
Route::match(['get', 'post'],'sample/delete-orm', 'SampleController@deleteOrm');
viewの作成
(1) /sample/resources/views/sample/selectOrm.blade.phpファイル作成
<html>
<head>
<title>sample</title>
<style>
.sample-table {
border-collapse:collapse;
white-space: nowrap;
border: 1px solid #000000;
}
.sample-table thead {
background-color: #33CCFF;
color: #FFFFFF;
font-weight: bold;
}
.sample-table td {
padding-left:10px;
padding-right:10px;
border: 1px solid #000000;
}
</style>
</head>
<body>
<form action="{{ url('sample/select-orm') }}" method="post">
@csrf
@error('id')
@foreach ($errors->get('id') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>id<input type="text" name="id" value="{{ old('id') }}"></div>
@error('varchar_col')
@foreach ($errors->get('varchar_col') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>varchar_col<input type="text" name="varchar_col" value="{{ old('varchar_col') }}"></div>
@error('int_col')
@foreach ($errors->get('int_col') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>int_col<input type="text" name="int_col" value="{{ old('int_col') }}"></div>
@error('datetime_col')
@foreach ($errors->get('datetime_col') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>datetime_col<input type="text" name="datetime_col" value="{{ old('datetime_col') }}"></div>
@error('date_col')
@foreach ($errors->get('date_col') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>date_col<input type="text" name="date_col" value="{{ old('date_col') }}"></div>
@error('time_col')
@foreach ($errors->get('time_col') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>time_col<input type="text" name="time_col" value="{{ old('time_col') }}"></div>
<input type="submit" >
</form>
<br>
<table class="sample-table">
<thead>
<tr>
<td colspan=6>table2</td>
<td colspan=6>table3</td>
</tr>
<tr>
<td>id</td>
<td>varchar_col</td>
<td>int_col</td>
<td>datetime_col</td>
<td>date_col</td>
<td>time_col</td>
<td>id</td>
<td>varchar_col</td>
<td>int_col</td>
<td>datetime_col</td>
<td>date_col</td>
<td>time_col</td>
</tr>
</thead>
<tbody>
@foreach ($recordList as $record)
<tr>
<td>{{ isset($record->joinTable2) ? $record->joinTable2->id : '' }}</td>
<td>{{ isset($record->joinTable2) ? $record->joinTable2->varchar_col : '' }}</td>
<td>{{ isset($record->joinTable2) ? $record->joinTable2->int_col : '' }}</td>
<td>{{ isset($record->joinTable2) ? $record->joinTable2->datetime_col : '' }}</td>
<td>{{ isset($record->joinTable2) ? $record->joinTable2->date_col : '' }}</td>
<td>{{ isset($record->joinTable2) ? $record->joinTable2->time_col : '' }}</td>
<td>{{ $record->id }}</td>
<td>{{ $record->varchar_col }}</td>
<td>{{ $record->int_col }}</td>
<td>{{ $record->datetime_col }}</td>
<td>{{ $record->date_col }}</td>
<td>{{ $record->time_col }}</td>
</tr>
@endforeach
</tbody>
</table>
</body>
</html>
(2) /sample/resources/views/sample/insertOrm.blade.phpファイル作成
<html>
<head>
<title>sample</title>
</head>
<body>
<form action="{{ url('sample/insert-orm') }}" method="post">
@csrf
@error('table2_id')
@foreach ($errors->get('table2_id') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>table2_id<input type="text" name="table2_id" value="{{ old('table2_id') }}"></div>
@error('varchar_col')
@foreach ($errors->get('varchar_col') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>varchar_col<input type="text" name="varchar_col" value="{{ old('varchar_col') }}"></div>
@error('int_col')
@foreach ($errors->get('int_col') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>int_col<input type="text" name="int_col" value="{{ old('int_col') }}"></div>
@error('datetime_col')
@foreach ($errors->get('datetime_col') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>datetime_col<input type="text" name="datetime_col" value="{{ old('datetime_col') }}"></div>
@error('date_col')
@foreach ($errors->get('date_col') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>date_col<input type="text" name="date_col" value="{{ old('date_col') }}"></div>
@error('time_col')
@foreach ($errors->get('time_col') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>time_col<input type="text" name="time_col" value="{{ old('time_col') }}"></div>
<input type="submit" >
</form>
<br>
@isset($saved)
@if ($saved)
<div>成功しました</div>
@else
<div>失敗しました</div>
@endif
@endif
</body>
</html>
(3) /sample/resources/views/sample/updateOrm.blade.phpファイル作成
<html>
<head>
<title>sample</title>
</head>
<body>
<form action="{{ url('sample/update-orm') }}" method="post">
@csrf
@error('id')
@foreach ($errors->get('id') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>id<input type="text" name="id" value="{{ old('id') }}"></div>
@error('table2_id')
@foreach ($errors->get('table2_id') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>table2_id<input type="text" name="table2_id" value="{{ old('table2_id') }}"></div>
@error('varchar_col')
@foreach ($errors->get('varchar_col') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>varchar_col<input type="text" name="varchar_col" value="{{ old('varchar_col') }}"></div>
@error('int_col')
@foreach ($errors->get('int_col') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>int_col<input type="text" name="int_col" value="{{ old('int_col') }}"></div>
@error('datetime_col')
@foreach ($errors->get('datetime_col') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>datetime_col<input type="text" name="datetime_col" value="{{ old('datetime_col') }}"></div>
@error('date_col')
@foreach ($errors->get('date_col') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>date_col<input type="text" name="date_col" value="{{ old('date_col') }}"></div>
@error('time_col')
@foreach ($errors->get('time_col') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>time_col<input type="text" name="time_col" value="{{ old('time_col') }}"></div>
<input type="submit" >
</form>
<br>
@isset($saved)
@if ($saved)
<div>成功しました</div>
@else
<div>失敗しました</div>
@endif
@endif
</body>
</html>
(4) /sample/resources/views/sample/deleteOrm.blade.phpファイル作成
<html>
<head>
<title>sample</title>
</head>
<body>
<form action="{{ url('sample/delete-orm') }}" method="post">
@csrf
@error('id')
@foreach ($errors->get('id') as $error)
<div style="color:red;">{{ $error }}</div>
@endforeach
@enderror
<div>id<input type="text" name="id" value="{{ old('id') }}"></div>
<input type="submit" >
</form>
<br>
@isset ($deleted)
@if ($deleted)
<div>成功しました</div>
@else
<div>失敗しました</div>
@endif
@endif
</body>
</html>
動作確認
(1) http://localhost/laravelSample/sample/insert-orm
送信ボタンをクリックするとinsertが実行されます
テーブルをselectしてみると作成日時、更新日時も値が設定されています
(2) http://localhost/laravelSample/sample/update-orm
送信ボタンをクリックするとレコードが更新されます
テーブルをselectしてみると更新日時の値が更新されています
(3) http://localhost/laravelSample/sample/delete-orm
送信ボタンをクリックするとレコードが削除されます
(4) http://localhost/laravelSample/sample/select-orm
送信ボタンをクリックするとレコードがselectされます