2

I have 2 table, RecipesTable & IngredientsTable.

IngredientsTable:

class IngredientsTable extends Migration
{
    public function up()
    {
        Schema::create('ingredients', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('ingredient_name');
        });
    }
}

RecipesTable :

class RecipesTable extends Migration
{
    public function up()
    {
        Schema::create('recipes', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('recipe_name');
            $table->unsignedBigInteger('ingredient_id');
            $table->foreign('ingredient_id')->references('id')->on('ingredient');
        });
    }
}

Let say in my RecipesTable table entry I have a recipe call Fried Chicken and my IngredientsTable I have 4 entry : 1, Chicken, 2, Dory, 3, Salt, 4, Breadcrumb. How can I create an entry that associate multiple entry of IngredientsTable into RecipesTable in my Controller? for example my entry should look like this in JSON : Recipe :

{
    id: 1
    name : 'Friend Chicken'
    ingredient_id ; ['1', '3', '4']
}

Right now in my Controller I have something like this :

public function createRecipe(Request $request )
    {
            $data = ([
                'recipe_name' => 'Fried Chicken',
                'ingredient_id' => ['1', '3', '4'],
                ])

            Recipe::create($data);
            return redirect()->route('recipe.index')->withStatus(__('Recipe has been added.'));
        }        
    }

and its not working.

5
  • You need to use many-to-many relation here. It means you need another table which will associate your recipes with ingradients. Laravel is supporting that type of relations. See laravel.com/docs/master/eloquent-relationships#many-to-many Also note, that you need table like this recipe_ingradient_relation Where you will have id, recipe_id, ingradient_id Commented Sep 5, 2019 at 7:23
  • Also see laravel.com/docs/master/… Commented Sep 5, 2019 at 7:24
  • thanks, I'm looking at it right now Commented Sep 5, 2019 at 7:26
  • I have posted an answer, try it and let me know it is working or no :) Commented Sep 5, 2019 at 7:38
  • @RobMkrtchyan Hi, thanks your update check it on it now, sorry I was away for a while Commented Sep 11, 2019 at 2:32

3 Answers 3

1

Add new migration:

class RecipeIngredientRelTable extends Migration
{
    public function up()
    {
        Schema::create('recipe_ingredient_rel', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->bigIncrements('recipe_id')->index();
            $table->bigIncrements('ingredient_id')->index();

            $table->foreign('recipe_id')->references('id')->on('recipes');
            $table->foreign('ingredient_id')->references('id')->on('ingredient');
        });
    }
}

Add model

class RecipeIngredientRel extends BaseModel
{
    protected $fillable = [
        'recipe_id',
        'ingredient_id'
    ];

    public function recipe(){
        return parent::belongsTo(Recipe::class);
    }

    public function ingredient(){
        return parent::belongsTo(Ingredient::class);
    }
}

In your recipes model add

public function ingredients(){
    return $this->belongsToMany(Ingredient::class, 'recipe_ingredient_rel', 'recipe_id');
}

In your ingredients model add

public function recipes(){
    return $this->belongsToMany(Recipe::class, 'recipe_ingredient_rel', 'ingredient_id');
}

Then, in controller Just write

Recipe::create([
    'recipe_name' => $data['recipe_name']
])->attach($data['ingredient_id']);

It will create entity in recipes table with name And 3 entities in recipe_ingredient_rel table with

recipe_id => {created_id} | ingredient_id => 1
recipe_id => {created_id} | ingredient_id => 2
recipe_id => {created_id} | ingredient_id => 2

Then to retrieve recipe with ingredients, just use

$recipe = Recipe::with('ingredients')->find({created_id});

It will give you Collection, just use toArray() to see the actual result.

UPDATE

    Recipe::create([
        'recipe_name' => $data['recipe_name']
    ])->ingredients()->attach($data['ingredient_id']);

This one should work

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks @Rob I'm trying this right now, will let you know when it worked
Hi @Rob I Tried this and it says Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails when creating the entry
Are you sure you have all ingradients in db? For this example you should have idngedients with id: 1, id: 3 and id:4
Yes I have all the ingredient in db
hi this seem to fix the problem, thank you so much fo your help and patience!
|
1

Just do these thing in your controller:

public function createRecipe(Request $request )
    {

            $data = ([
                'recipe_name' => 'request('name')',
                'ingredient_id' => 'serialize(request('ingredient_id '))',
                ])

            Recipe::create($data);
            return redirect()->route('recipe.index')->withStatus(__('Recipe has been added.'));
        }        
    }

While retrieve use unserialize to get data ['1', '3', '4'] in these format.I hope it may help you.Try this.

Comments

1

I think you must change your migrations. Since a recipe has many ingredients. One to Many relationship approach

Recipe Migration:

Schema::create('recipes', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->string('recipe_name'); 
});

Ingredients Migration:

Schema::create('ingredients', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->unsignedBigInteger('recipe_id');
    $table->string('ingredient_name');

    $table->foreign('recipe_id')
        ->references('id')
        ->on('recipes')
        ->onDelete('cascade');
});


Create a model for each Recipe and Ingredient table and add relationship:

Recipe model

class Recipe
{
    protected $table = 'recipes';
    //fill the fillables here

    public function ingredient(){
        return $this->hasMany('App\Ingredient');
    }
}

Ingredient model

class Ingredient
{
    protected $table = 'ingredients';
    //fill the fillables here

    public function ingredient(){
        return $this->belongsTo('App\Recipe');
    }
}


Now in your question how to add:

Create first the recipe:

$value = 'fried chicken';

$recipe = Recipe::create([
    'recipe_name' => $value
]);

And then insert the ingredients of the recipe:

$ingredients = ['flour', 'salt', 'oil', 'chicken'];
foreach($ingredients AS $value){
    $recipe->ingredient()->create([
        'recipe_id' => $recipe->id,
        'ingredient_name' => $value
    ]);
}


Display the ingredients of fried chicken:

//search the recipe
$recipe = Recipe:where('recipe_name', 'fried chicken')->first();

//display ingredients
return $recipe->ingredient;

NOTE: This is just to answer the question, scroll down more to see the other approach.

8 Comments

How you will create another recipe with same ingradients?
@RobMkrtchyan this is One to Many relationship brother.
Yeah, but seems he need many-to-many :) Ingradients can be duplicated for different recipes, so with one-to-many you will have many duplicated rows in ingradients table
@RobMkrtchyan he can use other approach as what I say :) But I will use this approach if I was he. I will try to make a Many to Many for him, I will edit this
Hi @suspended thanks for the answer and yes as Rob said I want to re use the ingredient for the next recipe i created.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.