Laravel Eloquentでデータを追加・更新・削除を行う
前回はusersテーブルのデータを、Eloquentモデルを使って取得し表示するということを行いました。
今回はユーザーデータを新規で追加したり、すでにあるデータを更新したり削除したりしていきましょう。
これが出来れば簡単な動きアプリケーションは作成できます。
以下の流れで行っていきます
- 新規ユーザーの登録
- ユーザー詳細ページの作成
- 一覧に詳細ページへのリンクを付ける
- 詳細ページでユーザーの更新
- 詳細ページでユーザーの削除
それでは一つずつ実装していきましょう。
新規ユーザーの登録
一覧ページで、新規ユーザーを登録するフォームから作成していきます。
resources/views/users/index.blade.php
<div>
<div>
<form action="/users" method="post">
{{ csrf_field() }}
<div>
<label>名前</label>
<input type="text" name="name" />
</div>
<div>
<label>年齢</label>
<input type="number" name="age" />
<input type="submit" value="登録" />
</div>
</form>
</div>
</div>
inputのname属性はcontroller側で使うので、name・ageとDBと同じものにしておきます。
ここで {{ csrf_field() }} という記述がありますが、これは一時的なトークンを生成してhiddenでinputに挿入するものです(追加、更新、削除で使用)。
これはセキュリティのために行われるものですが、なぜそれが必要になるかはここを参照してください。
foreachでユーザー一覧を表示しているコードは省略(前回の記事参照)
actionを /users 、methodをpostとしているので、routerは以下のような設定にします。
routes/web.php
Route::post('/users', [UserController::class, 'create']);
GETリクエスト比べると、Route::postになっているだけです。これでacitonがpostのリクエストを受け付けられるようになります。
controllerのメソッドは以下のように記述します。
app/Http/Controllers/UserController.php
public function create(Request $request)
{
User::create([
"name" => $request->name,
"age" => $request->age,
]);
return redirect("users");
}
これがUserのEloquentモデルを通してusersテーブルにデータを書き込んでいるコードです。
Eloquentモデルではcreateというメソッドが備えられていて、連想配列でusersテーブルのカラム名=>値とすることで追加(insert)を行っています。
今回はformでnameとageを指定しているので、それぞれEloquentモデルでも指定して、新規追加を行っています。
最後の行のredirectは、引数内のパスにリダイレクトする処理です。つまり登録処理が終わったら /users に再アクセスされます。
Userクラスは以下のように変更しておいてください。
app/Http/Models/User.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
/**
* **@mixin** Builder
*/
class User extends Model
{
const UPDATED_AT = null;
protected $fillable = [
'name',
'age'
];
}
const UPDATED_AT = null; はLaravelではデフォルトでupdated_atカラムに対してデータ入れようとするのですが、今回のusersテーブルはupdated_atが存在しないので、その処理を無効化するということをしてます。
また$fillableに定義した配列では、Eloquentで操作可能なカラムをしていしています。これによりnameとageに対して書き込み処理をすることが可能になります。
実際に/usersにアクセスして、
名前と年齢を入力し登録ボタンを押すと、新しく一覧に追加されるはずです。↓
ユーザー詳細ページの作成
次はユーザーの詳細ページを作成していきましょう。
まずは、routerに以下を追加します。
routes/web.php
Route::get('/users/{userId}', [UserController::class, 'show']);
今までのルーティングと違って少し特殊で、pathに {userId} と入っています。
ユーザーの詳細ページは /users/1 や /users/2 といったURLでアクセスするようにするのですが、この1とか2という数字を取得する必要があります。
そこで {} を使って変数名 userId とすることで、controller側でこれが使えるようになります。
以下がユーザー詳細表示用のcontrollerのメソッドですが、 $request->userId のようにすることで、routerで指定したuserIdに数字が取得できます。
ddを使って、dd($request->userId);として、 /users/1 にアクセスすると1が表示されるので試してみてください。
app/Http/Controllers/UserController.php
public function show(Request $request)
{
$user = User::find($request->userId);
return view("users/show", ["user" => $user]);
}
ここではidが1のユーザーを取得して、その情報をusers/showというviewに渡していますね。
resources/views/users/show.blade.php
<div>
<div>名前: {{ $user->name }}</div>
<div>年齢: {{ $user->age }}</div>
</div>
ユーザーの詳細を表示してみます。以下のように表示されれば成功です。
一覧に詳細ページへのリンクを付ける
一覧から詳細ページにリンクさせてみます。今のままだとidをURLに直接打たないといけないので、使いづらいからです。
といっても非常に簡単で、$usersにはidが含まれているので、それを使ってaタグでリンクを作成してあげればOKです(追加フォームは省略しています)。
resources/views/users/index.blade.php
@foreach($users as $user)
<div>
{{ $user->name }}, 年齢は {{ $user->age }}歳です。
<a href="/users/{{ $user->id }}">編集</a>
</div>
@endforeach
以下のように表示されていれば問題ありません。実際に編集リンクをクリックすると、該当のユーザー詳細ページ遷移します。
詳細ページでユーザーの更新
次は、ユーザーの更新を行います。
先程作った詳細ページをフォーム化して、ユーザー情報を更新できるようにしていきます。
viewの変更
このような画面を作ります。URLはユーザーIDである7が入っています。この7という情報から、DBに保存されているデータを取得してフォームに表示していきます。
詳細ページのview配下のように書き換えてください。
resources/views/users/show.blade.php
<div>
<div>
<form action="/users" method="post">
@method('PUT')
{{ csrf_field() }}
<input type="hidden" name="userId" value="{{ $user->id }}" />
<div>
<label>名前</label>
<input type="text" name="name" value="{{ $user->name }}" />
</div>
<div>
<label>年齢</label>
<input type="number" name="age" value="{{ $user->age }}" />
<input type="submit" value="更新" />
</div>
</form>
</div>
</div>
少し記述が一つずつ説明します。
@method('PUT')
formのactionとmethodについてですが、これはユーザー新規追加時と全く同じです。これでは新規追加の処理が実行されそうですが、
@method('PUT')という記述述により、methodをpostからputに上書きしています。
実際のHTMLは以下のようになっています。
formタグのactionはgetとpostしかサポートしていないので、直接記述する方法はありません。ですが、Laravelの @method を使うと上記のHTMLが差し込まれ上書きされると言った具合です。
{{ csrf_field() }} は新規追加時と同様セキュリティのためです。
これはどのユーザーを更新するべきなのか判断するために使います。idを指定することで、controller側で該当のユーザーを検索し、入力された値で更新すると言った具合です。
すでに保存されているデータをデフォルト値として表示
以下の記述は、フォームにデフォルト値を設定するためのもです。新規追加時とほとんど一緒ですが、valueにnameやageを設定していることで、すでに入力済み(保存済み)のデータということがより分かりやすくなります。
更新処理のルーティング
routerは以下の様にしておきます。
routes/web.php
Route::put('/users', [UserController::class, 'update']);
formでPUTを指定していたので、ここでもputとしています。
controllerで更新処理記述
いよいよ更新処理です。これも結構簡単に記述することができます。
app/Http/Controllers/UserController.php
public function update(Request $request)
{
$user = User::find($request->userId);
$user->update([
"name" => $request->name,
"age" => $request->age,
]);
return redirect("/users");
}
まず でuserIdを送信していたので、$request->userIdを使って該当のユーザーIDを取得して、findで検索をかけます。
その後、$userには更新対象のユーザー情報が入っており、updateメソッドに連想配列を渡すことで、更新処理完了します。
$userにはidがすでに入っている状態なので、nameとageだけを指定してあげれば、更新可能です。
処理が完了したら、/usersにリダイレクトして、一覧ページを表示するようにしています。
名前と年齢を変更して更新ボタンを押すと↓のように更新されていることが確認できます。
ちゃんとbob2になっており、年齢も42に更新されていますね。
詳細ページでユーザーの削除
いよいよ最後のユーザー削除を実装していきます。
削除機能はユーザー詳細ページに追加します。以下のようになります。
まずユーザー詳細のviewに追記をしていきます(更新フォーム部分は省略)。
resources/views/users/show.blade.php
<form action="/users" method="post">
@method('DELETE')
{{ csrf_field() }}
<input type="hidden" name="userId" value="{{ $user->id }}"/>
<input type="submit" value="削除"/>
</form>
更新時と同様に @method('DELETE') でmethodを上書きしていき、 {{ csrf_field() }} でセキュリティ対策を行います。
削除処理は、ユーザーのIDさえ分かれば、実行できるので以下が重要です。
これを送信して、該当ユーザーを検索し削除していきます。
routerは以下になります。
routes/web.php
Route::delete('/users', [UserController::class, 'delete']);
controllerは以下になります。
app/Http/Controllers/UserController.php
public function delete(Request $request)
{
$user = User::find($request->userId);
$user->delete();
return redirect("/users");
}
更新時と同様にユーザーを取得します。削除なのでdelete()を呼んでいます。
削除処理が完了したら、/usersにリダイレクトさせています。
削除ボタンをクリックして以下のようにbob2が一覧から消えていることを確認しましょう。
ここまで、Laravelを使ったデータの追加、更新、削除が行えるようになりました。
こでCRUD処理はバッチリだと思いますので、色々テーブルを変えたりして試してみると良いでしょう。
ここまで出来た方は小さなアプリケーションであれば作れるようになっているはずです。
ただ今は名前や年齢が未入力の場合や、DB定義以上の文字列を入力された場合も処理を受け付けてしまいます。試しに未入力で登録をしようとすると以下のようなエラーが出ます。
これはDBのusersテーブルのnameカラムは未入力(null)を許可していないので、入力しろとDBに言われています。
DBではこのように弾かれるのですが、アプリケーションの利用者にこのようなエラーを出すとビックリしてしまうと思います。なので適切なメッセージをだしたり、DBの処理を呼ぶ前に事前にチェックしたいものです。
このチェックをバリデーションと呼び、バリデーションではアプリケーション提供者が意図する形式であることを保証することができます。
次回は簡単なバリデーションを作成して、最低限安全でユーザーに優しいアプリケーションに改良していきましょう。