LaravelのService層を導入して可読性と保守性を高める方法
Laravelで開発を続けていると、「Controllerが肥大化してきた」「ロジックの再利用がしづらい」と感じることはありませんか?
この記事では、Service層(サービスクラス)を導入することで、アプリケーションの保守性・テスト容易性を高める方法を解説します。
Controllerが肥大化する理由
LaravelのControllerは便利ですが、ビジネスロジックやデータ加工処理を直接書き込むと、次のような問題が生じます。
- コントローラが長くなり可読性が落ちる
- 同じロジックを別のコントローラで再利用できない
- 単体テストがしづらい(外部依存が多くなる)
例:肥大化したController
class OrderController extends Controller
{
public function store(Request $request)
{
$validated = $request->validate([
'user_id' => 'required',
'items' => 'required|array',
]);
$order = new Order();
$order->user_id = $validated['user_id'];
$order->total_price = collect($validated['items'])->sum('price');
$order->save();
foreach ($validated['items'] as $item) {
OrderItem::create([
'order_id' => $order->id,
'product_id' => $item['id'],
'price' => $item['price'],
]);
}
return response()->json($order);
}
}
このように、注文作成ロジックとHTTPリクエスト処理が混在しています。
Service層を導入する
Service層を導入して、ビジネスロジックを切り出します。
ディレクトリ構成
app/
├─ Http/
│ └─ Controllers/
└─ Services/
└─ OrderService.php
Serviceクラスの例
namespace App\Services;
use App\Models\Order;
use App\Models\OrderItem;
class OrderService
{
public function createOrder(int $userId, array $items): Order
{
$order = Order::create([
'user_id' => $userId,
'total_price' => collect($items)->sum('price'),
]);
foreach ($items as $item) {
OrderItem::create([
'order_id' => $order->id,
'product_id' => $item['id'],
'price' => $item['price'],
]);
}
return $order;
}
}
Controller側のリファクタ後
class OrderController extends Controller
{
public function __construct(private OrderService $orderService) {}
public function store(Request $request)
{
$validated = $request->validate([
'user_id' => 'required',
'items' => 'required|array',
]);
$order = $this->orderService->createOrder(
$validated['user_id'],
$validated['items']
);
return response()->json($order);
}
}
Service層を導入するメリット
- Controllerが薄くなり、役割が明確になる
→ HTTPリクエストとレスポンス処理に専念できる。 - ビジネスロジックの再利用が可能
→ 同じ処理をジョブやスケジューラからも呼び出せる。 - テストが容易になる
→ Service層を単体でテスト可能。
テスト例
public function testCreateOrder()
{
$service = new OrderService();
$order = $service->createOrder(1, [
['id' => 10, 'price' => 1200],
['id' => 11, 'price' => 800],
]);
$this->assertEquals(2000, $order->total_price);
$this->assertCount(2, $order->items);
}
まとめ
Laravelはシンプルな構造でも十分動作しますが、長期的な保守を考えるとService層の導入は非常に有効です。
チーム開発や大規模化を見据えた設計を行うことで、後からの改修コストを大幅に抑えることができます。