The library for your next Laravel booking app.
Supported Laravel versions: >=9.x
- Install package via composer
$ composer require shirokovnv/innkeeper
- Run migrations
$ php artisan migrate
- Done!
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Shirokovnv\Innkeeper\Contracts\Bookable;
use Shirokovnv\Innkeeper\Traits\HasBooking;
class Room extends Model implements Bookable {
use HasBooking;
}
That's basically it. Now your rooms can be booked.
The Innkeeper
service provides functionality to check wether its possible to book something in a date range:
use \Shirokovnv\Innkeeper\Contracts\Innkeepable;
$room = \App\Models\Room::find(1);
$innkeeper = app()->make(Innkeepable::class);
// Has bookings in a date range ?
$has_bookings = $innkeeper->exists(
$room,
new DateTime('2022-08-01 15:00'),
new DateTime('2022-08-07 12:00')
);
Creating a new booking is straight forward and could be done the following way:
use \Shirokovnv\Innkeeper\Contracts\Innkeepable;
$room = \App\Models\Room::find(1);
$innkeeper = app()->make(Innkeepable::class);
$booking_hash = generateBookingHash();
$innkeeper->book(
$room,
$booking_hash,
new DateTime('2022-08-01 15:00'),
new DateTime('2022-08-07 12:00')
);
Or if you like facades, you can do it like this:
use Shirokovnv\Innkeeper\Facades\Innkeeper;
Innkeeper::book(
$room,
$booking_hash,
new DateTime('2022-08-01 15:00'),
new DateTime('2022-08-07 12:00')
);
Notes:
Why we need
booking_hash
and what is it ?
- The hash is a field in a database with a unique constraint
- It serves purpose to prevent some duplicate bookings without explicitly locking tables
Let me show you and example:
Suppose, you have a few visitors on your booking site. And all the visitors asks for booking the same room at a time.
In this particular case, you probably need to assign the room to the first customer and notify others the room already booked.
You can do it by these simple steps:
- Define hash function
function generateBookingHash(int $room_id, string $started_at, string $ended_at) {
return $room_id . $started_at . $ended_at;
}
- In your business logic code
use Illuminate\Database\QueryException;
$room = \App\Models\Room::find(1);
$booking_hash = generateBookingHash($room->id, $started_at, $ended_at);
try {
$innkeeper->book($room, $booking_hash, $started_at, $ended_at);
} catch (QueryException $exception) {
// Catch SQLSTATE[23000]: Integrity constraint violation: 19 UNIQUE constraint failed: bookings.hash
// show user popup with apologies or
// redirect to another free room or ...
}
This example covers only the case, when you have deterministic booking schedule without intersections. Like this:
- 09:00 - 10:00
- 10:00 - 11:00
- 11:00 - 12:00
- ...
If you have some intersections, like:
- 09:00 - 10:00
- 09:30 - 10:30
you may still have a problem with duplicates.
Of course, you can check the availability of the room:
$can_be_booked = ! $innkeeper->exists($room, $started_at, $ended_at);
if ($can_be_booked) {
$innkeeper->book($room, $booking_hash, $started_at, $ended_at);
} else {
// show user an error message
}
But it doesn't guarantee resolving concurrent requests for your schedule.
So, please, let me know what can be a solution if it is your case.
use \Shirokovnv\Innkeeper\Contracts\Innkeepable;
$room = \App\Models\Room::find(1);
$innkeeper = app()->make(Innkeepable::class);
// All the bookings for the room
$bookings = $innkeeper->all($room);
// All the bookings for the room in a range.
$bookings = $innkeeper->allInRange($room, $started_at, $ended_at);
// The first started booking
$first_booking = $innkeeper->first($room);
// The last ended booking
$last_booking = $innkeeper->last($room);
$room = \App\Models\Room::find(1);
$booking_hash = 'some hash';
// Delete by predefined hash
$innkeeper->deleteByHash($room, $booking_hash);
$started_at = new DateTime('2022-08-01 09:00');
$ended_at = new DateTime('2022-08-02 09:00');
// Delete by specific date range.
$innkeeper->deleteByRange($room, $started_at, $ended_at);
Please see the changelog for more information on what has changed recently.
$ composer test
Please see contributing.md for details and a todolist.
If you discover any security related issues, please email shirokovnv@gmail.com instead of using the issue tracker.
MIT. Please see the license file for more information.