Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

marcoacm's avatar

Relationships confusion

Hello. I having problems with Eloquent and I need some help.

I have 3 tables: Recipe, Ingredients, RecipeIngredients defined as follows


class Recipe extends Model {
    protected $table = "recipes";
    public function ingredients() {
            return $this->hasMany(RecipeIngredient::class);
        }
}

class RecipeIngredient extends Model
{
    protected $table = "recipe_ingredients";

    public function recipe() {
        return $this->belongsTo(Recipe::class);
    }

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

}

class Ingredient extends Model
{
    protected $table = "ingredients";

    public function recipes() {
        $this->hasMany(RecipeIngredient::class);
    }
}

I am trying do to do

$recipe->ingredients()->associate($ingredient); // To associate an ingredient
$recipe->save();

I get the following error: Call to undefined method Illuminate\Database\Query\Builder::associate()

Why doesn't associate() work? Is this valid code?

I am trying to find the best way to sync (delete ingredients, and add ingredients) but I can't make it work. I tried sync() as well.

Please help.

0 likes
9 replies
pmall's avatar

It doesnt work because you use a HasMany relation instead of a belongsToMany. You dont need the RecipeIngredient class.

marcoacm's avatar

I don't understand. How to I link Recipes to Ingredients without that class?

marcoacm's avatar

I changed my code to this.


class Recipe extends Model
{
    public function ingredients() {
        return $this->belongsToMany(Ingredient::class, 'recipe_ingredients');
    }

}

class Ingredient extends Model
{
    public function recipes() {
        return $this->belongsToMany(Recipe::class, 'recipe_items', 'recipe_ingredients_id');
    }
}

and now I get null when I call $ingredients = $recipe->ingredients;

any thoughts?

davorminchorov's avatar
$recipes = Recipe::with('ingredients')->get();
// usually the $recipes variable is passed to the view and you do something like this in the view to show the data:
foreach($recipes as $recipe)
{
    $recipe->ingredients()->name; // name is an imaginary field from the ingredients table.
}
  
marcoacm's avatar

@bobbybouwmann Actually in the documentation you can find that you do specify the custom name of the table.

"As mentioned previously, to determine the table name of the relationship's joining table, Eloquent will join the two related model names in alphabetical order. However, you are free to override this convention. You may do so by passing a second argument to the belongsToMany method:

return $this->belongsToMany('App\Role', 'user_roles');"

Am I interpreting this the wrong way?

marcoacm's avatar

So after playing my code for a while, I figured out that a custom Model class I created to deal with timezone was braking my relations. I use this class to create my models (e.g class Recipe extends MyModel ). I had removed from my code in my original post to this forum to avoid confusing anybody.


<?php

namespace App\Models;


use Illuminate\Database\Eloquent\Model;
use Session;

class MyModel extends Model {

  public function getAttribute($key)
  {

      $isDate = in_array($key, $this->dates);

      if ($isDate)
      {
          // return Session::get('timezone');
          return $this->getAttributeValue($key)->setTimezone(Session::get('timezone'));
      }

      return $this->getAttributeValue($key) ;

  }


}

Any ideas why this would break relationships in particular?

jekinney's avatar

Depends on what your setting the time zone on.

Seeing your using a pivot table, ensure yor setting your time zone attribute on a different model. Or if your intention is the pivot table make sure your relations have withTimestamps() added as per the docs and use a query scope on the model calling the relationship.

pmall's avatar

@marcoacm It should not break anything. What is the error ?

@Ruffles It is not $recipe->ingredients()->name but $recipe->ingredients and it returns a collection.

1 like

Please or to participate in this conversation.