Order Management System
A comprehensive web application for order management built with Symfony backend and Twig templates with HTML, CSS, and JavaScript frontend. This application allows users to create, view, modify, delete orders, and generate printable order summaries.
This is just a little demo project as test for a job interview, it's not intended to be complete in any part, it just shows the use of some OOP
and good practices and patterns.
You should be crazy using this software in production, anyway I must warn that the project is just a try and is not intended to be a finished app,
DO NOT USE IT IN PRODUCTION!!! ๐
Features
- CRUD Operations: Complete Create, Read, Update, Delete functionality for orders
- RESTful API: Well-structured REST API endpoints for all order operations
- Search & Filter: Advanced filtering by customer code, customer name, order number, and date range
- Responsive UI: Clean, intuitive Bootstrap 5 based user interface
- Dockerized: Fully containerized with Docker Compose
- Tested: Unit and integration tests for backend and frontend
- Code Quality: Linting with PHP CS Fixer for code consistency
- Design Patterns: MVC, Repository pattern, SOLID principles
Technology Stack
Backend
- Framework: Symfony 7.4
- Database: MariaDB 10.11
- ORM: Doctrine ORM
- Testing: PHPUnit 10.5
- Code Quality: PHP CS Fixer
Frontend
- Templates: Twig
- CSS Framework: Bootstrap 5.3
- Icons: Bootstrap Icons
- JavaScript: Vanilla JS (ES6+)
Infrastructure
- Containerization: Docker & Docker Compose, having some issues with Docker compose in my local PC I used DDEV
- Web Server: Nginx
- PHP: PHP 8.2-FPM
Prerequisites
- Docker Desktop (or Docker Engine + Docker Compose)
- Git
- Minimum 4GB RAM available for Docker
Installation & Setup
1. Clone the Repository
git clone <repository-url>
cd order-management-system2. Build and Start Docker Containers
docker-compose up -d --buildbut if you are ok with DDEV, you can use:
ddev startThis will start three containers:
order_management_php- PHP 8.2-FPMorder_management_nginx- Nginx web serverorder_management_db- MySQL 8.0 database
3. Install Dependencies
docker-compose exec php composer installor with DDEV:
ddev composer install4. Run Database Migrations
docker-compose exec php php bin/console doctrine:migrations:migrate --no-interactionor with DDEV:
ddev exec bin/console doctrine:migrations:migrate --no-interaction5. Access the Application
Open your browser and navigate to:
- Web Interface: http://localhost:8080
- API Base URL: http://localhost:8080/api
Project Structure
order-management-system/
โโโ config/ # Symfony configuration files
โ โโโ packages/ # Bundle configurations
โ โโโ routes.yaml # Routing configuration
โ โโโ services.yaml # Service container configuration
โโโ docker/ # Docker configuration
โ โโโ nginx/ # Nginx configuration
โ โโโ php/ # PHP Dockerfile
โโโ migrations/ # Database migrations
โโโ public/ # Public web directory
โ โโโ index.php # Application entry point
โโโ src/
โ โโโ Controller/ # Controllers
โ โ โโโ Api/ # API Controllers
โ โ โโโ OrderController.php # Web Controllers
โ โโโ Entity/ # Doctrine entities
โ โ โโโ Order.php
โ โ โโโ OrderProduct.php
โ โโโ Repository/ # Doctrine repositories
โ โ โโโ OrderRepository.php
โ โ โโโ OrderProductRepository.php
โ โโโ Kernel.php # Symfony kernel
โโโ templates/ # Twig templates
โ โโโ base.html.twig
โ โโโ order/ # Order templates
โ โโโ index.html.twig
โ โโโ create.html.twig
โ โโโ show.html.twig
โ โโโ edit.html.twig
โ โโโ print.html.twig
โโโ tests/ # Test files
โ โโโ Controller/ # Controller tests
โ โโโ Repository/ # Repository tests
โโโ .env # Environment variables
โโโ .php-cs-fixer.php # PHP CS Fixer configuration
โโโ composer.json # PHP dependencies
โโโ docker-compose.yml # Docker Compose configuration
โโโ phpunit.xml.dist # PHPUnit configuration
โโโ README.md # This fileDatabase Schema
Order Table
id(INT, PRIMARY KEY, AUTO_INCREMENT)order_number(VARCHAR, UNIQUE)customer_code(VARCHAR)customer_name(VARCHAR)created_at(TIMESTAMP)
Order_Product Table
id(INT, PRIMARY KEY, AUTO_INCREMENT)order_id(INT, FOREIGN KEY โ Order.id)product_code(VARCHAR)product_name(VARCHAR)price(DECIMAL 10,2)quantity(INT)created_at(TIMESTAMP)
API Documentation
Base URL: http://localhost:8080/api
Endpoints
1. List All Orders
GET /api/ordersQuery Parameters:
customerCode(optional) - Filter by customer codecustomerName(optional) - Filter by customer nameorderNumber(optional) - Filter by order numberdateFrom(optional) - Filter orders from date (YYYY-MM-DD)dateTo(optional) - Filter orders to date (YYYY-MM-DD)
Response Example:
{
"success": true,
"data": [
{
"id": 1,
"orderNumber": "ORD-2024-001",
"customerCode": "CUST001",
"customerName": "John Doe",
"createdAt": "2024-02-05 10:30:00",
"totalAmount": 159.98,
"products": [
{
"id": 1,
"productCode": "PROD001",
"productName": "Product Name",
"price": "79.99",
"quantity": 2,
"subtotal": 159.98
}
]
}
]
}2. Get Single Order
GET /api/orders/{id}Response Example:
{
"success": true,
"data": {
"id": 1,
"orderNumber": "ORD-2024-001",
"customerCode": "CUST001",
"customerName": "John Doe",
"createdAt": "2024-02-05 10:30:00",
"totalAmount": 159.98,
"products": [...]
}
}3. Create Order
POST /api/orders
Content-Type: application/jsonRequest Body:
{
"orderNumber": "ORD-2024-001",
"customerCode": "CUST001",
"customerName": "John Doe",
"products": [
{
"productCode": "PROD001",
"productName": "Product Name",
"price": "79.99",
"quantity": 2
}
]
}Response Example:
{
"success": true,
"message": "Order created successfully",
"data": {
"id": 1,
"orderNumber": "ORD-2024-001",
...
}
}4. Update Order
PUT /api/orders/{id}
Content-Type: application/jsonRequest Body: Same as Create Order
Response Example:
{
"success": true,
"message": "Order updated successfully",
"data": {...}
}5. Delete Order
DELETE /api/orders/{id}Response Example:
{
"success": true,
"message": "Order deleted successfully"
}Error Responses
All endpoints return consistent error responses:
{
"success": false,
"message": "Error description",
"errors": ["Validation error 1", "Validation error 2"]
}HTTP Status Codes:
200- Success201- Created400- Bad Request (validation errors)404- Not Found500- Internal Server Error
Running Tests
Run All Tests
docker-compose exec php composer testRun Specific Test Suite
# Repository tests
docker-compose exec php php bin/phpunit tests/Repository
# API Controller tests
docker-compose exec php php bin/phpunit tests/Controller/ApiRun with Coverage (requires Xdebug)
docker-compose exec php php bin/phpunit --coverage-html coverageCode Quality
Run Linter (Dry Run)
docker-compose exec php composer lintFix Code Style Issues
docker-compose exec php composer lint:fixLinting Rules
The project follows:
- PSR-12 coding standards
- Symfony coding standards
- Custom rules defined in
.php-cs-fixer.php
Development Commands
Access PHP Container
docker-compose exec php bashAccess MySQL Database
docker-compose exec database mysql -u symfony -psymfony order_managementClear Symfony Cache
docker-compose exec php php bin/console cache:clearCreate New Migration
docker-compose exec php php bin/console make:migrationView Logs
# All containers
docker-compose logs -f
# Specific container
docker-compose logs -f php
docker-compose logs -f nginx
docker-compose logs -f databaseDesign Patterns Used
1. MVC (Model-View-Controller)
- Models: Entity classes (Order, OrderProduct)
- Views: Twig templates
- Controllers: OrderController, OrderApiController
2. Repository Pattern
- Encapsulates data access logic
OrderRepositoryandOrderProductRepository- Custom query methods for filtering
3. Dependency Injection
- Symfony's service container
- Constructor injection for all dependencies
- Auto-wiring enabled
4. SOLID Principles
Single Responsibility Principle:
- Separate controllers for web and API
- Dedicated repositories for data access
- Entity classes focused on data representation
Open/Closed Principle:
- Extendable through inheritance and interfaces
- Repository pattern allows easy extension
Liskov Substitution Principle:
- All repositories extend
ServiceEntityRepository - Consistent interface contracts
Interface Segregation Principle:
- Focused, specific interfaces
- No fat interfaces
Dependency Inversion Principle:
- Depend on abstractions (interfaces)
- High-level modules don't depend on low-level modules
Troubleshooting
Port Conflicts
If ports 8080 or 3307 are already in use:
Edit docker-compose.yml:
nginx:
ports:
- "8081:80" # Change 8080 to another port
database:
ports:
- "3308:3306" # Change 3307 to another portDatabase Connection Issues
# Restart database container
docker-compose restart database
# Check database logs
docker-compose logs databasePermission Issues
# Fix permissions
docker-compose exec php chown -R www-data:www-data var/
docker-compose exec php chmod -R 777 var/License
This project is licensed under the MIT License.
Support
For issues and questions:
- Create an issue in the repository
- Contact the development team
Acknowledgments
- Symfony Framework
- Bootstrap Team
- Docker Community