Я пробую следующее: у меня есть две модели (Pub и Schedule), связанные отношениями 1xN следующим образом:
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function pubSchedules()
{
return $this->hasMany(Schedule::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function pub()
{
return $this->belongsTo(Pub::class);
}
Таблица расписаний имеет следующие поля:
id | pub_id | week_day | открытие_время | закрытие_время |
Я использую следующую функцию, чтобы узнать, открыт ли один паб в настоящее время (или нет):
/**
* @return bool
*/
public function isPubCurrentlyOpen()
{
$schedules = Schedule::where([
['pub_id', $this->id ],
['week_day', Carbon::now()->dayOfWeek],
])->get();
foreach ($schedules as $schedule){
$isOpen[] =
Carbon::now('Europe/Madrid')->between(
Carbon::now('Europe/Madrid')->setTimeFromTimeString($schedule->opening_time),
Carbon::now('Europe/Madrid')->setTimeFromTimeString($schedule->closing_time)
);
}
if (in_array(true, $isOpen)){
return true;
//return "Pub Opened";
}
return false;
//return "Pub Closed";
}
В моем PubController я бы хотел, чтобы при выборе опции «Фильтр по открытым пабам» if ($request->openPubs == 1) отображались только открытые пабы isOpen ==true.
Зная отношения между моделями, как я могу это сделать?
Я ищу что-то вроде этого:
if ($request->openPubs == 1)
{
$pubs = $pubs->with('pubSchedules')->where('isOpen' == true);
}
Вы можете помочь мне?
Большое спасибо!
использование $ appends и getOpenPubs () в модели должно дать вам виртуальное поле, которое вы ищете






Для небольших таблиц вы можете вызвать функцию isPubCurrentlyOpen для каждого элемента.
Для этого вам нужно будет изменить свою функцию, чтобы получать pub_id в качестве параметра:
public function isPubCurrentlyOpen($pub_id)
{
$schedules = Schedule::where([
['pub_id', $pub_id ],
['week_day', Carbon::now()->dayOfWeek],
])->get();
foreach ($schedules as $schedule){
$isOpen[] =
Carbon::now('Europe/Madrid')->between(
Carbon::now('Europe/Madrid')->setTimeFromTimeString($schedule->opening_time),
Carbon::now('Europe/Madrid')->setTimeFromTimeString($schedule->closing_time)
);
}
if (in_array(true, $isOpen)){
return true;
//return "Pub Opened";
}
return false;
//return "Pub Closed";
}
и для запроса данных выполните:
if ($request->openPubs == 1)
{
// assuming $pubs is a collection instance
$pubs = $pubs->filter(function($a){
return $this->isPubCurrentlyOpen($a->id);
})
}
Я не совсем понимаю, как вы пытаетесь это сделать, но должно быть что-то вроде этого
$pubs = Pub::with(['pubSchedules' => function ($query) {
$query->where('opening_time', '>' ,Carbon::now()) // make sure it's currently open
->where('closing_time', '<' ,Carbon::now()) // make sure that it's not finished already
->where('week_day', '==' ,Carbon::now()->dayOfWeek) // make sure it's today
}])->find($id);
// to get if pub is currently
if ($pub->pubSchedules->count()){
//
}
you can put this code in the model (Pub) and make some changes
if you already have the object you can do this (Add it to model)
public function isPubOpen()
{
$this->load(['pubSchedules' =>
// same code in other method
]);
return (bool) $this->pubSchedules->count();
}
Вы можете сделать это с помощью whereHas
$openPubs = Pub::whereHas('schedule', function ($query) {
$query->where('week_day', Carbon::now()->dayOfWeek);
$query->whereRaw(
"'".Carbon::now('Europe/Madrid')->format("H:i:s")."' BETWEEN opening_time AND closing_time"
);
})->get();
Предполагается, что время открытия и время закрытия являются подходящим форматом времени, а не строками (хотя строки также будут работать в 24-часовом формате).
Вы можете добиться чего-то похожего на то, что ищете, используя прицел, например.
public function scopeFilterBy($query, $filter = null) {
if ($filter == "isOpen") {
$query->whereHas('schedule', function ($query) {
$query->where('week_day', Carbon::now()->dayOfWeek);
$query->whereRaw(
"'".Carbon::now('Europe/Madrid')->format("H:i:s")."' BETWEEN opening_time AND closing_time"
);
});
}
return $query; //Not sure if this is needed
}
Тогда вы могли бы сделать:
Pub::filterBy($request->openPubs ? "isOpen" : null)->get();
да, это было бы лучшим решением, если он хочет только открытые пабы (у)
@AchrafKhouadja Тогда я, возможно, неправильно понял требование
Большое спасибо за ваш ответ, просто мне нужно то, что вы сделали. У меня есть проблемы с его реализацией, но я надеюсь их решить. Позвольте мне несколько минут, большое спасибо
@BerTsacianegudelTepuy, вы можете прочитать об объемах на laravel.com/docs/5.6/eloquent#query-scopes для более подробной информации о 2-й части
Эта ошибка: Синтаксическая ошибка или нарушение прав доступа: 1064 У вас есть ошибка в синтаксисе SQL; ........ и существует (выберите * из schedules, где pubs.id = schedules.pub_id и week_day = 1 и 2018-06 -11 17:15:56 МЕЖДУ временем открытия И временем закрытия)) в Connection.php (664) «связано с Carbon :: now ('Europe / Madrid')». МЕЖДУ временем открытия И временем закрытия "... знаете ли вы, как решить эту проблему?
Я пропустил цитаты, а вы пропустили часть ->format("H:i:s"). Проверить обновление
В Eloquent есть функция под названием Нетерпеливая загрузка. Eloquent ORM предоставляет простой синтаксис для запроса всех расписаний, связанных с этим конкретным Pub, как описано ниже:
$pubIsOpen= $pub->schedules()
->where([
['week_day', Carbon::now()->dayOfWeek],
['opening_time' , '<' , Carbon::now('Europe/Madrid')],
['closing_time' , '>' , Carbon::now('Europe/Madrid')]
])
->count();
if ($openPubCount > 0){
//PUB is open
}else{
//PUB is closed
}
Если это кому-то поможет в будущем, я публикую свое решение благодаря @apokryfos:
/**
* @param $pubs
* @return mixed
*/
public static function isPubCurrentlyOpen($pubs)
{
$pubs->whereHas( 'pubSchedules', function ($pubs) {
$pubs->where( 'week_day', Carbon::now()->dayOfWeek )
->whereRaw(
"'" . Carbon::now( 'Europe/Madrid' )->format( "H:i:s" ) . "' BETWEEN opening_time AND closing_time"
);
} );
return $pubs;
}
/**
* @param GetPubRequest $request
* @return ApiResponse
*/
public function getPubs(GetPubRequest $request)
{
$orderBy = 'id';
$order = 'asc';
$pubs = Pub::withDistance();
............
if ($request->openPubs == 1)
{
$pubs = Pub::isPubCurrentlyOpen($pubs);
}
return $this->response(PubProfileResource::collection($pubs->orderBy($orderBy, $order)->paginate()));
}
Может вы это ищете: laravel.com/docs/5.6/eloquent-relationships#eager-loading