🏗️ 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
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:
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:
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:
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:
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):
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:
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:
// 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.
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:
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:
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:
// 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
+--------------------+
| 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
+--------------------+
| 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: