The task from Booking Layer
These have been the assumptions while working on the test application.
-
Room (can be blocked or booked)
- id
- capacity (integer)
-
Booking (is a room reservation, that takes 1 capacity. So room with 4 capacity can be booked 4 times for same date)
- id
- room_id
- starts_at (date)
- ends_at (date)
-
Block (that’s not booking it’s just a indicator that room is not available then, same as booking one block takes only 1 capacity)-
- id
- room_id
- starts_at (date)
- ends_at (date)
Steps I thought of and executed for solving the given problem:
- Prepare the migrations for the required tables
- Seed the data so that we can formulate a query. Even though the document states the feasibility the of the test-taker to create/edit models. To my understanding adding a table or a field should not be added unless really necessary.
- Prepare necessary query
- First Pass
-
Prepare query to filter bookings by given date/month/room_id
- To prepare the monthly query for the first time i retrieved all the days and counted the booking start date and end date summed up the (inclusive)difference which was a not an efficent approach.
$booking = Booking::where(function ($query) use ($startDate) { $query->whereMonth('starts_at', '<=', $startDate->month); $query->whereMonth('ends_at', '>=', $startDate->month); })->get(); $allBookingDays = 0; foreach ($booking as $allBookingDay) { $diff = Carbon::parse($allBookingDay->starts_at)->diffInDays(Carbon::parse($allBookingDay->ends_at)) + 1; $allBookingDays += $diff; }
- Prepare query to filter blocking by given date/month/room_id
- Prepare query to calculate room capacity
-
- First Pass
- Second Pass
-
Improve the query to count the booking days
- To improve the query I thought of delegating the task of calculation to database rather than the program itself, which came as:
$this->getQuery(Booking::class) ->selectRaw( 'sum(DATEDIFF(ADDDATE(ends_at, INTERVAL 1 DAY), starts_at)) as days_between' )->whereRaw('month(starts_at) <= ? and month(ends_at) >= ?', [ $month, $month, ]) ->when(! empty($roomId), function ($query) use ($roomId) { return $query->whereIn('room_id', $roomId); });
The above query helped me to get the exclusive interval if I swapped it for
Booking
,Block
which gave the accurate results as above. Also thewhen
method came handy here as we know theroom_id
os optional in requests. -
Third Pass:
- Encaupaltion of necessary logic into place so that the controller does not get bloated
- Refactoring and removing un-necessary code.
-
- No any third party library other than the framework itself provides.
- Uses php 8.1
- Uses phpunit for testing and xDebug 3.0 for code coverage analysis.
- Docker is used to run the application, which encapsulates all the necessary services.
Run the following commands to set up the application, given that Docker is available in the host machine:
git clone
https://github.com/ravisharmaa/booking-layer-testdocker-compose up -d
vendor/bin/phpunit
:- For code coverage:
vendor/bin/phpunit --coverage-text
- Additionally a report can also be generated using the command
vendor/bin/phpunit --coverage-html=reports
The tests provide a basic overview of the application. Some steps can be done to see the application in action, which are.
- To seed a basic data according to the document.
php artisan db:seed
- Use the necessary routes to view the occupancy.
- I have not used any form request validation or json resource to show the response.
- I have not also validated the get request, lets say if the room_ids is a valid array or not and the date/month are valid or not.
- I tried to use bindings but somehow it was not possible/working in some places.
It was a challenge. However, if I had to improve upon this:
- I would work out to implement proper validation on places like Booking create, update, and get endpoints.
- I would work on implementing proper bindings as it is a get request and there might be malicious attacks.
- I would also work on using
JsonResource
to send the response. - More testing can also be done, to ensure applications integrity and behaviour.