Skip to content

🏗️ Architecture

It is highly recommended to fully understand this package before diving into the Laravel library. The main purpose of this package is to follow as closely as possible to the SOLID principles by Robert C. Martin.

SOLID

S - Single-responsibility Principle

O - Open-closed Principle

L - Liskov Substitution Principle

I - Interface Segregation Principle

D - Dependency Inversion Principle

image

There are 3 main folders of this packages. Contratcs, Repositories & Services.

Contratcs

In the context of PHP development, the term "contracts" generally refers to interfaces. An interface in PHP specifies what methods a class must implement, without having to define how these methods are handled.

Examples

Simple Example of Using Contracts

Let's consider a simple example of a payment system where you can process payments through different methods (like PayPal, Credit Card, etc.).

Step 1: Define the Contract

First, you define an interface that all payment methods will implement:

php
interface PaymentGatewayInterface {
    public function charge($amount);
}

Step 2: Implement the Contract

Next, create classes that implement this interface. Each class will have its own implementation of the charge method:

php
class PayPal implements PaymentGatewayInterface {
    public function charge($amount) {
        // Logic to charge via PayPal
        echo "Charging $amount using PayPal.";
    }
}

class CreditCard implements PaymentGatewayInterface {
    public function charge($amount) {
        // Logic to charge via Credit Card
        echo "Charging $amount using a Credit Card.";
    }
}

Step 3: Use the Contract

Finally, you use the interface in your application. This allows you to write code that is independent of the specific payment methods:

php
function processPayment(PaymentGatewayInterface $paymentMethod, $amount) {
    $paymentMethod->charge($amount);
}

// Client code
$paypal = new PayPal();
processPayment($paypal, 50);  // Outputs: Charging 50 using PayPal.

$creditCard = new CreditCard();
processPayment($creditCard, 75);  // Outputs: Charging 75 using a Credit Card.

In this way, you can add new payment methods without changing the code that processes the payments. This approach adheres to the SOLID principles, enhancing the design and maintainability of your application.

Repositories

Repositories in PHP, particularly within the Laravel framework, serve as an abstraction layer between the data access logic and the business logic of the application. They implement the Repository Pattern, which involves creating a contract (interface) for repository classes that handle data operations. This abstraction allows the application to manage data persistence more flexibly and promotes cleaner, more maintainable code that adheres to the SOLID principles, especially the Single Responsibility Principle and Dependency Inversion Principle.

Examples

Simple Example of Using Repositories

Consider a simple example where you manage users in an application.

Step 1: Define the Contract

First, define an interface for the repository that outlines the methods for accessing user data:

php
interface UserRepositoryInterface {
    public function getAll();
    public withoutEmail();
}

Step 2: Implement the Contract

Implement this interface in a concrete class that will interact with the data source (e.g., a database):

php
class EloquentUserRepository implements UserRepositoryInterface {
    public function getAll() {
        return User::all();
    }

    public function withoutEmail() {
        return User::whereNull('email')->get();
    }
}

Step 3: Use the Repository in Business Logic

Instead of using the Eloquent model directly in your business logic, use the repository:

php
class UserService {
    protected $userRepository;

    public function __construct(UserRepositoryInterface $userRepository) {
        $this->userRepository = $userRepository;
    }

    public function fetchAllUsers() {
        return $this->userRepository->getAll();
    }

    public function fetchUsersWithoutEmail() {
        return $this->userRepository->withoutEmail();
    }
}

Integrating with Laravel

In Laravel, you can bind interfaces to concrete classes in the service container, allowing Laravel to automatically resolve these dependencies:

php
// Within a ServiceProvider
public function register() {
    $this->app->bind(
        UserRepositoryInterface::class,
        EloquentUserRepository::class
    );
}

No Worries

Aim Admin handles interface binding automatically.

Services

In PHP development, particularly in frameworks like Laravel, "services" refer to classes that encapsulate specific business logic of an application. These service classes are designed to handle operations that involve business rules and calculations, interacting with data through repositories or models. By defining services, you separate the concerns of data access and business logic.

Details

Simple Example of Using Services

Let's consider an example where you have a service in a Laravel application that manages user profiles

Step 1: Define the Service Interface

First, Implement this interface in a concrete class that will interact with the service.

php
interface UserProfileServiceInterface {
    public function createUserProfile($userData);
}

Step 2: Create a service class

Create a service class that will contain the business logic related to user profiles:

php
class UserProfileService  implements UserProfileServiceInterface{
    protected $userRepository;

    public function __construct(UserRepositoryInterface $userRepository) {
        $this->userRepository = $userRepository;
    }

    public function createUserProfile($userData) {
        // Business logic to validate and prepare user data
        $this->validateUserData($userData);
        return $this->userRepository->create($userData);
    }

    private function validateUserData($data) {
        // Perform validation on user data
        if (empty($data['email'])) {
            throw new \Exception("Email is required");
        }
    }
}

Step 3: Use the Service in Controllers

In your controller, you can inject this service and use it to handle requests related to user profiles:

php
class UserProfileController extends Controller {
    protected $userProfileService;

    public function __construct(UserProfileServiceInterface $userProfileService) {
        $this->userProfileService = $userProfileService;
    }

    public function store(Request $request) {
        try {
            $profile = $this->userProfileService->createUserProfile($request->all());
            return response()->json($profile, 201);
        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 400);
        }
    }
}

Integrating with Laravel's Service Container

Laravel's service container can automatically resolve service dependencies, making it easy to manage and inject services:

php
// Within a ServiceProvider
public function register() {
    $this->app->bind(
        UserProfileService::class,
        function ($app) {
            return new UserProfileService($app->make(UserRepositoryInterface::class));
        }
    );
}

No Worries

Aim Admin resolve service dependencies automatically.

How it works with the Request Life Cycle

Laravel Request Life Cycle

bash
        +--------------------+
        | User Request       | (Browser)
        +--------------------+
                    |
                    v
        +--------------------+
        | Web Server         | (e.g. nGinx/Apache) 
        +--------------------+
                    |
                    v
        +--------------------+
        | public/index.php   | (Entry Point)
        +--------------------+
                    |
                    v
        +--------------------+
        | Bootstrap Process  |
        | (Loads app, etc.)  |
        +--------------------+
                    |
                    v
        +--------------------+
        | Route Matching     |
        | (Finds the route)  |
        +--------------------+
                    |
                    v
        +--------------------+ 
        | Middleware Stack   | (Optional)
        +--------------------+
                    |
                    v
        +--------------------+
        | Controller         |
        | (Handles request)  |
        +--------------------+
                    |
                    v
        +--------------------+ 
        | Model              |(Optional)
        | (Data Access)      |
        +--------------------+
                    |
                    v
        +--------------------+
        | Controller         |
        | (Generate view)    |
        +--------------------+
                    |
                    v            
        +--------------------+
        | Response           |
        | (Sent back to user)|
        +--------------------+
                    |
                    v
        +--------------------+
        | User Response      | (Browser)
        +--------------------+

Laravel Request Lifecycle with Aim Admin Installed

bash

        +--------------------+
        | User Request       | (Browser)
        +--------------------+
                    |
                    v
        +--------------------+
        | Web Server         | (e.g. nGinx/Apache) 
        +--------------------+
                    |
                    v
        +--------------------+
        | public/index.php   | (Entry Point)
        +--------------------+
                    |
                    v
        +--------------------+
        | Bootstrap Process  |
        | (Loads app, etc.)  |
        +--------------------+
                    |
                    v
        +--------------------+
        | Route Matching     |
        | (Finds the route)  |
        +--------------------+
                    |
                    v
        +--------------------+ 
        | Middleware Stack   | (Optional)
        +--------------------+
                    |
                    v
        +--------------------+
        | Controller         |
        | (Handles request)  |
        +--------------------+
                    |
                    v
        +--------------------+
        | Service            |
        +--------------------+
                    |
                    v 
        +--------------------+
        | Repository (Model) |
        +--------------------+            
                    |
                    v
        +--------------------+
        | Service            |
        +--------------------+
                    |
                    v 
        +--------------------+
        | Controller         |
        | (Generate view)    |
        +--------------------+
                    |
                    v            
        +--------------------+
        | Response           |
        | (Sent back to user)|
        +--------------------+
                    |
                    v
        +--------------------+
        | User Response      | (Browser)
        +--------------------+

For a clearer understanding, please refer to the diagram below:

image

Developed By ❤️ Taki Elias