Eloquent: запрос с использованием несуществующего столбца - PullRequest
0 голосов
/ 11 июня 2018

Я пытаюсь сделать следующее: у меня есть две модели (Pub и Schedule), связанные отношением 1xN следующим образом:

Pub:

/**
 * @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 |день недели |Время открытия |close_time |

Я использую следующую функцию, чтобы узнать, открыт ли в данный момент (или нет) один паб:

/**
 * @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 я бы хотел, чтобы опция «Фильтровать по открытой»pubs "выбрано if($request->openPubs == 1), чтобы показывать только открытые пабы isOpen ==true.

Зная отношения между моделями, как я могу это сделать?

Я ищу что-то вроде этого:

 if($request->openPubs == 1)
 {
   $pubs = $pubs->with('pubSchedules')->where('isOpen' == true);
 }

Вы можете мне помочь?

Спасибо большое!

Ответы [ 5 ]

0 голосов
/ 12 июня 2018

Если это поможет кому-то в будущем, я опубликую свое решение, благодаря @apokryfos:

Pub:

/**
 * @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;
}

PubsController:

/**
 * @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()));
}
0 голосов
/ 11 июня 2018

В Eloquent есть функция под названием Eager Loading .Eloquent ORM предоставляет простой синтаксис для запроса всех расписаний, связанных с этим конкретным пабом, как описано ниже:

$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
}
0 голосов
/ 11 июня 2018

Я не совсем понимаю, как вы пытаетесь это сделать, но должно быть что-то вроде этого

   $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();
}
0 голосов
/ 11 июня 2018

Вы можете сделать это, используя "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(); 
0 голосов
/ 11 июня 2018

Для небольших таблиц вы можете вызвать функцию 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);
   })
}
...