Я новичок в Laravel и пытаюсь реализовать даты бронирования, которые не могут совпадать ни в какой день.
У меня есть модель под названием «Заказы», которая включает room_id, start_date и end_date.
У меня есть проверка, которая проверяет, что дата окончания не может быть раньше начала:
$this->validate($request, [
'start_date' => 'required|date',
'end_date' => 'required|date|after_or_equal:start_date',
]);
Однако я не уверен, как проверить, что диапазон дат не конфликтует с другими диапазонами дат того же room_id, хранящегося в таблице бронирования (поскольку одна комната не может быть забронирована дважды в одном диапазоне).
Любая помощь будет оценена,
Спасибо!






Есть встроенный углеродный метод isPast (), поэтому вы можете использовать:
$start_date->isPast()
$end_date->isPast()
Вы можете проверить, были ли оба выбранных объекта забронированы ранее.
Если вы не использовали Carbon, вот ссылка: https://carbon.nesbot.com/docs/
Вы должны проверить это в базе данных. Итак, вы можете сделать это:
$result = Bookings::where('start_date', '<=' $request->start_date)->where('end_date', '>=' $request->end_date)->where('room_id',$request->room_id)->first();
if (!$result){
// Code to Book room
}
При типичном перекрытии, учитывая два события A и B, вы должны рассмотреть четыре сценария:
Итак, в sql, чтобы проверить, занята ли комната в интервале дат, скажем, 2018-11-20 'и' 2018-11-30 ', это будет:
select *
from rooms
where
start_date between '2018-11-20' and '2018-11-30' or
end_date between '2018-11-20' and '2018-11-30' or
'2018-11-20' between start_date and end_date or
'2018-11-30' between start_date and end_date;
В laravel я создаю область видимости в модели.
public function scopeByBusy($query,$start_date,$end_date)
{
return $query->whereBetween('start_date', [$start_date, $end_date])
->orWhereBetween('end_date', [$start_date, $end_date])
->orWhereRaw('? BETWEEN start_date and end_date', [$start_date])
->orWhereRaw('? BETWEEN start_date and end_date', [$end_date]);
}
Наконец, я могу проверить, занята ли комната с идентификатором 95 в период между 2018-11-20 и 2018-11-30, вот так:
$room_id = 95;
$start = '2018-11-20';
$end = '2018-11-30';
$exists = Rooms::where('id', $room_id)
->byBusy($start, $end)
->first();
if ($exists)
{
echo "the room is busy in the interval you selected";
}
Надеюсь, это вам поможет.
Спасибо @Namoshek. Я некоторое время играл с Laravel и другими вещами, но я так и не дал ответа, думаю, пришло время поделиться тем, что я узнал, с другими :). Спасибо, что поправили меня. Это хороший момент. Безопасность. Я не учел этого, потому что даты должны передавать запрос валидатора с правилами ['required', 'date_format: d / m / Y'] и даже использовать объект настраиваемого правила, чтобы проверить, что вторая дата больше или равно первой дате. Затем, когда даты попадают в контроллер, я форматирую их в формате базы данных «Y-m-d», затем я использую объем модели.
Я немного опоздал, но нужен ли orWhereRaws? Думаю, достаточно двух условий. Последние - ненужные проверки.
У меня было аналогичное использование, когда мне нужно было проверить, запланировал ли человек что-то в диапазоне дат
Пример кода Laravel ниже:
$start = Carbon::parse($request['start_date'])->format('Y-m-d 00:00:00');
$end = Carbon::parse($request['end_date'])->format('Y-m-d 23:59:59');
$existsActive = Microsite::where(function ($query) use ($start) {
$query->where('start_date', '<=', $start);
$query->where('end_date', '>=', $start);
})->orWhere(function ($query) use ($end) {
$query->where('start_date', '<=', $end);
$query->where('end_date', '>=', $end);
})->count();
if ($existsActive > 0 ){
echo "Already exists";
}
Я просто хотел проверить, есть ли у меня какие-либо перекрывающиеся записи в базе данных. Это сработало для меня.
Очень хороший первый ответ. Я быстро просмотрел ваш пост и изменил форматирование на то, что обычно используется при переполнении стека. Также я исправил уязвимость SQL-инъекции во втором блоке кода. Вы можете использовать возможность построителей запросов для привязки параметров за вас, иначе запрос будет небезопасным. Но тем не менее хороший ответ!