Laravel фильтр вложенных отношений - PullRequest
2 голосов
/ 02 августа 2020

Итак, у меня есть три модели: Волонтер, Задача и Оплата. У волонтера может быть много (много взаимосвязанных) задач, а у задачи может быть много (у другого много взаимосвязей) выплат.

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 или с. Ниже приведен код:

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();

Любая помощь приветствуется!

Ответы [ 2 ]

1 голос
/ 02 августа 2020

Я хотел бы предложить что-то еще, что добавляет столбец в таблицу tasks, который указывает, является ли задача [оплаченной, неоплаченной или частично оплаченной] в вашей tasks миграции, например,

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

затем каждый раз, когда волонтер производит платеж, вы будете выполнять простую проверку для обновления tasks.paid_status, что-то вроде проверки суммы paid_amount и задачи amount

, затем используя Laravel hasManyThrough в Volunteer такая модель

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 Здесь

0 голосов
/ 05 августа 2020

Вы также можете справиться с этим, используя способности красноречия. Расширяет модель задачи с помощью локальной области метода

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()
...