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 10 Apexcharts Bar Chart Example
Laravel 10 Apexcharts Bar Char...

In this article, we will see the laravel 10 apexcharts bar chart example. Here, we will learn about how to create a bar...

Read More

May-24-2023

Introduction of Node.js Modules
Introduction of Node.js Module...

In this tutorial I will give you information about Introduction of Node.js Modules. Node.js modules provide a way t...

Read More

Sep-10-2021

How To Create Dynamic Pie Chart In Laravel 8
How To Create Dynamic Pie Char...

In this article, we will see how to create a dynamic pie chart in laravel 8. Pie charts are used to represent...

Read More

Oct-02-2020

Angular 15: Unleashing Modern Web Development
Angular 15: Unleashing Modern...

Angular 15 is the latest iteration of one of the most popular JavaScript frameworks for building dynamic web application...

Read More

Jun-05-2023