You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel 5.5中使用服务层,实现控制器与业务逻辑分离?

How to Separate Business Logic from Controllers in Laravel 5.5 Using Interface-Service Pattern

Hey there! Great call prioritizing clean separation of concerns by moving business logic out of your controllers—this makes your code way more testable, maintainable, and scalable, just like the ASP.NET MVC pattern you're familiar with. Let's break down exactly how to implement this in Laravel 5.5:

1. Define Service Interfaces

First, create interfaces that outline the contract for your business logic. Interfaces let you swap out implementations later without changing controller code (perfect for testing or future updates).

Create a new directory app/Contracts to store your interfaces. For example, if you're handling user-related logic:

// app/Contracts/UserServiceInterface.php
namespace App\Contracts;

interface UserServiceInterface
{
    public function createUser(array $data);
    public function updateUser(int $id, array $data);
    public function deleteUser(int $id);
    public function getUserById(int $id);
}

This interface defines what methods any user service implementation must provide—no details about how the logic works, just what needs to be done.

2. Implement the Service

Next, create a concrete service class that implements the interface. This is where all your business logic lives. Create an app/Services directory for these classes:

// app/Services/UserService.php
namespace App\Services;

use App\Contracts\UserServiceInterface;
use App\User;
use Illuminate\Support\Facades\Hash;

class UserService implements UserServiceInterface
{
    public function createUser(array $data)
    {
        // Business logic: validate data, hash password, create user
        return User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => Hash::make($data['password']),
        ]);
    }

    public function updateUser(int $id, array $data)
    {
        $user = User::findOrFail($id);
        
        // Business logic: check permissions, update only allowed fields
        $user->update([
            'name' => $data['name'] ?? $user->name,
            'email' => $data['email'] ?? $user->email,
        ]);
        
        return $user;
    }

    public function deleteUser(int $id)
    {
        $user = User::findOrFail($id);
        // Business logic: prevent deleting admin users
        if ($user->is_admin) {
            throw new \Exception("Cannot delete admin user");
        }
        $user->delete();
        return true;
    }

    public function getUserById(int $id)
    {
        return User::findOrFail($id);
    }
}

Notice how all the heavy lifting (password hashing, permission checks, validation rules) is here—not in the controller.

3. Bind Interface to Implementation in Service Container

Laravel's service container needs to know which concrete class to use when you request an interface. Open app/Providers/AppServiceProvider.php and add the binding in the register method:

// app/Providers/AppServiceProvider.php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Contracts\UserServiceInterface;
use App\Services\UserService;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->bind(UserServiceInterface::class, UserService::class);
    }
}

This tells Laravel: "Whenever someone asks for UserServiceInterface, give them an instance of UserService."

4. Inject the Service into Controllers

Now you can inject the interface into your controllers via dependency injection. Your controller will only handle HTTP requests and responses—no business logic!

// app/Http/Controllers/UserController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Contracts\UserServiceInterface;

class UserController extends Controller
{
    private $userService;

    // Inject the interface via constructor
    public function __construct(UserServiceInterface $userService)
    {
        $this->userService = $userService;
    }

    public function store(Request $request)
    {
        // Controller only handles request validation and response
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:8',
        ]);

        $user = $this->userService->createUser($validated);

        return response()->json($user, 201);
    }

    public function update(Request $request, int $id)
    {
        $validated = $request->validate([
            'name' => 'nullable|string|max:255',
            'email' => 'nullable|string|email|max:255|unique:users,email,'.$id,
        ]);

        try {
            $user = $this->userService->updateUser($id, $validated);
            return response()->json($user);
        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 400);
        }
    }
}

Bonus Tips

  • Keep Services Focused: Each service should handle one domain (e.g., UserService, OrderService)—avoid "god services" that do everything.
  • Testability: Since you're using interfaces, you can easily mock the service in unit tests to isolate controller logic.
  • Repository Pattern (Optional): For complex data access, pair this with a repository pattern to separate database logic from services too—though for simpler apps, the service layer can interact directly with models.

That's it! You've now got a clean separation between controllers (HTTP layer) and business logic (service layer), just like ASP.NET MVC's interface-service approach.

内容的提问来源于stack exchange,提问作者Joshua Kisanga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:56:25