A demonstration project showcasing a flexible and extensible pricing engine built with Symfony.
It provides a REST API to manage products and a /checkout endpoint that calculates the final
cart price by applying different discount strategies.
Each product has a base price and can have one of the following discount strategies applied:
- Fixed Discount
- Percentage Discount
- Buy One Get One Free
This project highlights clean code, modular design, and clear API structure, making it easy to extend with additional business rules or discount strategies.
To run this project, you need:
- PHP 8.4 or higher
- Composer
- Symfony CLI
- Docker & Docker Compose
- Copy the environment file:
Then add your API token inside. You can generate a token with:
cp .env.example .env.local
php -r "echo bin2hex(random_bytes(32));" - Install PHP dependencies:
composer install
- Start the database with Docker:
docker-compose up -d
- Run database migrations:
For the main database:
For the test database:
php bin/console doctrine:migrations:migrate
php bin/console doctrine:database:create --env=test php bin/console doctrine:migrations:migrate --env=test
- Start the Symfony development server:
The API will be accessible at:
symfony server:start
http://localhost:8000/api/v1
http://localhost:8000/api/v1
| Method | Endpoint | Description |
|---|---|---|
| GET | /products | List all products |
| GET | /products/{id} | Retrieve a single product |
| POST | /products | Create a new product |
| PUT | /products/{id} | Update an existing product |
| DELETE | /products/{id} | Delete a product |
| POST | /checkout | Calculate the total cart price with discounts |
All API requests require a token in the Authorization header:
Authorization: Bearer your_api_token
The token should match the one set in your .env.local.
The API is documented using OpenAPI 3.2.0.
Full details are available in the openapi.yaml file.
Postman collection and environment files are saved in the postman/ directory.
You can import them in Postman to quickly start testing the API.
The project uses PHPUnit for unit and integration tests, with a separate test database to avoid interfering with the development database.
Run the tests using Composer:
composer testTests automatically use the .env.test file and a dedicated database named app_test.
The project uses the following tools to ensure clean, maintainable code, catch errors early, and keep the codebase consistent:
- PHP_CodeSniffer for PSR-12 coding standards:
composer phpcs
composer phpcbf- PHPStan for static analysis:
composer phpstanThis project uses GitHub Actions to automatically run tests, static analysis, and generate code coverage on every push or pull request.
- The
.github/workflows/tests.ymlworkflow runs PHPUnit with Xdebug to collect code coverage, which is uploaded to Codecov for visualization and badge updates. - The
.github/workflows/static-analysis.ymlworkflow runs PHPStan to check for type errors and potential issues.
The project separates persistence from business logic. Doctrine and Symfony entities are used solely for database interactions, while the application uses its own domain models and value objects for core business logic. This approach ensures a clean architecture, easier testing, and better maintainability.
Doctrine cache is enabled in the production environment to improve performance. A production-ready system could also leverage HTTP-level caching (e.g., Cache-Control headers) for additional performance gains, though it was not implemented in this project.
This project is licensed under the MIT License. See the LICENSE file for details.