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

Nova Business Hours Laravel Package

tomhatzer/nova-business-hours

A Laravel Nova field for managing weekly business hours on Eloquent models. Set opening and closing times per weekday through a clean Nova form interface, store schedules as JSON, and display them alongside your resources.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is an early-stage (v0.1.x) Laravel field for editing opening-hours data, designed to pair with spatie/opening-hours. The v0.1.1 release is documentation-only: it adds a README snippet showing how to hand the field's value to spatie/opening-hours. There are no code, API, or config changes to migrate for.

Start here:

  1. composer require the package alongside spatie/opening-hours in the same project — the integration snippet assumes both are installed.
  2. Read the README's new snippet first; it is currently the canonical example of the intended data flow (field value → OpeningHours instance).
  3. Add a json (or text) column to the model that owns the hours, e.g. opening_hours.
  4. Register the field on the relevant Nova resource form/detail screen and give it that column name.
  5. Cast or hydrate the stored value into Spatie\OpeningHours\OpeningHours in the model so the rest of your app (controllers, Blade, API resources) never touches the raw JSON.

First use case: a "business hours" editor on a Location/Venue resource, where an admin sets per-weekday ranges and the front end renders "Open now / Closed" via OpeningHours::isOpen().

Implementation Patterns

Store raw, hydrate late. Keep the DB column as the field's native serialised shape (an array of day → ranges). Do the OpeningHours conversion in an accessor or a small cast so the field round-trips cleanly and spatie/opening-hours remains a presentation/query concern:

protected $casts = ['opening_hours' => 'array'];

public function openingHours(): OpeningHours
{
    return OpeningHours::create($this->opening_hours ?? []);
}

Seed sensible defaults. An empty field value is common on first create. Provide a default week (e.g. Mon–Fri 09:00–17:00, weekend closed) either in the field's default()/resolveUsing or via a model observer, so OpeningHours::create() never receives a malformed array.

Use it as the single source of truth. Once the field owns the data, derive everything else — isOpen(), nextOpen(), "closed on public holidays" exceptions, and JSON API output — from the hydrated object rather than re-parsing the column in multiple places. This keeps the field's format an internal detail you can change on a minor bump.

Validation at the edge. Pair the field with backend validation (start < end, no overlapping ranges per day) rather than trusting the UI component. Early 0.x field packages rarely ship a full validation rule.

Testing. Feature-test the resource form with a fixture array and assert the persisted column matches; unit-test the hydration helper separately. Because spatie/opening-hours parses on construction, a test that builds OpeningHours::create() from your stored fixtures catches format drift quickly after any package upgrade.

Gotchas and Tips

  • 0.x semver. At v0.1.1 anything may change between releases; pin with "vendor/package": "0.1.*" (or an exact tag) and read every changelog. The v0.1.1 note itself is a signal that documentation is still being filled in — expect API surfaces to be lightly documented.
  • Docs are thin. The only guidance added in this release is the spatie/opening-hours snippet. Treat the source (field class + Vue component) as the real spec for accepted value shapes before wiring it into production forms.
  • Timezone and DST. spatie/opening-hours evaluates against a timezone you must supply; store the venue timezone separately and pass it explicitly, otherwise "open now" drifts for remote locations and around DST boundaries.
  • Overnight ranges. Ranges crossing midnight (e.g. 18:00–02:00) are a classic source of off-by-one bugs in both the editor UI and spatie/opening-hours exceptions. Test these explicitly rather than assuming the field enforces them.
  • Column type. Use json on MySQL 5.7+/Postgres; on older MySQL fall back to text and cast. Empty string vs null vs [] will each behave differently on hydration — normalise in the accessor.
  • Debugging. When the field renders blank, check in order: the column is in $casts, the resource field name matches the column, and the stored array keys are the day names spatie/opening-hours expects. Log the hydrated object in a Tinker session before blaming the Vue component.
  • Extension points. Overriding the published Vue component or the field's resolve/fill methods is the practical way to add custom formatting (24h vs 12h, locale day labels). Prefer subclassing the field over editing vendor files so upgrades stay painless.
  • Version coupling. The README snippet is written against a specific spatie/opening-hours API; if you are on an older major of that package, adapt the snippet — the field release does not pin or constrain it for you.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager