0

I have three models, User, Category and Article.

Article belongs to both a User and a Category where the foreign keys user_id and category_id are not null.

Am lost trying to seed the database with fake data via factories accordingly, here's the seeding code...

// 2 categories and 12 articles, 6 per category
// TODO: A user should have 6 articles with mixed categories 
// 3 from each category
// So we will have 2 users
factory(Category::class, 2)->create()->each(function($category) {
    factory(User::class)->create()->each(function($user) use ($category) {
        // How to assign an Article to $category or $user while creating?
        $user->articles()->createMany(
                    factory(Article::class, 3)->make()->toArray()
                ); // category_id can't be null
        // OR
        $category->articles()->createMany(
                    factory(Article::class, 3)->make()->toArray()
                ); // user_id can't be null
    });
});

I'll get one of two errors, either

Column user_id doesn't have a default value

Or

Column category_id doesn't have a default value

Which is logical due to the Article table migration

$table->increments('id');
$table->unsignedInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->unsignedInteger('category_id');
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');

How can I pass the category_id or user_id to the factory call?
Is there a better way to acheive this?

Thanks in advance

Salim Djerbouh
  • 10,719
  • 6
  • 29
  • 61

3 Answers3

1

You can override attributes for your factory by passing an array with the desired attributes to the make() method:

Change

$user->articles()->createMany(
  factory(Article::class, 3)->make()->toArray()
);

to

$user->articles()->createMany(
  factory(Article::class, 3)->make([
    'category_id' => $category->id
  ])->toArray()
);

to override the category_id attribute.

https://laravel.com/docs/6.x/database-testing#using-factories

brombeer
  • 8,716
  • 5
  • 21
  • 27
0

Seed the categories separately.

Then seed the users and inside it seed the articles. In the article factory file ArticleFactory:

$factory->define(App\Article::class, function (Faker $faker) {

    return [
        'category_id' => App\Category::inRandomOrder()->value('id'),
        ....
        'created_at' => time(),
        'updated_at' => time(),
    ];
});
N69S
  • 16,110
  • 3
  • 22
  • 36
0

This may help you

First

make users create when you make a new article from factory

$factory->define(App\Article::class, function ($faker) use ($factory)  {
    return [
        'user_id' => $factory->create(App\User::class)->id,
        'title' => $faker->sentence,
        'body' => $faker->paragraph
    ];
});

Second

from your seeder in this example i will make 3 categories * 6 Articles

factory('App\Category', 3)->create()->each(function($u) {
    $u->posts()->save(factory('App\Article', 6)->create());
});
Joseph
  • 5,644
  • 3
  • 18
  • 44
  • `$factory->create(App\User::class)->id` will whip up a new user for each article, doesn't satisfy the requirement of `A user should have 6 articles`, this way a user would only have 1 article – Salim Djerbouh Sep 20 '19 at 15:05
  • No the first part just for create user foreach article in factory but in your seeder you will make 3 category each of them has 6 article – Joseph Sep 20 '19 at 15:06