Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Bookings Laravel Package

rinvex/laravel-bookings

Rinvex Laravel Bookings provides a flexible booking system for Laravel applications, with Eloquent models, migrations, and configurable services, resources, availability, and pricing to manage reservations and schedules with ease.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: the package is archived upstream and its composer constraints target older Laravel/Illuminate majors. Before you invest a day in it, run composer require rinvex/laravel-bookings in a throwaway branch and check composer why-not laravel/framework. If it won't resolve on your current Laravel, plan to fork it into packages/ (or a private VCS repo) and bump the constraints rather than fighting --ignore-platform-reqs. The code is small and readable — a fork is usually cheaper than a workaround.

Assuming it installs:

  1. Publish config and migrations, then migrate:
    php artisan vendor:publish --provider="Rinvex\Bookings\Providers\BookingsServiceProvider"
    php artisan migrate
    
  2. Open the published migration and config before running anything in a real database. The migration is the actual documentation of the data model — column names, price/currency representation, and whether there is a status column at all. Adjust it now, because Rinvex migrations are published once and then you own them.
  3. Attach the traits to your Eloquent models: the bookable trait on the resource being reserved (Room, Vehicle, Consultant, Seat), and the customer/booker trait on User or Organization. Verify exact trait and namespace names by listing vendor/rinvex/laravel-bookings/src/Traits/ — this is the fastest way to see the real API surface (relations, scopes, helpers) rather than trusting the README.
  4. Add a morphMap entry for each bookable/customer type in AppServiceProvider if you don't want FQCNs in your database.

First use case: a single-resource, single-slot booking — a meeting room booked by the hour. Create one Booking against one Room, then immediately write the availability query yourself (see below). Do not expect the package to tell you a slot is free; it gives you the schema, polymorphic relations, and traits, not a scheduling engine.

Implementation Patterns

Create through a service, not the controller. Wrap creation in a transaction and re-check availability inside it:

public function book(Bookable $resource, array $data): Booking
{
    return DB::transaction(function () use ($resource, $data) {
        $conflict = Booking::query()
            ->where('bookable_type', $resource->getMorphClass())
            ->where('bookable_id', $resource->getKey())
            ->whereNotIn('status', ['cancelled', 'no_show'])
            ->where('booked_from', '<', $data['booked_to'])   // half-open interval
            ->where('booked_to', '>', $data['booked_from'])
            ->lockForUpdate()
            ->exists();

        abort_if($conflict, 409, 'Slot no longer available');

        return Booking::create([...$data, 'status' => 'pending']);
    });
}

The booked_from < $end AND booked_to > $start shape is the only correct overlap test for half-open intervals — it also catches "starts inside" and "ends inside" cases that naive between queries miss.

Own the status lifecycle. The package stores status; it does not enforce transitions. Put a small enum + a transitionTo() method on your own Booking subclass (or a trait) so pending → confirmed → completed and → cancelled are validated in one place, and record cancelled_at/confirmed_at in your own migration additions.

Extend the model via config, not by editing vendor. Rinvex packages generally allow model swapping in the published config; bind your App\Models\Booking extends Rinvex\Bookings\Models\Booking there so you can add casts, accessors, and scopes without touching vendor/. Always follow with php artisan config:clear.

Model extra data as a separate table. Participant counts, add-ons, deposits, and external calendar IDs don't belong in the core table — a booking_meta or booking_addons table keyed by booking_id survives package upgrades and keeps your queries fast.

Reporting. Build read models with plain Eloquent/query builder against bookings, indexed on (bookable_type, bookable_id, booked_from, booked_to) and (customer_type, customer_id). Aggregations (revenue per resource, utilization %) are your queries, not the package's.

API integration. Validate that booked_to > booked_from, that the customer is authorized for the bookable (tenant/org scoping), and that the resource is active — none of this is in the package. Map a 409 from the conflict check to a "slot taken, pick another" UI state.

Gotchas and Tips

  • Archived means no security or compatibility fixes. Treat it as vendored source you own. Pin the exact version, add a FORK.md note, and budget for a Laravel upgrade every cycle.
  • Race conditions are the #1 production bug. Check-then-insert without lockForUpdate() (or a unique constraint / exclusion constraint on a Postgres range type) will double-book under load. If you're on Postgres, add a tstzrange exclusion constraint in a follow-up migration — it's a real guarantee, not a convention.
  • Timezones. Store booked_from/booked_to in UTC and convert at the edge. If the published migration used timestamp instead of timestampTz/dateTime, cast the column explicitly on your model. Mixing app timezone and DB timezone silently shifts every overlap check.
  • Money. Confirm whether price/total are decimal or integer minor units before writing formatting code; be consistent across price, quantity, and total, and compute total server-side, never from the request. Currency is a string column — validate it against your supported list.
  • Polymorphic types drift. Once rows exist with FQCN bookable_type values, adding a morphMap later breaks existing queries. Decide on morph aliases before the first booking row is written.
  • Config cache. Model swaps and config changes are invisible until config:clear / cache:clear; a stale cached config referencing the vendor model is a classic "my scope doesn't exist" error.
  • Deletes. Hard-deleting bookings destroys audit history and silently frees slots. Prefer status transitions, and if you soft-delete, remember your conflict query must filter deleted rows.
  • Debugging overlaps: log the resolved interval and the conflict query bindings; most "phantom double booking" reports are a timezone offset or a <= where < was needed.
  • Tests: write your own factories (don't rely on vendor ones), and cover the conflict matrix — adjacent bookings (end == start) must be allowed, overlapping ones rejected.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource