Creating Modular Laravel Applications with Domain-Driven Design (DDD)

Websolutionstuff | Sep-27-2024 | Categories : Laravel

In this guide, I’ll explain how to structure a Laravel project using Domain-Driven Design (DDD) principles to create modular and maintainable applications. DDD allows you to divide complex applications into different layers and modules based on the business logic and domain.

This helps in keeping the code clean, easy to understand, and scalable. By the end of this article, you’ll have a solid understanding of how to apply DDD concepts in Laravel with examples of folder structures, service layers, and aggregates.

Creating Modular Laravel Applications with Domain-Driven Design (DDD)

 

Step 1: Create Domain and Application Layers

The first step in applying DDD is to split the application into layers that reflect the domain and business logic. These typically include a Domain and an Application layer.

Create folders inside the app/ directory for Domain and Application:

app/
    ├── Application/
    └── Domain/

 

Step 2: Define Entities in the Domain Layer

In DDD, entities represent core business objects. For instance, in an e-commerce application, an Order could be an entity.

Create an Order entity inside the Domain folder:

app/Domain/Entities/Order.php

namespace App\Domain\Entities;

class Order
{
    private $id;
    private $customer;
    private $products = [];
    
    public function __construct($id, $customer, $products)
    {
        $this->id = $id;
        $this->customer = $customer;
        $this->products = $products;
    }

    public function getTotal(): float
    {
        return array_sum(array_map(fn($product) => $product->price, $this->products));
    }
}

 

Step 3: Define Aggregates

An aggregate is a collection of related entities that must be handled as a single unit. For example, an Order aggregate could include the Customer and Product entities.

app/Domain/Aggregates/OrderAggregate.php

namespace App\Domain\Aggregates;

use App\Domain\Entities\Order;
use App\Domain\Entities\Customer;

class OrderAggregate
{
    private $order;
    private $customer;

    public function __construct(Order $order, Customer $customer)
    {
        $this->order = $order;
        $this->customer = $customer;
    }

    public function placeOrder(): void
    {
        // Place the order logic here
    }
}

 

Step 4: Create Repositories for Data Access

Repositories abstract the data layer and provide methods to interact with the data, separating the logic from the domain.

app/Domain/Repositories/OrderRepository.php

namespace App\Domain\Repositories;

use App\Domain\Entities\Order;

interface OrderRepository
{
    public function save(Order $order): void;
    public function findById($id): ?Order;
}

 

Step 5: Implement Services in the Application Layer

Service classes in the Application layer handle the application logic and interact with repositories.

app/Application/Services/OrderService.php

namespace App\Application\Services;

use App\Domain\Repositories\OrderRepository;
use App\Domain\Entities\Order;

class OrderService
{
    private $orderRepository;

    public function __construct(OrderRepository $orderRepository)
    {
        $this->orderRepository = $orderRepository;
    }

    public function createOrder($customer, $products)
    {
        $order = new Order(uniqid(), $customer, $products);
        $this->orderRepository->save($order);
        return $order;
    }
}

 

Step 6: Controllers for Communication

Finally, controllers are responsible for handling HTTP requests and passing them to the service layer.

app/Http/Controllers/OrderController.php

namespace App\Http\Controllers;

use App\Application\Services\OrderService;
use Illuminate\Http\Request;

class OrderController extends Controller
{
    private $orderService;

    public function __construct(OrderService $orderService)
    {
        $this->orderService = $orderService;
    }

    public function create(Request $request)
    {
        $customer = $request->input('customer');
        $products = $request->input('products');
        $order = $this->orderService->createOrder($customer, $products);

        return response()->json($order);
    }
}

 

Step 7: Folder Structure Overview

Here’s what the final folder structure looks like:

app/
    ├── Application/
    │   └── Services/
    │       └── OrderService.php
    ├── Domain/
    │   ├── Aggregates/
    │   │   └── OrderAggregate.php
    │   ├── Entities/
    │   │   └── Order.php
    │   └── Repositories/
    │       └── OrderRepository.php
    └── Http/
        └── Controllers/
            └── OrderController.php

 


You might also like:

Recommended Post
Featured Post
Skype Screen Sharing Not Working Ubuntu In 22.04
Skype Screen Sharing Not Worki...

In this article, we will see skype screen sharing is not working in ubuntu 22.04. When you install skype in ubuntu...

Read More

Feb-15-2023

Laravel 11 Reverb Real-Time Notifications
Laravel 11 Reverb Real-Time No...

Hello, laravel web developers! In this article, we'll see how to send real-time notifications in laravel 11 usi...

Read More

Sep-09-2024

Next Previous Link Button Pagination in Laravel
Next Previous Link Button Pagi...

Today we will learn next previous link button pagination in laravel, Using paginate method you can easily create paginat...

Read More

Jun-14-2021

Laravel 11 Socialite Login with Slack Account
Laravel 11 Socialite Login wit...

Hello, laravel web developers! In this article, we'll see how to Socialite login with Slack in laravel 11. In l...

Read More

Aug-16-2024