Introduction
This project marks the beginning of my transition to software architecture. I refactored a procedural PHP e-commerce into a well-structured OO codebase, applying design patterns and SOLID principles. Although I had seen these concepts before, this was my first time applying them systematically in a real project structure.
In this article, I'll cover:
- The problems with procedural code
- How I applied Strategy, Factory, and Repository patterns
- How interfaces reduce coupling and enable testing
- The final architecture and folder structure
The Problem with Procedural Code
The procedural code has a lot of problems including mixed responsibilities, SQL injection vulnerability, difficulty adding new types, harder testing, and high coupling. For example, a single function might validate data, build SQL queries, and execute them directly - all mixed together.
Strategy Pattern
I used the Strategy pattern to guarantee the Open/Closed Principle (the "O" in SOLID) and avoid mistakes when modifying files with a lot of logic. Instead of adding more if/else statements, I created separate classes for each shipping and discount type.
Before (procedural):
if ($type === 'post_office') {
return $weight * 2.5;
} elseif ($type === 'transport') {
return $weight * 1.8 + 10;
}
After (Strategy):
$calculator = $factory->create($type);
return $calculator->calculate($weight);
Factory Pattern
I used the Factory pattern to decouple the client code from object creation and avoid if/else statements scattered across the codebase. The creation logic stays centralized in one place.
Repository Pattern
I used the Repository pattern to separate database communication from business logic. This avoids high coupling and allows me to test without a real database by using an InMemoryRepository.
How Interfaces Help
Interfaces make testing easier and reduce coupling. The controller depends on ProductRepositoryInterface, not on ProductRepository. This way, I can inject InMemoryProductRepository for tests without changing any controller code.
Final Architecture
I used PSR-4 to organize files and enable autoloading.
App/
Controller/
Entity/
Repository/
Shipping/
Discount/
Tests/
Each layer has a single responsibility:
- Entity: Represents business data with self-validation
- Repository: Handles database communication
- Shipping/Discount: Contains domain logic with interfaces, implementations, and factories
- Controller: Orchestrates the flow between layers
Conclusion
This project helped me understand how design patterns and SOLID principles work in practice, not just in theory. The code is now more secure, testable, and easier to extend. This is just the beginning of my journey toward software architecture.
Repository
Check the full code here: php-ecommerce-architecture
Top comments (0)