【问题标题】:Laravel filter nested relationshipLaravel 过滤嵌套关系
【发布时间】:2020-11-22 16:40:28
【问题描述】:

所以我有三个模型:志​​愿者、任务和付款。一个志愿者可以有很多(有很多关系)任务,一个任务可以有很多(另一个有很多关系)付款。

class Volunteer

public function tasks()
{
    return $this->hasMany(Task::class);
}

class Task

  public function volunteer()
{
    return $this->belongsTo(Volunteer::class);
}

 public function payments()
{
    return $this->hasMany(Payment::class);
}

class Payment 

public function task() {
    return $this->belongsTo(Task::class);
}

现在我想查询所有有无偿/部分有偿任务的志愿者。所以,基本上我想过滤志愿者的任务,其中每个任务的金额应该等于与该特定任务相关的所有付款的总和。

我尝试使用 whereHas 和 with,但似乎无法正确过滤任务。

我已经设法使用连接来做到这一点,但想知道是否可以使用 whereHas 或 with。下面是代码:

Volunteer::select('volunteers.id', 'volunteers.name', 'tasks.amount', DB::raw('SUM(payments.amount) as amount_paid'))
        ->join('tasks', 'tasks.volunteer_id', '=', 'volunteers.id')
        ->leftJoin('payments', 'payments.task_id', '=', 'tasks.id')
        ->groupBy('volunteers.id', 'volunteers.name', 'tasks.amount')
        ->havingRaw('amount_paid >= tasks.amount')
        ->get();

任何帮助将不胜感激!

【问题讨论】:

    标签: php laravel eloquent eloquent-relationship


    【解决方案1】:

    你也可以使用雄辩的力量来处理这个问题。使用local scope 方法扩展任务模型

    class Task extends Model
    {
        public function volunteer()
        {
            return $this->belongsTo(Volunteer::class);
        }
    
        public function payments()
        {
            return $this->hasMany(Payment::class);
        }
    
        public function scopeIncompletePayments($query)
        {
            return $query->select('tasks.*')->leftJoin('payments', 'tasks.id', '=', 'payments.task_id')
                ->having('tasks.amount', '>', DB::raw('SUM(payments.amount)'))
                ->groupBy('tasks.id')
                ->with(['volunteer', 'payments']);
        }
    }
    

    这允许您运行以下代码来获取相关付款总和小于任务金额的任务。随着付款和志愿者热切地加载

    Task::incompletePayments()->get()
    

    【讨论】:

      【解决方案2】:

      我想提出其他建议,即在tasks 表中添加一列,以指示您的tasks 迁移中的任务是否[付费、未付费或部分付费]

      $table->unsignedTinyInteger('paid_status')->default(0); // 0 -> unpaid, 1 -> partially paid, 2 -> paid
      

      然后,每次志愿者付款时,您都会做一个简单的检查来更新tasks.paid_status,比如检查总数paid_amount和任务amount

      然后像这样在Volunteer 模型中使用 Laravel hasManyThrough

      public function payments()
      {
         return $this->hasManyThrough(
             'App\Payment',
             'App\Task'
        );
      }
      

      现在要获取您的数据,您将这样做

      // unpaid tasks
      Volunteer::query()->first()->payments()->where('tasks.paid_status', '0')->get();
      // partially paid tasks
      Volunteer::query()->first()->payments()->where('tasks.paid_status', '1')->get();
      // paid tasks
      Volunteer::query()->first()->payments()->where('tasks.paid_status', '2')->get();
      

      你可以阅读更多关于 HasManyThrough Here

      【讨论】:

      • 好主意。只是想知道它不会破坏数据库的动态吗?就像我对付款状态进行硬编码而不是动态计算一样。一些建议会很有用。
      • 不,我不认为它会破坏您的数据库的动态性,确实这样做是一个好习惯,说到付款状态,您可以在每次新付款时发送PaymentObserver将检查tasks.amount$task->payments()->sum('amount'),然后更新tasks.paid_status,这是一种完全动态的方式。
      猜你喜欢
      • 2017-03-02
      • 1970-01-01
      • 2015-10-16
      • 2022-01-03
      • 2014-10-27
      • 2020-10-15
      • 1970-01-01
      • 2018-08-04
      • 2021-07-19
      相关资源
      最近更新 更多