【问题标题】:Eloquent: querying using a non-existing columnEloquent:使用不存在的列进行查询
【发布时间】:2018-06-11 13:51:27
【问题描述】:

我正在尝试以下操作:我有两个通过 1xN 关系相关的模型(Pub 和 Schedule),如下所示:

酒馆:

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

表计划具有以下字段:

标识 | pub_id |工作日 |开放时间 |关闭时间 |

我使用以下函数来了解一个酒吧当前是否(或未)开放:

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

In my PubController I'd like, when the option "Filter by open pubs" is chosen if($request->openPubs == 1), to show only opened pubs isOpen ==true.

知道模型之间的关系,我该怎么做?

我正在寻找这样的东西:

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

你能帮帮我吗?

非常感谢!

【问题讨论】:

标签: laravel orm eloquent filtering


【解决方案1】:

您可以使用“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(); 

【讨论】:

  • 是的,如果他只想要开放的酒吧 (y),这将是最好的解决方案
  • @AchrafKhouadja 当时我可能误解了要求
  • 非常感谢您的回答,只是我需要您所做的。我在实现它时遇到了一些问题,但我希望能解决它们。让我几分钟,非常感谢
  • @BerTsacianegudelTepuy 您可以在laravel.com/docs/5.6/eloquent#query-scopes 阅读有关范围的信息,以了解第二部分的更多详细信息
  • 此错误:语法错误或访问冲突:1064 您的 SQL 语法有错误;........并且存在(select * from schedules where pubs.@ Connection.php (664) 中的 987654327@ = schedules.pub_idweek_day = 1 和 2018-06-11 17:15:56 BETWEEN opening_time AND closing_time)" 是由于 Carbon::now('欧洲/马德里')。” BETWEEN opening_time AND closing_time"...你知道怎么解决吗?
【解决方案2】:

我不完全理解你是如何做到这一点的,但它应该是这样的

   $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();
}

【讨论】:

    【解决方案3】:

    对于小表格,您可以为每个元素调用函数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);
       })
    }
    

    【讨论】:

      【解决方案4】:

      Eloquent 中有一个名为 Eager Loading 的功能。 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
      }
      

      【讨论】:

        【解决方案5】:

        如果将来对某人有帮助,我会发布我的解决方案,感谢@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;
        }
        

        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()));
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-05-28
          • 1970-01-01
          • 2018-09-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-12-08
          • 1970-01-01
          相关资源
          最近更新 更多