如何在Laravel中获得一段关系的最新记录

时间:2019-04-18 06:32:50

标签: php laravel

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

我需要做什么

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

问题是

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

示例

  1. 我的用户在3 rows中有invoices
  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

不会发送电子邮件

2 个答案:

答案 0 :(得分:2)

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

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 :(得分:0)

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

MySQL服务器版本<8没有窗口功能,可以使在匹配的行中进行行编号更容易。

一种解决方法是设置客户端变量,该变量可用于从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));
}