How to send a value as parameter to the Factory Class

902 Views Asked by At

I need to run a Factory 50 times, so inside the DatabseSeeder:

public function run()
{
    for($i=1;$i<=50;$i++){
       (new CategoryQuestionFactory($i))->create();
    }
}

So as you can see, I tried passing a variable called $i as parameter to CategoryQuestionFactory class.

Then at this Factory, I tried this:

class CategoryQuestionFactory extends Factory
{
    protected $counter;

    public function __construct($c)
    {
        $this->counter = $c;
    }
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition()
    {
        $question = Question::find($this->counter);

        return [
            'category_id' => $this->faker->numberBetween(1,22),
            'question_id' => $question->id
        ];
    }
}

But when I run php artisan db:seed at Terminal, I get this error:

Call to a member function pipe() on null

at C:\xampp\htdocs\forum\root\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Factories\Factory.php:429

So what's going wrong here? How can I properly send a value as a parameter to the Factory Class?

Also, at the IDE for the __construct method of this Factory, I get this message:

enter image description here


UPDATE #1:

Here is the capture of error at IDE:

enter image description here

4

There are 4 best solutions below

0
On

It seems to me that you want to seed the intermediate table. There are methods that can be use when seeding them one of them is has() which is the one i always use.

/**
* will create a one question and 3 category then create a data in the intermediate table. 
* expected data : 
* question_id | category_id
*     1            1
*     1            2
*     1            3
*/
Question::factory()->has(
    Category::factory()->count(3)
)->create();

So let's say you want to create a 100 question and 5 categories

/**
* will create a 100 question and 5 category then create a data in the intermediate table. 
* expected data : 
* question_id | category_id
*     1            1
*     1            2
*     1            3
*     1            4
*     1            5
*     2            1
*     2            2
*     2            3
*     2            4
*     2            5
* until the 100th question will have a 5 categories
*/
Question::factory(100)->has(
    Category::factory()->count(5)
)->create();
0
On

In laravel its better to associate with the model, So instead of doing this

$question = Question::find($this->counter);

return [
     'category_id' => $this->faker->numberBetween(1,22),
     'question_id' => $question->id
];

you can do this (then you dont have to passs the $i)

return [
     'category_id' => $this->faker->numberBetween(1,22),
     'question_id' => Question::factory(),
];
1
On

Don't forget to call parent::__construct() in the constructor of your CategoryQuestionFactory factory. Your CategoryQuestionFactory is supposed to extends Laravel standard Factory. Missing to call the parent constructor on a child class breaks the code.

1
On

I've generated the model via PhpStrom:

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Collection;

class CategoryQuestionFactory extends Factory
{
    public function __construct($count = null, ?Collection $states = null, ?Collection $has = null, ?Collection $for = null, ?Collection $afterMaking = null, ?Collection $afterCreating = null, $connection = null, ?Collection $recycle = null)
    {
        parent::__construct($count, $states, $has, $for, $afterMaking, $afterCreating, $connection, $recycle);
    }

    public function definition()
    {
        $question = Question::find($this->counter);

        return [
            'category_id' => $this->faker->numberBetween(1,22),
            'question_id' => $question->id
        ];
    }
}

It's should work fine. I checked. You should call parent::__construct.

Like constructors, parent destructors will not be called implicitly by the engine. In order to run a parent destructor, one would have to explicitly call parent::__destruct() in the destructor body. Also like constructors, a child class may inherit the parent's destructor if it does not implement one itself.