Weave Code
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 Hours Helper Laravel Package

label84/laravel-hours-helper

Generate Laravel collections of time/date intervals for any period: build dropdown-ready schedules with custom formatting, exclusions, support for past-midnight ranges, and multi-day spans. Simple facade API to create evenly spaced slots like 08:00–09:30 every 30 minutes.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer:

composer require label84/laravel-hours-helper

First Use Case: Generate a time dropdown for appointment scheduling.

use Label84\HoursHelper\Facades\HoursHelper;

// Basic 30-minute slots between 8 AM and 9:30 AM
$slots = HoursHelper::create('08:00', '09:30', 30);

// Pass to Blade view
return view('appointments.create', ['slots' => $slots]);

Key Starting Points:

  1. Facade API (preferred for most cases)
  2. Test File (real-world examples)
  3. Release Notes (Laravel version compatibility)

Implementation Patterns

Core Workflow

  1. Generate Slots:

    $slots = HoursHelper::create(
        start: '09:00',
        end: '17:00',
        interval: 60, // minutes
        format: 'g:i A',
        exclusions: [['12:00', '13:00']] // lunch break
    );
    
  2. Blade Integration:

    <select name="appointment_time">
        @foreach($slots as $slot)
            <option>{{ $slot }}</option>
        @endforeach
    </select>
    
  3. API Response:

    return response()->json(['slots' => $slots]);
    

Advanced Patterns

Dynamic Exclusions from Database:

$excludedRanges = DB::table('blocked_slots')
    ->where('date', $date)
    ->pluck('range');

$slots = HoursHelper::create('08:00', '18:00', 30, 'H:i', $excludedRanges);

Multi-Day Generation with Chunking:

$start = now()->startOfDay();
$end = now()->addDays(7)->endOfDay();

$slots = collect();
while ($start < $end) {
    $dayEnd = $start->copy()->endOfDay();
    $daySlots = HoursHelper::create($start, $dayEnd, 60, 'Y-m-d H:i');
    $slots = $slots->merge($daySlots);
    $start = $dayEnd->addMinute();
}

Validation Rule:

use Illuminate\Validation\Rule;

$validator->validate([
    'time' => Rule::in($slots->pluck('value')->toArray())
]);

Background Job Processing:

foreach ($slots as $slot) {
    GenerateReminderJob::dispatch($slot);
}

Integration Tips

  • Timezones: Use Carbon::setTimezone() before calling the helper if working with non-default timezones.
  • Caching: Cache generated slots for static periods (e.g., business hours).
  • Localization: Combine with Laravel's localization for translated time formats.
  • Testing: Mock the facade in unit tests:
    $this->mock(HoursHelper::class)->shouldReceive('create')->andReturn(collect(['09:00', '10:00']));
    

Gotchas and Tips

Common Pitfalls

  1. Exclusion Overlap Handling:

    • Exclusions are processed as inclusive ranges. Overlapping ranges may produce unexpected gaps.
    • Fix: Normalize exclusions before passing (e.g., merge [09:00,10:00] and [09:30,10:30] into [09:00,10:30]).
  2. Past-Midnight Edge Cases:

    • The helper handles midnight crossings automatically, but large ranges (e.g., 23:00 to 01:00) may include unexpected slots.
    • Tip: Validate the generated collection:
      $slots->reject(fn($slot) => $slot > '01:00');
      
  3. Performance with Large Ranges:

    • Generating monthly/yearly slots can create memory-intensive collections.
    • Solution: Use chunking or process in batches:
      $slots->chunk(100)->each(function($chunk) { /* process */ });
      
  4. Time Format Quirks:

    • Custom formats may produce unexpected output (e.g., g:i A vs. H:i).
    • Tip: Test formats with Carbon::parse()->format() first.
  5. Facade vs. Class:

    • The facade is auto-discoverable, but direct class usage (new \Label84\HoursHelper\HoursHelper) is possible for non-Laravel contexts.

Debugging Tips

  • Validate Inputs:
    if (!Carbon::parse($start)->isBefore(Carbon::parse($end))) {
        throw new \InvalidArgumentException("Start must be before end.");
    }
    
  • Inspect Exclusions:
    dd($slots->reject(fn($slot) => in_array($slot, $excludedSlots)));
    
  • Check Timezone:
    Carbon::setTestNow(Carbon::now('America/New_York'));
    

Extension Points

  1. Custom Interval Logic:

    • Extend the class to support non-linear intervals (e.g., exponential spacing):
      class CustomHoursHelper extends \Label84\HoursHelper\HoursHelper {
          public function createExponential($start, $end, $multiplier) { ... }
      }
      
  2. Database Integration:

    • Create a service to fetch exclusions dynamically:
      class SlotGenerator {
          public function generate($start, $end, $interval) {
              $exclusions = $this->fetchExcludedRanges($start, $end);
              return HoursHelper::create($start, $end, $interval, null, $exclusions);
          }
      }
      
  3. Event Dispatching:

    • Trigger events for each slot:
      $slots->each(fn($slot) => event(new SlotGenerated($slot)));
      
  4. Localization:

    • Override the facade to add translated formats:
      HoursHelper::macro('createTranslated', function($start, $end, $interval, $locale) {
          $translator = app('translator');
          return $this->create($start, $end, $interval, fn($time) =>
              $translator->get('time.' . $time->format('H_i'))
          );
      });
      

Configuration Quirks

  • No Config File: The package uses zero-configuration but relies on Laravel’s default Carbon settings.
  • Service Provider: Auto-registered via Laravel’s package discovery (no manual registration needed).
  • Testing: Use HoursHelper::shouldReceive('create') in PHPUnit tests to mock responses.

Performance Optimizations

  • Pre-filter Exclusions:
    $exclusions = collect($rawExclusions)->unique()->sort()->values()->toArray();
    
  • Lazy Loading:
    $slots->lazy()->each(fn($slot) => /* process */);
    
  • Memory Management: For very large ranges, consider generating on-demand rather than storing all slots in memory.
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.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata