Clean Architecture for PHP & Slim framework.
“Good architecture makes the system easy to understand, easy to develop, easy to maintain, and easy to deploy. The ultimate goal is to minimize the lifetime cost of the system and to maximize programmer productivity.”
― Robert C. Martin
What’s clean architecture
Clean architecture is a method for organizing an application code. The method is defined by Robert C Martin in his book Clean Architecture: A Craftsman’s Guide to Software Structure and Design.
The goal of the clean architecture method is the separation of concerns of the application.
The benefits of using the clean architecture method are creating a simple, loosely-coupled and testable application.
Like many other methods clean architecture separates the application in different layers:
Entities
Entities layer contains the application business objects. The business objects can have business roles or just data structures. The business roles should depend only on the entity and not on any external system.
Use Cases
The Use Cases layer contains all the system use cases, and it is used for implementing all the application-specific business rules. The Use Cases layer is used to transfer the data from and to the entities and it depends on abstract interfaces to communicate with the higher layers.
Adapters
The Adapters layer contains the implementations for transferring and transforming the data from the external systems (Database, browser etc…) to the application and from the application to the external systems. Adapters layer can have the persistence, API and UI implementations.
Frameworks and drivers
Frameworks and drivers layer contains the tools that are used by the application. These tools can be a database, web framework, monitoring tool, etc. The choice of these tools should not be very critical, and the tools should be easy to replace.
Characteristics
- Abstraction
Entities and Use Cases layers have the highest level of abstraction. On the other hand, the Adapters layer has more concrete implementations and a lower level of abstraction.
- Changeability
Adapters layer has more and frequent changes. Most of the changes in the Adapters layer come from fixing and maintaining the implementations.
Entities and Use Cases layers have fewer changes. Once these layers are created, they will have almost no changes because they don’t have any concrete implementation.
- Dependency
The higher layers depend on the lower layers. Adapters layer depends on Uses Cases and Entities layers and Use Cases layer depends on Entities layer.
A lower layer should never depend on the higher layer.
Use Cases and Entities layers should not have any dependencies on tools or frameworks.
PHP and Slim Framework code example
Scenario:
In this example, we will show how to implement a simple User Management API by following the clean architecture method.
The use cases are: add a user and find a user by id. The user data will be stored in a database (Any database, we will use sqlite for this example).
Check the complete code in https://github.com/sahbijabnouni/clean-architecture-php
Entities layer
User: Contains user data structure.
Use Cases layer
UserManager: Contains all the user use cases
UserRepositoryInterface: An abstraction of user data persistence implementation and it is used by the UserManager.
Adapters layer
UserRepository: Implementation for storing/retrieving user data in the database.
UserController: Used for receiving API requests and returning responses.
Dependency Injection:
Dependency injection is a design pattern that allows the creation of dependencies outside of the callers.
Dependency injection helps maintain the separation between the layers and makes the testing easier.
In our example, we use PHP-DI for implementing the Dependency injection.
Running the example:
pull the code from https://github.com/sahbijabnouni/clean-architecture-php
Install the libraries and run the API:
composer install
composer startAdd user:
curl -d '{"id":"1", "firstName":"firstname","lastName":"lastname", "email":"myemail@example.com"}' -H "Content-Type: application/json" -X POST http://localhost:8080/users
Get user:
curl -H "Content-Type: application/json" -X GET http://localhost:8080/users/1
Conclusion
Using a good design for our application can help us be more productive, make it easy to add new features, replace dependencies, maintain and test code. Clean architecture is one of the best approaches to achieve good design and create high-quality applications.
Thanks for reading! Let me know if you have any questions or need help.