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!!! 😅
- 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
- Framework: Symfony 7.4
- Database: MariaDB 10.11
- ORM: Doctrine ORM
- Testing: PHPUnit 10.5
- Code Quality: PHP CS Fixer
- Templates: Twig
- CSS Framework: Bootstrap 5.3
- Icons: Bootstrap Icons
- JavaScript: Vanilla JS (ES6+)
- 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
- Docker Desktop (or Docker Engine + Docker Compose)
- Git
- Minimum 4GB RAM available for Docker
git clone <repository-url>
cd order-management-systemdocker-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
docker-compose exec php composer installor with DDEV:
ddev composer installdocker-compose exec php php bin/console doctrine:migrations:migrate --no-interactionor with DDEV:
ddev exec bin/console doctrine:migrations:migrate --no-interactionOpen your browser and navigate to:
- Web Interface: http://localhost:8080
- API Base URL: http://localhost:8080/api
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 fileid(INT, PRIMARY KEY, AUTO_INCREMENT)order_number(VARCHAR, UNIQUE)customer_code(VARCHAR)customer_name(VARCHAR)created_at(TIMESTAMP)
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)
Base URL: http://localhost:8080/api
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
}
]
}
]
}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": [...]
}
}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",
...
}
}PUT /api/orders/{id}
Content-Type: application/jsonRequest Body: Same as Create Order
Response Example:
{
"success": true,
"message": "Order updated successfully",
"data": {...}
}DELETE /api/orders/{id}Response Example:
{
"success": true,
"message": "Order deleted successfully"
}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
docker-compose exec php composer test# Repository tests
docker-compose exec php php bin/phpunit tests/Repository
# API Controller tests
docker-compose exec php php bin/phpunit tests/Controller/Apidocker-compose exec php php bin/phpunit --coverage-html coveragedocker-compose exec php composer lintdocker-compose exec php composer lint:fixThe project follows:
- PSR-12 coding standards
- Symfony coding standards
- Custom rules defined in
.php-cs-fixer.php
docker-compose exec php bashdocker-compose exec database mysql -u symfony -psymfony order_managementdocker-compose exec php php bin/console cache:cleardocker-compose exec php php bin/console make:migration# All containers
docker-compose logs -f
# Specific container
docker-compose logs -f php
docker-compose logs -f nginx
docker-compose logs -f database- Models: Entity classes (Order, OrderProduct)
- Views: Twig templates
- Controllers: OrderController, OrderApiController
- Encapsulates data access logic
OrderRepositoryandOrderProductRepository- Custom query methods for filtering
- Symfony's service container
- Constructor injection for all dependencies
- Auto-wiring enabled
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
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 port# Restart database container
docker-compose restart database
# Check database logs
docker-compose logs database# Fix permissions
docker-compose exec php chown -R www-data:www-data var/
docker-compose exec php chmod -R 777 var/This project is licensed under the MIT License.
For issues and questions:
- Create an issue in the repository
- Contact the development team
- Symfony Framework
- Bootstrap Team
- Docker Community