Red scorpion's avatar

Eloquent & form model for business hours

Hi,

i'm trying to implement business hours for my users. So i have basic users table and user_business_hours table, which looks like this:

| id | user_id | weekDay | start_time | end_time | is_break | created_at | updated_at |
|---:|---------|--------:|------------|----------|----------|------------|------------|
| 1  | 10      | 1       | 10:00:00   | 16:00:00 | 0        | ...        | ...        |
| 2  | 10      | 1       | 12:00:00   | 12:30:00 | 1        | ...        | ...        |

When is_break parameter id 1 the times represents working break (eg. lunch)

Now the problem: How to query this model and setup form model / inputs, that laravel will automatically fill nescessary inputs with provided values whlie updating bussiness hours for particular user?

I was thinking about this input organisation:

| ...     | Work From | Work From | Break From | Break To |
|---------|-----------|-----------|------------|----------|
| Monday  | 10:00:00  | 18:00:00  | 12:00:00   | 13:00:00 |
| Tuesday | <input>   | <input>   | <input>    | <input>  |

Thanks for your ideas

0 likes
4 replies
martinbean's avatar

@Red scorpion I wouldn’t store “breaks” as you’re going to find it difficult to maintain data integrity. Just have an opening_hours table that has the day of week, the opening time, and closing time. You can then specify multiple opening hours for a single day to designate a morning trading time and afternoon trading time if the business owner does close over lunch.

I tend to base a lot of my data modelling on the schema.org specifications. There just so happens to be one for opening hours, which is what I’ve based my answer on (and a schema I’ve implemented in an opening hours model in a previous application build).

Link: https://schema.org/OpeningHoursSpecification

4 likes
thepsion5's avatar

My take:

Assumptions: A break has to be between a the work_from and work_to values, and that a break is non-optional.

As far as organizing inputs, I would create nested form fields for each day, like so:

times[monday[work_from]]
times[monday[work_to]]
times[monday[break_from]]
times[monday[break_to]]

Repeat for each day of the week.

When the user submits, you need to turn that data into 3 models per work day. So something like this:

$timeRangesByDay = $request->get('times')
foreach($timeRangesByDay as $dayOfWeek => $timeRanges) {
    $preBreakHours = [ 
        $timeRanges['work_from'],
        $timeRanges['break_from']
    ];
    $breakHours = [
        $timeRanges['break_from'],
        $timeRanges['break_to']
    ];
    $postBreakHours = [
        $timeRanges['break_to'],
        $timeRanges['work_to']
    ];

    //left as an exercise for the reader ;)
    $this->businessHoursValidator->validate($preBreakHours, $breakHours, $postBreakHours);
    $this->businessHoursService->createForDay($dayOfWeek, $preBreakHours, $breakHours, $postBreakHours);
}

And the service class is pretty simple:

public function createForDay($dayOfWeek, array $preBreakHours, array $breakHours, array $postBreakHours)
{
    $user = $this->auth->user();
    $dayId = $this->getDayIdFromString($dayOfWeek);
    $preBreak = $this->createHoursInstance($user, $dayId, $preBreakHours[0], $preBreakHours[1]);
    $break = $this->createHoursInstance($user, $dayId, $breakHours[0], $breakHours[1], true);
    $postBreak = $this->createHoursInstance($user, $dayId, $postBreakHours[0], $postBreakHours[1]);

    return compact('preBreak', 'break', 'postBreak');
}

public function createHoursInstance(User $user, $dayId, $startTime, $endTime, $isBreak = false)
{
    return BusinessHours::create([
        'user_id'   => $user->getKey(),
        'weekDay' => $dayId,
        'start_time' => $startTime,
        'end_time' => $endTime,
        'is_break' => (int) $isBreak
    ]);
}

That should be plenty to get you started.

EDIT: @martinbean has the right idea, you should store the two non-break date range and assume anything else means closed.

1 like

Please or to participate in this conversation.