我如何在 eloquent 查询中使用连接变量并使用 Carbon 对其进行操作以获得我需要的结果

How can I use a joined variable in an eloquent query and manipulate it with Carbon to get the results I need

Laravel "^9.0"

我有点卡住了,因为我尝试构建的查询结果将解决一个更大的问题。情况是这样的:我有一个系统可以存储一天中的时间以向用户发送提醒。时间不与其他任何东西一起存储,而是与它们的时区相关联地存储。因此,如果用户在 America/Los_Angeles 时区,并且 select 每天下午 1 点提醒,他们应该在下午 1 点收到提醒。服务器和应用程序都在 UTC。因为我没有存储时间戳(我不需要日期,只需要一天中的时间,我发现在没有重要查询的情况下几乎不可能构建提醒逻辑(首先获取所有提醒,解析给用户,获取时区,然后按时间排序 selected)。我想通过简单的 JOIN 在使用用户时区的同时查询时间,但是,我似乎无法弄清楚如何使用 users.timezone 从 JOIN 开始工作。

提醒作业每 5 分钟运行一次,用户只能以 5 分钟为间隔 select 个提醒(例如 5:45 pm(存储为 17:45 pm))。 下面是看似简单的eloquent查询:

$reminders = Reminder::join('users as users', 'users.id', '=', 'reminders.user_id')
        ->where('reminders.time', '>=', Carbon::now()->subMinutes(2)->setTimezone('users.timezone')->format('G:i:s'))
        ->where('reminders.time', '<=', Carbon::now()->addMinutes(2)->setTimezone('users.timezone')->format('G:i:s'))
        ->get();

这里是错误:

  Carbon\Exceptions\InvalidTimeZoneException 

  Unknown or bad timezone (users.timezone)

  at vendor/nesbot/carbon/src/Carbon/CarbonTimeZone.php:106
    102▕         }
    103▕ 
    104▕         if ($tz === false) {
    105▕             if (Carbon::isStrictModeEnabled()) {
  ➜ 106▕                 throw new InvalidTimeZoneException('Unknown or bad timezone ('.($objectDump ?: $object).')');
    107▕             }
    108▕ 
    109▕             return false;
    110▕         }

      +2 vendor frames 
  3   app/Console/Commands/SendReminders.php:48
      Carbon\Carbon::setTimezone("users.timezone")

      +13 vendor frames 
  17  artisan:37
      Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))

如有任何帮助,我们将不胜感激。谢谢。

所以,事实证明我试图做的事情是不可能的(甚至 Taylor Otwell 在 Twitter 上发帖 - https://twitter.com/taylorotwell/status/1500100606274551816?s=21)。所以,我想我会折回并展示我最终做了什么:

首先,当我存储提醒时,我将其与当前用户时区和 UTC 一起存储,因此我有正确的时间用于其中任何一个。这里复杂的部分只是为了获得正确的偏移量,因为我没有存储完整的日期,只存储了小时和分钟。

然后在发送提醒的作业中,我有这个查询(替换上面的问题查询):

$results = Reminder::with('user')
        ->where('timeTz', Carbon::now()->format('H:i'))
        ->get();

我正在使用 Carbon::now(),因为我的应用程序以 UTC 运行,这就是 timeTz 的存储方式。我也是不看秒,只看时分。

那么,如果不是数千个查询(N+1,上面问题之前的原始问题),那么现在是一个。

我非常感谢 Twitter 上的 PHP 社区 - 一些重要的重量级人物出来并试图提供帮助。最终,上述解决方案最有意义。