Back to Blog
Lesson 44 of the Laravel Fundamentals: From Zero to Your First App course
LaravelJune 25, 20263 min read

Task Manager: Refactoring for Clean Code

Learn to refactor your Task Manager by moving business logic into Service classes, cleaning up controllers, and simplifying your Blade templates.

LaravelPHPRefactoringClean CodeServicesArchitecturebackend

Previously in this course, we covered Task Manager: Completing CRUD Functionality in Laravel. We built a functional, secure application, but as our logic grows, our controllers are starting to look a bit crowded.

In this lesson, we are applying refactoring to achieve clean code by extracting business logic from controllers into dedicated Service classes. This separation of concerns ensures your controllers stay thin, focused only on handling the HTTP request and returning a response.

Why Refactor Your Task Manager?

As you add more features to your Task Manager, your controller methods often become "god methods"—they handle validation, database queries, business rules, and response formatting. This makes the code hard to test and even harder to maintain.

By moving business logic into a "Service" layer, we gain:

  1. Reusability: You can call the same logic from a controller, an Artisan command, or a background job.
  2. Testability: It is much easier to write unit tests for a Service class than for a controller that requires an HTTP request context.
  3. Readability: Your controllers become thin "traffic cops" that simply route traffic to the right place.

Moving Logic to Services

Let's look at a common task: creating a new task. Currently, your controller might be handling the database insertion and any side effects (like logging or sending notifications).

Create a new directory at app/Services and create a TaskService.php file:

PHP
namespace App\Services;

use App\Models\Task;
use Illuminate\Support\Facades\Auth;

class TaskService
{
    public function createTask(array $data): Task
    {
        return Auth::user()->tasks()->create([
            'title' => $data['title'],
            'description' => $data['description'],
            'priority' => $data['priority'] ?? 'medium',
        ]);
    }
}

Now, inject this service into your TasksController. Instead of the controller knowing how to build a task, it just asks the service to do it.

PHP
#6A9955">// In TasksController.php
public function store(StoreTaskRequest $request, TaskService $service)
{
    $service->createTask($request->validated());

    return redirect()->route('tasks.index')->with('success', 'Task created!');
}

Simplifying Blade Templates

Clean code isn't just for your PHP classes; it extends to your views. If you find yourself repeating logic in your Blade files—like calculating CSS classes based on task priority—extract that logic.

Instead of writing complex @if statements inside your loop, define a method on your Task model to handle the presentation logic:

PHP
#6A9955">// In App\Models\Task.php
public function getPriorityColorAttribute(): string
{
    return match($this->priority) {
        'high' => 'text-red-600',
        'low' => 'text-green-600',
        default => 'text-gray-600',
    };
}

Now, your Blade template becomes significantly cleaner and easier to read:

HTML
style="color:#808080"><style="color:#4EC9B0">span class="{{ $task->priority_color }}">
    {{ ucfirst($task->priority) }}
style="color:#808080"></style="color:#4EC9B0">span>

Hands-on Exercise

  1. Create the Service: Generate an app/Services/TaskService.php file.
  2. Refactor: Identify one controller method (like update or delete) that contains more than just a simple Eloquent call. Move that logic into your new TaskService.
  3. Clean the View: Check your index.blade.php. If you are using complex logic to display task status or priority, move that logic into a helper method or an accessor within the Task model.

Common Pitfalls

  • Over-Engineering: Don't create a Service class for every single action. If a controller method is just Task::create($request->all()), keep it in the controller. Use Services for complex workflows.
  • Injecting Services in the Wrong Place: Remember that you can type-hint classes in your controller methods, and Laravel’s Service Container will automatically inject them for you.
  • Ignoring Eloquent: Don't move basic database queries into Services. Eloquent is designed to handle those. Use Services for business workflows (e.g., "When a task is completed, notify the manager, update the history log, and archive the file").

Recap

Refactoring for clean code is an iterative process. By moving business logic into Services, keeping your controllers thin, and leveraging Model accessors for view-level logic, you ensure your Task Manager remains maintainable as it evolves. You have successfully separated your concerns, making your application more robust and easier to test.

Up next: We will begin writing our first automated tests to ensure our refactored code works exactly as expected.

Similar Posts