【问题标题】:How to get latest record on a relationship in Laravel如何在 Laravel 中获取关系的最新记录
【发布时间】:2019-09-08 10:53:09
【问题描述】:

用户的计划存储在invoices 表中。这些计划是按月计算的。

我需要做什么

如果用户的计划到期日期已到并且他们没有更新他们的计划,我想为用户添加一个新行(我不想更新旧的)

问题是

每个用户在每个月更新时,invoices 表中的行数不受限制。现在,当我尝试检索他们的最新行并检查到期日期时,它也会获取这些用户的其他行。

示例

  1. 我的用户在invoices 中有3 rows
  2. 其中两个已经过期续订,当前一个是id=3
  3. 当我尝试使此 id=3 过期并为此用户创建 id=4
  4. 它获取所有3 rows 并向用户发送3 封电子邮件。

代码

public function handle()
    {
        $invoices = Invoice::where('plan_expire', '<=', Carbon::now())->get();
        $current = Carbon::now();
        $expiredatetime = $current->addDays(30);
        $useType = Type::where('name', 'Free')->first();

        foreach($invoices as $invoice)
        {
            Invoice::create([
                'user_id' => $invoice->user->id,
                'type_id' => $useType->id,
                'amount' => $useType->price,
                'status' => 'Approved',
                'plan_expire' => $expiredatetime->toDateTimeString(),
            ]);
            Mail::to($invoice->user->email)->send(new UserPlansReset($invoice));
        }
    }

User model

public function invoices()
{
  return $this->hasMany(Invoice::class);
}

Invoice model

protected $fillable = [
        'user_id', 'type_id', 'amount', 'status', 'plan_expire',
    ];

    protected $casts = [
        'plan_expire' => 'datetime',
    ];

    public function user()
    {
        return $this->belongsTo(User::class);
    }

问题

您知道我如何才能在invoices 表中获取用户的最新行吗?

更新

根据下面的答案,我将代码更改为:

$current = Carbon::now();
        $expiredatetime = $current->addDays(30);
        $useType = Type::where('name', 'Free')->first();

        $users = User::all();
        foreach($users as $user){
          $latestInvoice = $user->invoices()->latest()->first();

          if(!empty($latestInvoice) && $latestInvoice->plan_expire <= Carbon::now()){
              Invoice::create([
                  'user_id' => $user->id,
                  'type_id' => $useType->id,
                  'amount' => $useType->price,
                  'status' => 'Approved',
                  'plan_expire' => $expiredatetime->toDateTimeString(),
              ]);
              Mail::to($user->email)->send(new UserPlansReset($user));
          }
        }

现在这个函数会返回

Expected response code 220 but got an empty response

并且不会发送电子邮件

【问题讨论】:

    标签: php laravel


    【解决方案1】:

    查找过期发票,按用户 ID 分组,按plan_expire 订购,然后选择每个组中的第一条记录。

    MySQL 服务器版本

    一种解决方法是设置客户端变量,这些变量可用于对同一用户的发票编号,从 1 开始并仅选择第一个。

    
    $now = Carbon::now();
    $nowDS = $now->toDateTimeString();
    
    $expired_invoices = "
    SET @rownum := 0;
    SET @userid := NULL;
    
    SELECT *, uid as user_id, plan_expire 
    FROM (
        SELECT 
            *,
            @rownum := CASE
                WHEN @userid = uid 
                THEN @rownum + 1
                ELSE 1
                END AS rn,
            @userid := user_id AS uid,
            num
        FROM invoices AS i
        WHERE plan_expire <= $nowDS
        ORDER BY user_id, plan_expire DESC
    ) AS num_invoices WHERE rn = 1;
    "
    
    $invoices = DB::select($expired_invoices);
    

    现在,$invoices 可以迭代并发送给它的所有者。

    $expiredatetime = $now->addDays(30);
    $useType = Type::where('name', 'Free')->first();
    $users = User::all();
    
    
    foreach ($invoices as $invoice)
    {
        Invoice::create([
            'user_id' => $invoice->user_id,
            'type_id' => $useType->id,
            'amount' => $useType->price,
            'status' => 'Approved',
            'plan_expire' => $expiredatetime,
        ]);
    
        $user = $users->find(['id' => $invoice->user_id]);
        Mail::to($user->email)->send(new UserPlansReset($user));
    }
    
    

    【讨论】:

    • 它返回SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(user_id), plan_expire from invoices` 其中plan_expire user_i' at line 1 (SQL: select first(user_id), plan_expire from invoices`其中plan_expire user_id order by plan_expire desc)`
    【解决方案2】:

    更改 Invoice 模型,在 $dates 变量中添加 plan_expire 而不是 $casts :

    protected $dates = ["plan_expire"];
    

    你可以这样试试:

    $users = User::all();
    foreach($users as $user){
    
      $latestInvoice = $user->invoices()->latest()->first();
    
      if($latestInvoice->plan_expire->isPast()){
    
           //create invoice and mailed it
      }
      //other steup
    
    }
    

    对于电子邮件发送返回空响应问题,您可以查看此问题click here

    【讨论】:

    • 不,你误会了。不是关于 1 个用户,我需要检查所有用户计划,这是命令将按计划运行,因此它会自动完成工作。
    • 这会返回 Expected response code 220 but got an empty response PS 它会完成数据库工作,但它会阻止发送电子邮件。
    • 哦!当我评论邮件部分时,它返回Trying to get property 'plan_expire' of non-objectnote,因为这个命令每分钟运行一次,我们需要避免这个错误,以防没有过期的计划
    猜你喜欢
    • 2016-07-29
    • 2021-04-21
    • 2019-12-09
    • 2021-09-28
    • 1970-01-01
    • 1970-01-01
    • 2019-06-20
    • 1970-01-01
    • 2020-01-31
    相关资源
    最近更新 更多