skip to Main Content

My data model looks like this:

a diagram with three entities

An Order contains between 1 and N Products, a Product has a single Category.

I have 3 Factories, one for each entity: OrderFactory, ProductFactory, CategoryFactory. In them, I setup default data:

namespace DatabaseFactories;

use AppCategory;
use AppProduct;
use IlluminateDatabaseEloquentFactoriesFactory;

class ProductFactory extends Factory
{
    protected $model = Product::class;

    public function definition()
    {
        $name = $this->faker->realText(20);
        return [
            'category_id' => Category::factory(),
            'reference' => str_replace(' ', '', $name),
            'name' => $name,
            'price' => $this->faker->randomFloat(2, 1.00, 200.00),
        ];
    }
}

namespace DatabaseFactories;

use AppCategory;
use IlluminateDatabaseEloquentFactoriesFactory;

class CategoryFactory extends Factory
{
    protected $model = Category::class;

    public function definition()
    {
        return [
            'label' => $this->faker->realText(20),
            'description' => $this->faker->text,
        ];
    }
}

I want for one particular test to create an Order containing 5 products of a Category named my specific category label. I tried to do it like so:

$order = Order::factory()
    ->state([
        'number' => 014789012,
    ])
    ->has(
        Product::factory()
            ->count(3)
            ->has(
                Category::factory()->state([
                    'label' => 'my specific category label',
                ])
            )
    )
    ->create();

But the Category->label is not edited and remains the default one defined in CategoryFactory. Why?

2

Answers


  1. Chosen as BEST ANSWER

    I made a mistake by using has() instead of for() on my Product <=> Category relation: as it is a OneToMany relationship, we need to use for(), like so:

    $order = Order::factory()
        ->state([
            'number' => 014789012,
        ])
        ->has(
            Product::factory()
                ->count(3)
                ->for(
                    Category::factory()->state([
                        'label' => 'my specific category label',
                    ])
                )
        )
        ->create();
    

  2. You can do like this too I guess

    # First, create the category
    $category = Category::factory()->create([
        'label' => 'my specific category label',
    ]);
    
    # after,  link to the category
    $order = Order::factory()
        ->state([
            'number' => '014789012', # Make sure the number is a String or Number
        ])
        ->has(
            Product::factory()
                ->count(5) # Set to 5
                ->state([
                    'category_id' => $category->id, # Assin the ID of the category
                ])
        )
        ->create();
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search