Author: GPT-4o
In Laravel, Service Pattern and Repository Pattern are two common design patterns used to structure the business logic and data layer. Each pattern has its purpose and responsibilities, and they can even complement each other.
The Service Pattern is used to encapsulate business logic, making it reusable and independent of the controller or other layers. This is where you place the "what needs to be done" logic, such as calculations, complex workflows, or coordination of multiple repositories or APIs.
- Focuses on business logic.
- Keeps controllers thin by moving complex logic out.
- Typically interacts with one or more repositories or models.
- Promotes separation of concerns by isolating the business rules.
// Services/UserService.php
namespace App\Services;
use App\Repositories\UserRepository;
class UserService
{
protected $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function registerUser($data)
{
// Business logic
$data['password'] = bcrypt($data['password']);
return $this->userRepository->create($data);
}
}
use App\Services\UserService;
class UserController extends Controller
{
protected $userService;
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
public function register(Request $request)
{
$user = $this->userService->registerUser($request->all());
return response()->json($user);
}
}
The Repository Pattern is used to abstract the data access layer, making the application independent of the underlying database or ORM (like Eloquent). It provides a consistent API for data operations, such as find
, create
, or delete
.
- Focuses on data access.
- Acts as a mediator between the database (or ORM) and the application.
- Simplifies unit testing by mocking the repository.
- Promotes separation of concerns by isolating database logic.
// Repositories/UserRepository.php
namespace App\Repositories;
use App\Models\User;
class UserRepository
{
protected $model;
public function __construct(User $model)
{
$this->model = $model;
}
public function find($id)
{
return $this->model->find($id);
}
public function create($data)
{
return $this->model->create($data);
}
public function update($id, $data)
{
$user = $this->find($id);
return $user->update($data);
}
}
use App\Repositories\UserRepository;
class UserService
{
protected $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function getUserById($id)
{
return $this->userRepository->find($id);
}
}
Feature | Service Pattern | Repository Pattern |
---|---|---|
Purpose | Encapsulates business logic and workflows. | Encapsulates database and data access logic. |
Focus | "What needs to be done" (business rules). | "How to fetch/store data" (data operations). |
Dependency | Often depends on repositories or models. | Depends on models or raw queries. |
Scope | Handles multiple repositories or external services. | Handles a single model or data source. |
Testability | Easier to test business logic independently. | Simplifies testing of data access logic. |
Example Usage | User registration, payment processing. | Fetching users, paginated queries. |
-
Service Pattern:
- When you have complex business rules or workflows.
- To decouple business logic from controllers.
- For logic that involves multiple repositories or external services.
-
Repository Pattern:
- When you want to abstract data access from models.
- For easier swapping of database/ORM or mocking in tests.
- To maintain cleaner, reusable, and centralized data access logic.
Yes! They often complement each other.
- The Service Layer focuses on what needs to be done (business logic).
- The Repository Layer focuses on how to interact with the database.
For example:
- A
UserService
callsUserRepository
to handle database operations. - The controller interacts only with
UserService
, keeping it thin and clean.