【问题标题】:Eloquent "whereDate" not working after Laravel 5.4 UpgradeLaravel 5.4 升级后雄辩的“whereDate”不起作用
【发布时间】:2017-07-07 15:38:45
【问题描述】:

(抱歉,长篇大论)

我正在将我的应用程序从 laravel 5.2 升级到 5.4,并且从今天早上开始一直被这个问题困扰。出于某种原因,我使用 Eloquent 'whereDate' 选择即将发生的业务事件的查询没有返回任何内容,即使其他所有内容都表明它应该可以正常工作!

我有一个无法通过的 phpUnit 测试来尝试定位问题。 (见下文)

我有一个“商业”模型:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Business extends Model
{
    protected $table = 'businesses';
    ..

public function businessEvents(){
    return $this->hasMany('App\BusinessEvent', 'business_id');
}

以及“BusinessEvent”模型:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class BusinessEvent extends Model
{
  protected $table = 'business_events';
  protected $fillable = ['business_id', ..., 'start_date', 'end_date'];

  public function business(){
      return $this->belongsTo('App\Business', 'business_id');
  }
...

我在测试中制作了这两个版本的虚拟版本。虚拟“业务”适用于其他测试,但我为此测试用例引入了以下 虚拟“业务事件”

protected function createMockBusinessEventWithUpcomingDateTime($businessId){
  $faker = Faker::create();

  $businessEvent = BusinessEvent::create([
      'business_id'   => $businessId,
      'name'          => $faker->name,
      'description'   => $faker->text,
      'start_date'    => date("Y-m-d H:i:s", strtotime(date("Y-m-d H:i:s")."+30 minutes")),
      'end_date'      => date("Y-m-d H:i:s", strtotime(date("Y-m-d H:i:s")."+1 hour +30 minutes"))
  ]);

  ...

  $business = Business::find($businessId);
  if($business){
    $businessEvent->business()->associate($business);
  }

  return $businessEvent;
}

现在是实际的 test 函数:

public function testGetUpcomingN(){

    $this->businessEvent  = $this->createMockBusinessEventWithUpcomingDateTime($this->business->id);

    $response = $this->json('GET', '/api/v1/business/'.$this->business->id.'/events/upcoming/2');

    $this->outp($response->content());

    $this->outp("Testing Assertions");
    $this->assertEquals(200, $response->status());  
    $this->assertEquals($this->business->businessEvents()->first()->id, $this->businessEvent->id);     
}

测试没有失败,这意味着事件正确地与业务相关联,并且无论我如何查询 api 端点(HttpRequester、日志记录结果、测试中的返回值、生产...)它总是返回一个空数组!

以下函数是控制器中调用的(也已验证!):

public function upcomingN($businessId, $n){
    Log::info('Get upcoming '.$n.' recorded events for business with id: '.$businessId);
    $business = Business::find($businessId);
    if (is_null($business)){
        Log::warning('No business exists with given id. Exiting.');
        return response('No Content.', 204);
    }

    $currentDate = date('Y-m-d H:i:s');

    $greaterThan = $business->businessEvents()->first()->end_date >= $currentDate;
    Log::info("Greater THAN:", [$greaterThan]);

    $events = $business->businessEvents()->whereDate('end_date', '>=', $currentDate)->take($n)->get();

    if (!is_null($events)){
        Log::info('Got upcoming N recorded events for business with id: '.$businessId, (array) $events);
        return response()->json($events);
    }

    return response('No Content.', 204);
}

如您所见,我什至尝试记录“$greaterThan”布尔值,它应该测试与“whereDate”完全相同的东西,它的计算结果为真!我已经尝试过 Carbon::parse()-ing,设置语言环境,现在我几乎没有想法了。

在 5.2 中工作的旧功能

public function upcomingN($businessId, $n){
   Log::info('Get upcoming N recorded events for business with id: '.$businessId);
$business = Business::find($businessId);
if (is_null($business)){
    Log::warning('No business exists with given id. Exiting.');
        return response('No Content.', 204);
    }

    $currentDate = date('Y-m-d H:i:s');
    $events = $business->businessEvents()->whereDate('start_date', '>=', $currentDate)->take($n)->get();

     if (!is_null($events)){
         Log::info('Got upcoming N recorded events for business with id: '.$businessId, (array) $events);
         return response()->json($events);
     }

    return response('No Content.', 204);
}

在升级过程中我确实必须更改的一件事是将 mysql-db 设置为非严格,因为 Laravel 抱怨缺少默认值。但是,我已经检查了数据库,并且测试条目已正确填充。

任何帮助将不胜感激!

【问题讨论】:

  • 我认为您应该首先记录$business-&gt;businessEvents()-&gt;first()-&gt;end_date 的值并查看它返回的内容,然后您可以告诉它是否可以告诉您是否还有更多需要考虑
  • 我确实记录了这个值,它是"2017-07-07 18:32:01",而比较值(当前日期)输出为"2017-07-07 17:29:39"。正是我所期望的:/
  • 您可以检查两件事:我对字符串或日期时间对象的日期时间比较不太自信,因为根据内部转换,Laravel 的模型日期时间字段可能会返回作为字符串或 Carbon 对象,所以我建议即使您也可以简单地使用:Carbon::now()-&gt;greaterThan(Carbon::parse($business-&gt;businessEvents()-&gt;first()-&gt;end_date)); 也尽量不要使用 whereDate() 并使用 where()
  • 谢谢,使用 where() 是解决方案!我以为我已经尝试过了,但肯定有其他东西在干扰(或者我搞砸了其他东西)......

标签: php mysql laravel eloquent


【解决方案1】:

非常感谢Omisakin Oluwatobi,解决方案实际上是使用 Eloquent 'where' 而不是 'whereDate',因为 'whereDate' 只比较 dates 而不是 date次(事后看来这很明显)。

如果您可以使用相同数量的代码实现与“where”相同的结果,那么存在“whereDate”函数有点令人困惑。

我可以验证(经过单元测试)以下最终解决方案适用于选择未来的日期时间并忽略过去的日期时间:

public function upcomingN($businessId, $n){
    Log::info('Get upcoming '.$n.' recorded events for business with id: '.$businessId);
    $business = Business::find($businessId);

    if (is_null($business)){
        Log::warning('No business exists with given id. Exiting.');
        return response('No Content.', 204);
    }

    $currentDate = date('Y-m-d H:i:s');
    $events = $business->businessEvents()->where('end_date', '>=', $currentDate)->take($n)->get();

    if (!is_null($events)){
        Log::info('Got upcoming N recorded events for business with id: '.$businessId, (array) $events);
        return response()->json($events);
    }

    return response('No Content.', 204);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-11
    • 2017-10-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-12
    • 1970-01-01
    • 2023-04-07
    相关资源
    最近更新 更多