Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel generate object using model factory with parameter

Tags:

php

laravel

I have this model factory that generates new contact, it uses random company_id:

$factory->define(App\Models\Contact::class, function (Faker\Generator $faker) 
{
    $company_id = Company::all()->random()->id;

    return [
        'firstname' => $faker->firstName,
        'lastname' => $faker->lastName,
        'phone' => $faker->phoneNumber,
        'email' => $faker->email,
        'company_id' => $company_id,
        'lead_id' => \App\Models\Lead::where('company_id', $company_id)->get()->random()->id,
    ];
});

It is ok when I use it in seeds:

factory(App\Models\Contact::class)->create();

But for testing I need somehow to pass $company_id to factory, create contact for concrete company_id (I know that I can do ->create(['company_id', $company_id])) but this will rewrite only company_id from Contact.

When I select lead_id, I also need to know current company_id.

How to pass company_id to factory as parameter?

like image 644
Alexey Voloshin Avatar asked Mar 05 '18 16:03

Alexey Voloshin


People also ask

How to use model factories in Tests in Laravel?

Let’s review the basics to see in practice how Model Factories can be used in tests for your Laravel application: You can simply run this artisan command to generate a new Model Factory class The new ModelFactory class will be placed in your database/factories directory.

What is the Laravel factory generator?

Dawid Janik comes up with a package called Laravel Factory Generator. This package will generate factories from your existing models. That way you can get started with testing your Laravel or Lumen application more quickly! It is a forked version of mpociot/laravel-test-factory-helper package.

What is default state in Laravel factory?

* Define the model's default state. As you can see, in their most basic form, factories are classes that extend Laravel's base factory class and define a definition method. The definition method returns the default set of attribute values that should be applied when creating a model using the factory.

How to generate large amounts of Database records in Laravel?

Instead, you can use model factories to generate large amounts of database records conveniently. Laravel has a feature called model factories that allow us to generate fake data. It is beneficial for testing and seeding fake data into the database to see the code in action before any real-time user data comes into your application.


2 Answers

Try to use this example:

$factory->define(App\Models\Contact::class, function ($faker, $params) {
    $company_id = $params['company_id'];
    ....
});

and this to make a new object:

$newContact = factory(App\Models\Contact::class)->make(['company_id' => $current_company_id]);
like image 198
vpalade Avatar answered Nov 14 '22 22:11

vpalade


Depends on your Laravel version it will be different.

For laravel 5.1 https://github.com/laravel/framework/issues/9245

  • You will need to check if is passed manually

    // Testcase 
    $company = factory(App\Models\Company::class)->create(); 
    factory(App\Models\Contact::class)->create(['company_id' => $company->id]);
    
    // Factory
    $factory->define(App\Models\Contact::class, function (Faker\Generator $faker, $attribues) {
    
        // Manually check if id is passed 
        $company_id = (isset($attribues['company_id'])) ?: Company::all()->random()->id;
    
        return [
            'firstname' => $faker->firstName,
            'lastname' => $faker->lastName,
            'phone' => $faker->phoneNumber,
            'email' => $faker->email,
            'company_id' => $company_id,
            'lead_id' => \App\Models\Lead::where('company_id', $company_id)->get()->random()->id,
        ];
    });
    
  • For Laravel 5.2 and above you can simply pass id https://laravel.com/docs/5.5/database-testing#relationships

    // Testcase 
    $company = factory(App\Models\Company::class)->create(); 
    factory(App\Models\Contact::class)->create(['company_id' => $company->id]);
    
    // Factory
    $factory->define(App\Models\Contact::class, function (Faker\Generator $faker, $attribues) {
    
        // Manually check if id is passed 
        $company_id = (isset($attribues['company_id'])) ?: Company::all()->random()->id;
    
        return [
            'firstname' => $faker->firstName,
            'lastname' => $faker->lastName,
            'phone' => $faker->phoneNumber,
            'email' => $faker->email,
            'company_id' => function(){
                 return factory(\App\Models\Company::class)->create()
             },
            'lead_id' => \App\Models\Lead::where('company_id', $company_id)->get()->random()->id,
        ];
    });
    

So, for your case, get your random company_id first and pass it to factory. Depends on your Larval version change the ContactModel factory. Or if you have relation that you can query, you can do it as well.

// If you have a relation 
$contact = factory(App\Models\Contact::class)->create(); 

$company_id = $contact->company->id; 
like image 43
user918475 Avatar answered Nov 14 '22 22:11

user918475