Динамические c временные интервалы с интервалом в один час и динамические c интервалы тоже - PullRequest
0 голосов
/ 30 января 2020

У меня есть время возврата и время проверки, у меня уже есть код для динамических c временных интервалов, но я борюсь с динамическими c интервалами. Код ниже -

$attendance = Attendance::where('user_id', '=', $request->user()->id)->latest()->first();
if(!is_null($attendance) && !is_null($attendance->checkout)){
    $created = (string) $attendance->created_at;
    $timing = array($created);
    $main_diff = Carbon::parse($created)->diffInSeconds($attendance->checkout, false);

    $modul = $main_diff % 3600;
    $main_amount = $main_diff - $modul;
    $count = $main_amount/3600;

    if($count > 1){
        for($x=0; $x <= count($timing); $x++){
            $diff = Carbon::parse($timing[$x])->diffInSeconds($attendance->checkout, false);
            if($diff > 0){
                if($x==0){
                    array_push($timing, (string) Carbon::parse($timing[$x])->minute(0)->second(0)->addHour());
                }
                elseif($x>0 and $x<$count){
                    $var = Carbon::parse($timing[$x]);
                    array_push($timing, (string) $var->addHour());
                }
                elseif($x == $count){
                    array_push($timing, (string) $attendance->checkout);
                }
            }
            else{
                break;
            }
        }

        $timings = [];
        $last;
        foreach($timing as $edit){
            if(isset($last)){
                $timings[] = $last.' - '.Carbon::parse($edit)->format('h:i');
            }
            $last = Carbon::parse($edit)->format('h:i');
        }
        $variable['data'] = $timings;
        return response(json_encode($variable), 200);
    }
}

Вывод вышеприведенного кода -

10:15-11:00
11:00-12:00
12:00-12:18

Теперь есть два разных события EventFirst, EventSecond - я хочу интегрировать время событий в Основные сроки. Например -

10:15 - 11:00
11:00 - EventFirst->start_time
EventFirst->start_time - EventFirst->end_time
EventFirst->end_time - Next Nearest Hour
Next Nearest Hour - EventSecond->start_time
EventSecond->start_time - EventSecond->end_time
EventSecond->end_time - Next Nearest Hour
Next Nearest Hour - Checkout Time 

Проблема в том, что событие не является экземпляром, это коллекция, полученная из базы данных. Итак, что мне нужно сделать, это сначала взять все моменты из событий в массиве и проверить каждую итерацию.

Я не знаю человека, мой мозг готов.


Лучшее объяснение

У меня есть три таблицы, а именно -

Посещаемость, Событие Один, Событие Два

Теперь Соответствующие столбцы в каждой таблице -

Посещаемость

| ____ checkout_time (Carbon Timestamp)

| ____ созданный_at (Carbon Timestamp)

Событие 1

| ____ event_start (Carbon Timestamp)

| ____ event_duration (Int (Seconds))

Событие два

| ____ event_time (углеродная временная метка)

| ____ event_end_time (углеродная временная метка)

Что теперь является основным Требуется, чтобы в соответствии с таблицей посещаемости использовались часовые интервалы, кроме времени регистрации и проверки, поэтому формат должен быть -

checkin - Next Nearest Hour (e.g - 10:15-11:00)
Last Hour - Next Hour (e.g 11:00-12:00, 12:00-13:00, etc)
Nearest Hour Before Checkout - checkout (e.g - 18:00-18:22) 

Полученные выше результаты получены.

Теперь проблема возникает, когда мне нужно добавить временные интервалы из двух других событий, в основных временных интервалах.

Так что формат теперь становится -

checkin - Nearest Hour (e.g 11:34 - 12:00)
(Assuming Event one exists)
(case 1) -
If eventOne start and end is between Nearest Hour and the Next Hour add it in between
(e.g - 12:00-12:06, **12:06-12:54**, 12:54-13:00) 
(case 2) - 
If eventOne end crosses the Next Hour, unset the normal interval
(e.g - 12:00-12:06, **12:06-13:28**, 13:28-14:00)
Same Goes for eventTwo

Теперь все ясно?

Ответы [ 2 ]

0 голосов
/ 05 февраля 2020

Я бы начал с добавления слотов для событий первым. Затем проверка, затем проверка. И, только в конце, вычислите часовые интервалы.

Я не сделал часовые интервалы, которые вы уже сделали.

Вот пример.

Но все еще нужны некоторые проверки для крайних случаев, таких как даты (события, регистрация, извлечение), которые ежечасно (например, 11:00)

class ComputeTimeSlots {
    /** @var Carbon */
    public $checkin;
    /** @var Carbon */
    public $checkout;
    /** @var \Illuminate\Support\Collection */
    public $events;
    /** @var \Illuminate\Support\Collection */
    public $slots;

    /**
     * ComputeTimeSlots constructor.
     * @param $checkin
     * @param $checkout
     * @param \Illuminate\Support\Collection $events
     */
    public function __construct(Carbon $checkin, Carbon $checkout, Collection $events)
    {
        $this->checkin = $checkin;
        $this->checkout = $checkout;
        $this->events = $events;
        $this->slots = collect();
    }

    public function handle()
    {
        // First the Events
        foreach ($this->events as $event) {
            /** @var EEvent $event */
            $this->slots->push(
                new Slot($event->start, $event->end)
            );
        }

        // Then Checking
        /** @var Carbon $earliest_event_start_date */
        $earliest_event_start_date = $this->events->pluck('start')->sort()->first();
        $hourAfterCheckin = $this->checkin->clone()->setMinute(0)->addHour();

        if($hourAfterCheckin < $earliest_event_start_date) {
            $this->slots->push(
                new Slot($this->checkin, $hourAfterCheckin)
            );
        } else {
            $this->slots->push(
                new Slot($this->checkin, $earliest_event_start_date)
            );
            $hourAfterEvent = $earliest_event_start_date->clone()->setMinute(0)->addHour();
            $this->slots->push(
                new Slot($earliest_event_start_date, $hourAfterEvent)
            );
        }

        // Then Checkout
        /** @var Carbon $earliest_event_start_date */
        $last_event_end_date = $this->events->pluck('end')->sort()->last();
        $hourBeforeCheckout = $this->checkout->clone()->setMinute(0);

        if($hourBeforeCheckout > $last_event_end_date) {
            $this->slots->push(
                new Slot($hourBeforeCheckout, $this->checkout)
            );
        } else {
            $this->slots->push(
                new Slot($last_event_end_date, $this->checkout)
            );
            $hourBeforeEvent = $last_event_end_date->clone()->setMinute(0);
            $this->slots->push(
                new Slot($hourBeforeEvent, $last_event_end_date)
            );
        }
        $this->slots = $this->slots->sortBy('start');

        // Then compute hourly intervals

        return $this;
    }
}

class Slot {
    /** @var \Carbon\Carbon */
    public $start;
    /** @var \Carbon\Carbon */
    public $end;

    /**
     * Slot constructor.
     * @param \Carbon\Carbon $start
     * @param \Carbon\Carbon $end
     */
    public function __construct(Carbon $start, Carbon $end)
    {
        $this->start = $start;
        $this->end = $end;
    }

    public function toArray()
    {
        return "{$this->start->format('H:i')}-{$this->end->format('H:i')}";
    }
}

class EEvent extends Slot{}

Пример:

$c1 = new ComputeTimeSlots(
    Carbon::parse('10:15'),
    Carbon::parse('18:22'),
    collect([
        new EEvent(Carbon::parse('12:06'), Carbon::parse('12:54')),
        new EEvent(Carbon::parse('13:06'), Carbon::parse('14:30'))
    ])
);

var_dump($c1->handle()->slots->map->toArray()->all());

Выводит :

enter image description here

0 голосов
/ 02 февраля 2020

Если я правильно понимаю, вы можете сделать что-то вроде следующего. (Стоит отметить, что я сделал некоторые другие улучшения в коде)

$attendance = Attendance::query()
    ->where('user_id', '=', auth()->id())
    ->whereNotNull('checkout')
    ->latest()
    ->first()

if ($attendance !== null) {
    $hours     = $attendance->created_at->diffInHours($attendance->checkout);
    $createdAt = $attendance->created_at->copy()->startOfHour();
    $data      = [];

    if ($hours) {
        for($i = 0; $i < $hours; $i++) {
            $data[] = $createdAt->format('h:i') . ' - ' . $createdAt->addHour()->format('h:i');
        }

        return response()->json(compact('data'));
    }
}

Я сломаю изменения в коде ниже.

Attendance::query()

The query() Метод это просто метод stati c во всех моделях, которые возвращают новый экземпляр построителя запросов. Ваш исходный код назвал это внутренне, но я просто предпочитаю использовать его, так как он запускается красиво, поэтому я могу отформатировать его построчно.

whereNotNull()

Это один из методов Laravels magi c where, и добавит предложение WHERE column NOT NULL к SQL. Это означает, что вы получите результаты только в том случае, если столбец извлечения не пуст, то есть вам не нужно проверять его.

$hours = $attendance->created_at->diffInHours($attendance->checkout);

В исходном коде вы были:

  • Преобразование экземпляра углерода в строку,
  • Анализ этого экземпляра в углероде
  • Вычисление разницы в секундах
  • Вычисление количества секунд, оставшихся после работы из часов
  • Вычитание дополнительных секунд из разницы в секундах
  • Вычисление количества часов в разнице в секундах

Гораздо проще использовать Углеродный метод diffInHours().

$createdAt = $attendance->created_at->copy()->startOfHour();

Экземпляры углерода изменчивы, поэтому при каждой внесенной вами модификации объект меняется, а не возвращается новый. Это создает копию и устанавливает метку времени как начало этого часа.

Следующий бит самый простой. Вместо того, чтобы усложнять все эти условия в l oop, проще просто выполнить итерацию на основе разницы часов.

$data[] = $createdAt->format('h:i') . ' - ' . $createdAt->addHour()->format('h:i');

Поскольку экземпляры Carbon являются изменяемыми, вторая часть этой строки будет добавьте час, который будет означать, что экземпляр углерода обновляется при следующем запуске первой части.

return response()->json(compact('data'));

Laravel в ответах есть метод json(), позволяющий вернуть json ответ без необходимости кодировать его вручную.

Надеюсь, я правильно понял проблему и надеюсь, что это поможет.

...