Learn how to implement a service layer in Laravel to encapsulate business logic, reduce controller bloat, and build a more maintainable, testable application.
Previously in this course, we discussed architecting for maintainability, where we identified the dangers of controller bloat and began extracting logic into custom classes. In this lesson, we take that architectural shift further by formalizing our approach to business logic through the service layer.
In a typical Laravel application, developers often start by placing business logic directly inside controller methods. While convenient for small prototypes, this approach leads to "fat controllers" that are difficult to unit test and impossible to reuse.
When you need to trigger the same "Project Creation" logic from a web form, an API endpoint, and an Artisan command, a controller-bound implementation forces you to duplicate code. A service layer solves this by acting as the mediator between your HTTP layer (controllers) and your data layer (models/repositories).
A service layer is a set of classes that hold your application's "business rules." These classes are agnostic of the request cycle; they don't know about $request, session data, or redirects. They simply receive data, perform an action, and return a result or throw an exception.
By moving business logic into these classes, you ensure your controllers remain "thin," responsible only for:
Let's evolve our project board by creating a ProjectService. Suppose our logic requires creating a project and immediately assigning it to the authenticated user.
First, create the directory structure: app/Services. Now, define the service:
PHPnamespace App\Services; use App\Models\Project; use App\Models\User; class ProjectService { public function createProject(array $data, User $user): Project { #6A9955">// Encapsulate business logic: project creation + ownership assignment return $user->projects()->create([ 'name' => $data['name'], 'description' => $data['description'], 'is_active' => true, ]); } }
Next, inject this service into your ProjectController. Because Laravel’s service container is powerful, we can type-hint the service in the controller constructor or directly in the method.
PHPnamespace App\Http\Controllers; use App\Services\ProjectService; use Illuminate\Http\Request; class ProjectController extends Controller { protected $projectService; public function __construct(ProjectService $projectService) { $this->projectService = $projectService; } public function store(Request $request) { $validated = $request->validate([ 'name' => 'required|string|max:255', 'description' => 'nullable|string', ]); $project = $this->projectService->createProject($validated, auth()->user()); return response()->json($project, 201); } }
By doing this, the controller no longer cares how a project is created—it only cares that the ProjectService fulfills the contract. If you later decide to add logging, fire events, or notify team members upon project creation, you only update the service, and all entry points (API, Web, CLI) benefit automatically.
TaskService class in app/Services.createTask method that accepts an array of data and a Project model instance.TaskController@store method to inject TaskService and use it to handle the task creation logic instead of calling Task::create() directly.Model::create($request->all()), keep it in the controller. Use services when the logic involves multiple steps, external API calls, or complex domain rules.Service A calls Service B, which calls Service C, you might be creating a "circular dependency" or making the code hard to debug.new ProjectService() makes your code harder to mock during testing, which we will cover later in this course.The service layer is a design pattern that keeps your application maintainable as it grows. By separating business logic from HTTP concerns, you create a cleaner codebase that is easier to test and reuse. Remember: controllers handle the request/response, and services handle the "work."
Up next, we will look at the Repository Pattern Fundamentals to further decouple our services from the database layer.
Master service-oriented task management in Laravel. Learn to encapsulate task creation and user assignment logic within a service layer for cleaner code.
Read moreLearn the repository pattern to decouple your Laravel business logic from Eloquent. Master interfaces, concrete implementations, and dependency injection.
Project Board Domain Modeling
Advanced Eloquent Scopes and Accessors
Resource Controllers and API Responses
Handling API Validation and Form Requests
Implementing Middleware for API Security
Database Transactions for Data Integrity
Error Handling and Global Exceptions
Introduction to Laravel Events and Listeners
Asynchronous Processing with Queues
Job Chaining and Batching
Feature Testing Fundamentals
Mocking Services and Repositories in Tests
Testing Events and Jobs
Database Factories and Seeding
API Versioning Strategies
Advanced Request Filtering and Sorting
Handling File Uploads in REST APIs
Real-time Notifications with Broadcasting
Using Observers for Model Lifecycle Hooks
Implementing Policies for Authorization
Customizing Authentication Guards
Rate Limiting API Endpoints
Eloquent Performance Optimization
Caching Strategies for Performance
Using Traits for Code Reuse
Advanced Dependency Injection with Service Providers
Command Line Tools with Artisan
Scheduled Tasks and Cron Jobs
Integrating Third-Party Services
Handling Webhooks
Logging and Monitoring
Database Migrations Best Practices
Advanced Testing: Integration Tests
Testing API Authentication
Code Quality and Static Analysis
Project Structure for Large Applications
Environment and Configuration Management
Deploying Laravel Applications
Database Indexing Strategies
Using Value Objects
Strategy Pattern for Business Rules
Advanced Queue Monitoring
Building a Search API
Handling Concurrency and Race Conditions
API Documentation with OpenAPI
Testing with Test Doubles
Implementing Multi-Tenancy
Refactoring Legacy Code
Using Middleware for Feature Flags
Building Reusable Packages
Performance Profiling
Secure API Design
Event Sourcing Concepts