【Laravel入門】MVC + S Serviceクラスの書き方!
今回は【Laravel入門】サービスモデルの書き方!MVC + S 居ついての紹介です。
MVC + Sとは?
LaravelのMVC(Model-View-Controller) + Serviceの構成のアーキテクチャです。
各項目について説明していきますね。
M:Model
Mとは、「Model」のことを指します。
モデルは、データベースのテーブルやそれに関連するオブジェクトを表します。
V:View
Vとは、「View」のことを指します。
ユーザーに表示される部分です。
HTML、CSS、JavaScriptなどのフロントエンドのコードがここに含まれます。
C:Controller
Cとは、「Controller」のことを指します。
ユーザーのリクエストを受け取り、モデルを操作してデータを取得し、ビューを表示するための処理を行います。
コントローラはアプリケーションのロジックを含み、モデルとビューの間の仲介役として機能します。
S:Service
MVCパターンに加えて、Laravelでは「Service」と呼ばれるレイヤーが追加して、アーキテクチャを組むことがあります。
これはビジネスロジックを格納するためのレイヤーであり、コントローラとのやりとりがメインになってきます。
これにより、コントローラが過剰に肥大化することなく、アプリケーションのロジックをよりきれいに分離することができます。
もう少し、砕いて説明しますね。
データベースのデータについてはModelが担当でしたよね?
Modelとのやり取りを行うコードを、Contrller内でデータベース関連のQuery文など書くと、
Controllerの記述が多くなり、負荷ボリュームも増え、コードの可読性が下がります。
ですが、ビジネスロジック部分だけを切り離せば、どうでしょうか?
つまり、Controllerにはデータベースとのビジネスロジック書かなければということです。
Controller以外で、細かいQueryなどの処理を記述すば、Controllerはそのロジックを使えばいいだけですよね?
それで登場するのが、「Service」クラスになります。
Serviceクラスに、データベースのビジネスロジックを記述して結果を返します。
そうすることで、ControllerはServiceクラスを呼び出して、その結果に対して、プログラム処理を書いていけばいいだけになります。
Modelの例
モデルクラスのサンプルコードです
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Notifications\Notifiable;
/**
* ユーザー情報のサービスクラス
*
*/
class User extends Authenticatable
{
use HasFactory, Notifiable;
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
}
スポンサードサーチ
Serviceの例
サービスクラスのサンプルコードです。
モデルとやり取りを行います。
<?php
namespace App\Services;
use App\Models\User;
class UserService
{
/**
* 新しいユーザーを作成します。
*
* @param array $data
* @return User
*/
public function createUser(array $data)
{
// ユーザーの作成と保存
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
/**
* 指定されたユーザーを更新します。
*
* @param User $user
* @param array $data
* @return User
*/
public function updateUser(User $user, array $data)
{
// ユーザーの更新と保存
$user->update([
'name' => $data['name'],
'email' => $data['email'],
]);
return $user;
}
/**
* 指定されたユーザーを削除します。
*
* @param User $user
* @return void
*/
public function deleteUser(User $user)
{
// ユーザーの削除
$user->delete();
}
/**
* IDによるユーザーの取得
*
* @param int $id
* @return User|null
*/
public function getUserById($id)
{
// IDによるユーザーの取得
return User::find($id);
}
/**
* 全てのユーザー情報を取得
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function getAllUsers()
{
// 全てのユーザー情報を取得
return User::all();
}
}
Controllerの例
コントローラーのサンプルコードです
<?php
namespace App\Http\Controllers;
use App\Services\UserService;
use Illuminate\Http\Request;
class UserController extends Controller
{
/** @var UserService $userService */
protected $userService;
/**
* UserControllerのインスタンスを作成します。
*
* @param UserService $userService
*/
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
/**
* 全てのユーザーを表示します。
*
* @return \Illuminate\View\View
*/
public function index()
{
$users = $this->userService->getAllUsers();
return view('users.index', compact('users'));
}
/**
* 新しいユーザー作成フォームを表示します。
*
* @return \Illuminate\View\View
*/
public function create()
{
return view('users.create');
}
/**
* 新しいユーザーを保存します。
*
* @param Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(Request $request)
{
$userData = $request->only(['name', 'email', 'password']);
$this->userService->createUser($userData);
return redirect()->route('users.index')->with('success', 'User created successfully');
}
/**
* 指定されたユーザーを表示します。
*
* @param int $id
* @return \Illuminate\View\View
*/
public function show($id)
{
$user = $this->userService->getUserById($id);
if (!$user) {
return redirect()->route('users.index')->with('error', 'User not found');
}
return view('users.show', compact('user'));
}
/**
* 指定されたユーザーの編集フォームを表示します。
*
* @param int $id
* @return \Illuminate\View\View
*/
public function edit($id)
{
$user = $this->userService->getUserById($id);
if (!$user) {
return redirect()->route('users.index')->with('error', 'User not found');
}
return view('users.edit', compact('user'));
}
/**
* 指定されたユーザーを更新します。
*
* @param Request $request
* @param int $id
* @return \Illuminate\Http\RedirectResponse
*/
public function update(Request $request, $id)
{
$userData = $request->only(['name', 'email']);
$user = $this->userService->getUserById($id);
if (!$user) {
return redirect()->route('users.index')->with('error', 'User not found');
}
$this->userService->updateUser($user, $userData);
return redirect()->route('users.index')->with('success', 'User updated successfully');
}
/**
* 指定されたユーザーを削除します。
*
* @param int $id
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy($id)
{
$user = $this->userService->getUserById($id);
if (!$user) {
return redirect()->route('users.index')->with('error', 'User not found');
}
$this->userService->deleteUser($user);
return redirect()->route('users.index')->with('success', 'User deleted successfully');
}
}
スポンサードサーチ
Viewの例
ビューは用途に合わせて、ビュー毎に記述しています。
ユーザーの一覧表示用ビュー (index.blade.php)
ユーザーの一覧表示用ビューのビューです。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Users List</title>
</head>
<body>
<h1>Users List</h1>
<!-- 成功メッセージを表示 -->
@if(session('success'))
<div style="color: green;">{{ session('success') }}</div>
@endif
<!-- エラーメッセージを表示 -->
@if(session('error'))
<div style="color: red;">{{ session('error') }}</div>
@endif
<!-- 新しいユーザー作成ページへのリンク -->
<a href="{{ route('users.create') }}">Create New User</a>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<!-- ユーザーリストを表示 -->
@foreach($users as $user)
<tr>
<td>{{ $user->id }}</td>
<td>{{ $user->name }}</td>
<td>{{ $user->email }}</td>
<td>
<!-- ユーザー編集ページへのリンク -->
<a href="{{ route('users.edit', $user->id) }}">Edit</a>
<!-- ユーザー削除フォーム -->
<form action="{{ route('users.destroy', $user->id) }}" method="POST" style="display:inline;">
@csrf
@method('DELETE')
<button type="submit" onclick="return confirm('Are you sure?')">Delete</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</body>
</html>
ユーザー作成用ビュー (create.blade.php):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Create User</title>
</head>
<body>
<h1>Create User</h1>
<!-- 新しいユーザー作成フォーム -->
<form action="{{ route('users.store') }}" method="POST">
@csrf
<label for="name">Name:</label><br>
<input type="text" id="name" name="name"><br>
<label for="email">Email:</label><br>
<input type="email" id="email" name="email"><br>
<label for="password">Password:</label><br>
<input type="password" id="password" name="password"><br>
<button type="submit">Create</button>
</form>
</body>
</html>
ユーザーの更新用ビュー (edit.blade.php)
ユーザーの更新用のビューです。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Edit User</title>
</head>
<body>
<h1>Edit User</h1>
<!-- ユーザー編集フォーム -->
<form action="{{ route('users.update', $user->id) }}" method="POST">
@csrf
@method('PUT')
<label for="name">Name:</label><br>
<input type="text" id="name" name="name" value="{{ $user->name }}"><br>
<label for="email">Email:</label><br>
<input type="email" id="email" name="email" value="{{ $user->email }}"><br>
<button type="submit">Update</button>
</form>
</body>
</html>
ルーティング
ルーティングを「routes/web.php」に記述します。
ルーティングを記述しなければ、各メソッドは動かないので、実装しながら確認していきましょう。
use App\Http\Controllers\UserController;
Route::get('/users', [UserController::class, 'index'])->name('users.index');
Route::get('/users/create', [UserController::class, 'create'])->name('users.create');
Route::post('/users', [UserController::class, 'store'])->name('users.store');
Route::get('/users/{id}', [UserController::class, 'show'])->name('users.show');
Route::get('/users/{id}/edit', [UserController::class, 'edit'])->name('users.edit');
Route::put('/users/{id}', [UserController::class, 'update'])->name('users.update');
Route::delete('/users/{id}', [UserController::class, 'destroy'])->name('users.destroy');