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 Opening Hours Laravel Package

armincms/nova-opening-hours

A Laravel Nova field for managing weekly opening hours in your admin panel. Define multiple time slots per day, add exceptions, and store schedules as JSON for easy display on your frontend. Simple to integrate into Nova resources and customize for business hours.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with composer require <vendor>/<package> and confirm the version constraint — this is a 0.x release, so pin it ("^0.3") rather than floating. Minor bumps in 0.x are allowed to break.

  • Read in this order: README.md → src/Rules/ (the rule classes, including the new Overlap rule) → tests/ (the tests are the real specification for edge-case behaviour) → config/ if the package ships one (php artisan vendor:publish --tag=<package>-config).

  • Check composer.json for the supported Laravel/PHP matrix before adopting. Rule classes are usually plain Illuminate\Contracts\Validation\ValidationRule (Laravel 10+) or Rule (older) implementations, so they need no service provider bootstrapping — but confirm whether the provider registers translations or a facade.

  • First use case to try: block double-booking. In a form request:

    public function rules(): array
    {
        return [
            'starts_at' => ['required', 'date'],
            'ends_at'   => ['required', 'date', 'after:starts_at'],
            'room_id'   => ['required', 'integer', new Overlap($this->starts_at, $this->ends_at)],
        ];
    }
    

    Run it against a fixture where two ranges share an endpoint, one is fully contained, and one is adjacent-but-not-intersecting. Those three cases define the rule's contract and are exactly where implementations differ.

Implementation Patterns

  • Form requests are the default home. Instantiate the rule with the competing range's boundaries; keep the constructor arguments as primitives (strings, Carbon, IDs) so the rule stays serialisable for queued/async validators.
  • Pair with the existing validators, don't replace them. after:starts_at, date_format:Y-m-d H:i, and nullable belong on the same fields — the overlap rule should only answer "does this collide", not "is this a valid date".
  • Wildcard arrays for bulk input. When accepting a schedule payload, apply the rule per-row with bookings.*.starts_at and pass the sibling values via $this->input('bookings.*.starts_at') or validate a normalised DTO first. Normalise before validating; string-vs-Carbon comparison is the most common source of false negatives.
  • Compose into a reusable rule set. If overlap checking appears in three form requests, extract a BookingRequest base class or a Rule::class constant rather than repeating constructor arguments.
  • Use after() / withValidator() for cross-record checks when the overlap depends on database state (existing bookings). Keep the rule itself pure where possible so it stays unit-testable; do the query in a Rule::exists-style closure or a dedicated withValidator hook and pass the resulting ranges in.
  • Test at the rule boundary, not through HTTP. (new Overlap(...))->passes('field', $value) gives fast, table-driven tests for the half-open vs closed interval question — cover it once, explicitly, and encode the answer in test names.
  • Livewire/Filament/Inertia all funnel through the same validator, so a single form request covers every entry point. Verify once with assertInvalid in a feature test rather than per-surface.

Gotchas and Tips

  • Interval semantics are the whole package. Determine whether [start, end) or [start, end] is used. A booking ending at 10:00 and one starting at 10:00 should usually not collide; if the rule reports a conflict there, either pass adjusted endpoints or wrap it. Write the assertion down in a test.
  • Open-ended ranges. A null end date (ongoing booking) is the classic silent pass — confirm whether the rule treats null as "infinity" or skips validation. Handle it with sometimes/explicit defaults rather than assuming.
  • Normalise before you compare. Mixed inputs (ISO strings, Y-m-d, Carbon, timestamps, unix ints) are compared inconsistently. Cast to CarbonImmutable in UTC at the form-request layer.
  • Timezone drift. Carbon::parse() picks up app.timezone; stored UTC values will be off by hours. Compare in a single, explicit timezone.
  • Rule ordering matters. nullable/sometimes before the overlap rule; bail will stop at the first failure and can mask which side of a collision actually failed, making debugging harder.
  • Custom messages and translations. Override with :message in the attribute array ('room_id.overlap' => '...') and check whether the package publishes a lang/ directory — a missing translation key surfaces as the raw key string in the response.
  • Performance on large payloads. A PHP-side rule over hundreds of ranges is O(n²). For DB-backed overlap, prefer a constrained query (where('starts_at', '<', $end)->where('ends_at', '>', $start)) and use the rule only for in-memory/request-scope checks.
  • 0.x upgrade discipline. Read the diff on every minor. New rules in this release line up with a rule-object pattern, so extension points are typically: implement ValidationRule yourself, or subclass/extend the package rule to change interval semantics instead of forking.
  • Debugging tip: when a rule silently passes, first assert the rule is actually invoked — a mis-namespaced import in the rules array becomes a string class name that Laravel resolves later, and a typo in an array rule is easy to miss because bail/nullable may short-circuit before it.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings