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
Laravel 8 Group By Query Example
Laravel 8 Group By Query Examp...

In this example we will see laravel 8 group by query example. how to use group by in laravel 8. As you might expect...

Read More

Nov-29-2021

How to Search Records using Laravel 10 Livewire
How to Search Records using La...

Hey developers! Today, I'm excited to walk you through an incredibly powerful feature in Laravel 10: searching...

Read More

Dec-27-2023

Integrating ChatGPT with Node and Vue
Integrating ChatGPT with Node...

In a world where technology and human interaction blend seamlessly, artificial intelligence (AI) holds incredible potent...

Read More

Jul-17-2023

How To Generate PDF File In Laravel 10
How To Generate PDF File In La...

In this article, we will see how to generate a pdf file in laravel 10. Here, we will learn about laravel 10 ge...

Read More

Mar-10-2023