Search code examples
phplaraveleloquent

Are these eloquent relationship definitions correct?


I have a Payment model that belongs to a FinancialGoal model which in turn belongs to a User model. I have these relationships methods defined:

Payment model:

public function financialGoal()
{
    return $this->belongsTo(FinancialGoal::class);
}

public function user()
{   //not sure this is correct
    return $this->hasOneThrough(User::class, FinancialGoal::class);
}

User model:

public function financialGoals()
{
   return $this->hasMany(FinancialGoal::class);
}

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

Financial Goal model:

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

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

The question is how do I define the inverse of the payments method in the user model, in the payment model. I have used one of these two definitions on the payment model at some point and both work but just not sure if it's OK to use either and would love to know the correct approach.

public function user()
{
   return $this->financialGoal->user();
}

public function user()
{   // had to ignore static analysis error for this but it returns the relationship
    return $this->financialGoal->belongsTo(User::class);
}

Solution

  • Based on your relationships, I'm guessing this is your table structure

    payments
    id
    financial_goal_id
    financial_goals
    id
    user_id
    users
    id

    Your first user relationship on the Payment model ( $this->hasOneThrough(User::class, FinancialGoal::class) ) is incorrect as you need the inverse of it. It's not well documented in the Laravel docs, but if you play around with all the parameters of the hasOneThrough method you can achieve your goal. The user relationship would look like

    class Payment extends Model
    {
        public function user()
        {   
            return $this->hasOneThrough(User::class, FinancialGoal::class, 'id', 'id', 'financial_goal_id', 'user_id');
        }
    }
    

    This would be better than your other two attempts as this can be Eager loaded with ease and doesn't rely on other existing relationships.