_ \ | _) __|
__/ _` | _| | / | \ _` | (_ | _` | _| _` | _` | -_)
_| \__,_| _| _\_\ _| _| _| \__, | \___| \__,_| _| \__,_| \__, | \___|
____/ ____/
Implement a software solution that will enable various types of vehicle to park in a parking garage.
- When a vehicle arrives at the parking garage, and if there is space available, we should see a message on the screen saying "Welcome, please go in".
- When a vehicle arrives at the entrance to the parking garage, and it's full, we should see a message saying "Sorry, no spaces left".
- Must accept multiple types of vehicles: cars, vans, motorcycles
- Each type will have a different size (e.g. 2 motorcycles can park in 1 car spot, a van takes 1.5 car spots).
- Must have 3 floors, each floor has different capacity.
- A Van can only park on the ground floor.
- Start the Docker containers
docker compose up -d
- Install the vendor folder
docker compose exec app composer install
Or enter the container and install the vendor folder
docker exec -it parking-garage-assignment /bin/bash
composer install
- Run your tests
docker compose exec app vendor/bin/phpunit src/Tests/
- Run the console
docker compose exec app php src/console.php
- Stop the docker containers
docker compose down
There's no predefined size for each floor of the parking garage, meaning that parking spaces on each floor can change dynamically. This assumption suggests that my parking garage implementation is flexible enough to handle varying capacities for each floor.
I've implemented a leave method to support both vehicle parking (adding to capacity) and vehicle exit (freeing up space). This will be essential for ensuring that the system can adapt to vehicles entering and leaving in real-time.
I can assume the system is relatively straightforward without complex error scenarios. However, I considered basic error handling as per requirements, like preventing parking when the garage is full, or when a Van try to park (considering only the ground floor).
By following PSR12, I am adopting a widely accepted coding standard for PHP. This will ensure that my code is consistent, readable, and maintainable according to best practices.
src/
├── Domain/ # Domain-related code
│ ├── Entities/ # Entity classes
│ ├── Interfaces/ # Entities-related Interfaces
│ └── Exceptions/ # Entities-related Exceptions
├── Application/ # Application layer for orchestration
│ └── Commands/ # Commands folder
└── Tests/ # Unit and integration tests
I choose to use an Interface rather than an abstract class for vehicles because:
- The vehicles only share a method (like getSize()) and there's no common state or default behavior.
- The Sizable interface is more general and not specific to vehicles.
- This approach is ideal if you prioritize flexibility and anticipate potential changes in our vehicle structures.
For example: What if we want to let our users to parking a container (or other various objects)? Is not vehicle, but it's Sizable.
- Pros: Simplifies class definitions, reducing boilerplate code and enhancing code readability.
- Cons: Limits backward compatibility with PHP versions prior to 8, potentially restricting compatibility with certain environments.
Where is the best place to enforce domain-specific rules like "Special handling for Vans - can only park on the ground floor"?
- It depends on the architecture and expected growth.
- If the rules are simple, keeping them within the domain entity (ParkingGarage) can be straightforward and easy to maintain.
- If the rules are complex, or you expect them to evolve, using a domain service to encapsulate business logic can provide more flexibility and scalability.
I decided to Keep It Stupidly Simple (KISS), and keep it in the domain entity - ParkingGarage.
- Ensures the system identifies the right floor with sufficient space before attempting to park.
- Can apply business rules, like restricting certain vehicles to specific floors.
- Serves as an additional safety check at the floor level.
- Confirms the floor's capacity before changing its internal state (like updating the current load).
- A defensive measure to prevent overloading or parking in unintended areas.
- The PHP Coding Standards Fixer (PHP CS Fixer) tool fixes your code to follow standards.
- It can modernize your code (like converting the pow function to the ** operator on PHP 5.6) and (micro) optimize it.
- Install PHP-CS-Fixer:
composer require --dev friendsofphp/php-cs-fixer
- Run PHP-CS-Fixer:
docker compose exec app ./vendor/bin/php-cs-fixer fix src
Or alternatively (inside the container):
./vendor/bin/php-cs-fixer fix src
- Laravel Pint is an opinionated PHP code style fixer for minimalists.
- It is a code quality tool built on top of PHP CS Fixer for detecting coding style issues in PHP projects.
I configured the pint.json file with basic rules to enforce PSR-12 compliance.
- Install Laravel Pint:
composer require laravel/pint --dev
- Run Laravel Pint:
docker compose exec app ./vendor/bin/pint
Or alternatively (inside the container):
./vendor/bin/pint
- PHPStan finds bugs in your code without writing tests. It's open-source and free.
- PHPStan scans your whole codebase and looks for both obvious & tricky bugs.
- Install PHPStan:
composer require --dev phpstan/phpstan
- Run PHPStan:
docker compose exec app ./vendor/bin/phpstan analyse src
Or alternatively (inside the container):
./vendor/bin/phpstan analyse src
- Run PHPStan with level (e.g. level 6):
docker compose exec app ./vendor/bin/phpstan analyse -l 6 src
docker compose exec app ./vendor/bin/phpunit src/Tests/
I created a Unit Test only for Car and not for other vehicles for the sake of time.
I implemented a leave method, tested but not used in the console.
I would like to implement an interactive command, using the Symfony Console Component.
composer require symfony/console