Я работаю над проектом по аренде квартир. В рамках возможностей приложения владелец квартиры может выбрать дни, в которые квартира будет доступна для сдачи в аренду гостям. Я пишу поисковый запрос, чтобы получить квартиры, где он, среди прочего, проверяет дни, доступные для аренды. У меня есть следующие таблицы: номера, бронирования, дни, day_room (сводная таблица). Поскольку я здесь новичок, пожалуйста, дайте мне знать, если мне нужно опубликовать что-нибудь еще, чтобы вы лучше поняли мою проблему.
В этом запросе, когда я бы написал статическую дату, например, «2024-06-27», в последнем методе Where, она работала бы нормально и давала желаемые результаты, но при использовании $date->format('Y-m-d') это не так. ничего не нахожу. Однако в созданном SQL-запросе я не вижу какой-либо разницы, то есть в формате дат.
namespace App\Http\Controllers;
use App\Models\Room;
use App\Models\Booking;
use Carbon\CarbonPeriod;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class SearchController extends Controller
{
public function index()
{
// Validate data later
$city = request('city');
$guests_number = request('guests_number');
$object_type = request('object_type');
$checkIn = request('checkIn');
$checkOut = request('checkOut');
$interval = CarbonPeriod::create($checkIn, $checkOut);
$rooms = Room::query()
->with(['photos', 'bookings', 'days'])
->where('rooms.city_id', '=', $city)
->where('rooms.beds_num', '>=', $guests_number)
->where('rooms.object_type_id', '=', $object_type)
->join('bookings', 'bookings.room_id', '=',
'rooms.id')
->where(function ($query) use ($checkIn, $checkOut) {
$query->where('checkIn', '>=', $checkOut)
->orWhere('checkOut', '<=', $checkIn);
})
->whereExists(function ($query) use ($interval) {
$query
->from('day_room')
->join('days', 'days.id', '=', 'day_room.day_id')
->whereColumn('day_room.room_id', 'rooms.id')
->where(function ($query) use ($interval) {
foreach ($interval as $date) {
$query->where('days.day', '=', $date->format('Y-m-d'));
// when testing if I write static date like here, then it works.
// $query->where('days.day', '=', '2024-06-27');
}
});
})
->get('rooms.*');
return view('results', ['rooms' => $rooms]);
}
Вместо перебора объекта $interval вы можете использовать предложение whereBetween(). При этом не должно быть никакой разницы между $date->format('Y-m-d') и '2024-06-17', если предположить, что одна итерация вашего $interval действительно содержит эту дату, как предлагает Дхрув.
Просто передайте объект даты Carbon. Laravel достаточно умен, чтобы преобразовать его соответствующим образом. Убедитесь, что ваша модель выполнена правильно.
Вы можете добавить ->ddRawSql() в конце, чтобы увидеть фактически созданный запрос. Что может быть полезно для отладки и оптимизации. Или используйте что-то вроде debugbar. Я думаю, проблема в запросе, я думаю, вы пытаетесь сопоставить несколько days.day в одной ячейке. Только одна может быть правдой, поэтому, если вы жестко запрограммируете только одну дату, она будет работать.
В foreach вы вставляете несколько условий, связанных оператором AND: условия никогда не будут удовлетворены. Вместо этого вам следует использовать orWhere(), но, как предложил @TimLewis,whereBetween() является лучшим выбором.
@DhruvPandya, да, при тестировании я использовал 27 июня 2024 г. как $checkIn и 29 июня 2024 г. как $checkOut. Обе даты доступны в таблице БД.
@TimLewis, я пробовал разные способы использованияwhereBetween() в моем запросе, ни один из которых не дал требуемого результата, что, по меньшей мере, сбивает с толку.
@TimLewis, спасибо. Я отредактирую вопрос и опубликую ответ. Все еще новичок в stackoverflow. :)
Без проблем; добро пожаловать в ТАК 🙂 Кроме того, да, трудно сказать, почему whereBetween() не сработало бы для вас, но в конечном итоге, если у вас есть решение, которое дает правильные результаты, это более важно; оптимизация может прийти позже. Ваше здоровье!
@TimLewis, спасибо! Я слышал, что у Laravel отличное сообщество, но получить помощь из первых рук — это потрясающе, это действительно вдохновляет меня учиться больше и работать усерднее. Ребята, вы потрясающие! Удачи в ваших проектах!






Спасибо всем за ваши отзывы в разделе комментариев. @Rene и @Tupkap заставили меня задуматься в правильном направлении - я проверял несколько дней в одной ячейке. Я исправил это, переместив цикл foreach. Ниже приведена отредактированная версия кода, которая у меня работает. Думаю, это не самый изящный способ решения проблемы, но так как квартиры не бронируются на длительный срок (обычно на пару дней и не дольше 1-2 недель).
namespace App\Http\Controllers;
use App\Models\Room;
use App\Models\Booking;
use Carbon\CarbonPeriod;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class SearchController extends Controller
{
public function index()
{
// Validate data later
$city = request('city');
$guests_number = request('guests_number');
$object_type = request('object_type');
$checkIn = request('checkIn');
$checkOut = request('checkOut');
$interval = CarbonPeriod::create($checkIn, $checkOut);
$rooms = Room::query()
->with(['photos', 'bookings', 'days'])
->where('rooms.city_id', '=', $city)
->where('rooms.beds_num', '>=', $guests_number)
->where('rooms.object_type_id', '=', $object_type)
->join('bookings', 'bookings.room_id', '=', 'rooms.id')
->where(function ($query) use ($checkIn, $checkOut) {
$query->where('checkIn', '>=', $checkOut)
->orWhere('checkOut', '<=', $checkIn);
})
->where(function ($query) use ($interval) {
foreach ($interval as $date) {
$query->whereExists(function ($query) use ($date) {
$query
->from('day_room')
->join('days', 'days.id', '=', 'day_room.day_id')
->whereColumn('day_room.room_id', 'rooms.id')
->where('days.day', '=', $date->format('Y-m-d'));
});
}
})
->get('rooms.*');
return view('results', ['rooms' => $rooms]);
}
Какие даты вы принимаете в качестве $checkIn и $checkOut? Включает ли это указанную дату? 27.06.2024