Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel : using model factories to generate one-to-many relationships

I have a problem with generating multiple one-to-many relationship for a model using factories in Laravel. The factories seem to only be generating one ClubFixture per Club, when they should be generating 5 ClubFixtures per Club.

Models

Club

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Club extends Model
{
  //Table associated with the model
  protected $table = 'clubs';

   protected $fillable = ['name', 'league', 'age_group', 'colour', 'county', 'country'];

   public function fixtures(){
     return $this->hasMany('App\ClubFixture', 'club_id', 'id');
   }
}

ClubFixture

namespace App;

use Illuminate\Database\Eloquent\Model;

class ClubFixture extends Model
{
  //Table associated with the model
  protected $table = 'club_fixtures';
}

Modal Factories

$factory->define(App\Club::class, function (Faker\Generator $faker) {
    return [
        'name' => $faker->name,
        'league' => $faker->word,
        'age_group' => $faker->word,
        'colour' => $faker->hexcolor,
        'county' => $faker->state,
        'country' => $faker->country,
        'emblem' => $faker->imageUrl(80, 80),
        'banner' => $faker->imageUrl,
        'matches' => $faker->randomDigit,
        'wins' => $faker->randomDigit,
        'losses' => $faker->randomDigit,
    ];
});

$factory->define(App\ClubFixture::class, function (Faker\Generator $faker) {
    return [
        'club_id' => function () {
            return factory(App\Club::class)->create()->id;
        },
        'opposition' => $faker->name,
        'address' => $faker->address,
        'datetime' => $faker->dateTimeBetween('now', '+30 weeks'),
        'type' => $faker->randomElement(['home', 'away', 'none']),
    ];
});

Database seeder

factory(App\Club::class, 100)->create()->each(function ($u) {
     factory(App\ClubFixture::class, 5)->create();
});

Expected Result: Each Club should have 5 ClubFixtures associated with it

Actual Result: Some Clubs have no ClubFixtures, some only have one.

I've tried this answer, but get an error with saveMany does not exist and relationship is null.

You can download the SQL resulting database here.

Can someone tell me what I am doing wrong here?

like image 811
Luke Brandon Farrell Avatar asked Mar 02 '18 20:03

Luke Brandon Farrell


1 Answers

Your Models & Model Factories seem fine, but use them with this seeder instead:

use Illuminate\Database\Seeder;

class ClubSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        factory(App\Club::class, 100)->create()->each(function($c) {
            /** @var \App\Club $c */
            $c->fixtures()->saveMany(
                factory(App\ClubFixture::class, 5)->make(['club_id' => NULL])
            );
        });
    }
}

Make sure you call the saveMany() method on the fixtures() relationship method of your Club model. Finally also override the club_id for each iteration of the 5 ClubFixtures to prevent another creation of a Club. Otherwise you'd end up with 600 Clubs (instead of 100 Clubs) & 500 ClubFixtures.

like image 131
baikho Avatar answered Sep 18 '22 17:09

baikho