lukeraymonddowning / poser

Create class based model factories in Laravel applications in seconds.
MIT License
276 stars 10 forks source link

Providing default foreign key values in Laravel factories #50

Closed bradroberts closed 4 years ago

bradroberts commented 4 years ago

Hey, Luke. I've been manually creating class-based factories for a while and can appreciate how great this package is. Really looking forward to using it. I'm wondering what your recommendation is when using default values for foreign keys in your Laravel factories? For example, I typically do something like this.

$factory->define(App\Post::class, function (Faker $faker) {
    return [
        'author_id' => factory(Author::class),
        'title' => $faker->title
    ];
});

However, when I create a Post using Poser I end up with two Authors in the database.

PostFactory::new()
    ->forAuthor(
        Author::new()->withAttributes(['name' => 'Bob'])
    )->create();

Do you recommend removing foreign key defaults in Laravel factories? If so, is there an alternative in Poser?

lukeraymonddowning commented 4 years ago

Hi Brad!

Thanks for your support of the project 👍

We've known about this for a little while now, and the solution has been escaping me, but I think you've just provided it.

What are your thoughts on a syntax like

default<RelationshipMethodName>() functions placed in the Poser Factory that would be called automatically if there was no manual override set? Then, you can remove the foreign key default in the Laravel factories but still have the default functionality.

So, in your example, your Post Factory would look like this:

class Post extends Factory {

    public function defaultAuthor()
    {
        return AuthorFactory::new();
    }

}

When Poser runs, it uses reflection to look for methods starting with 'default' in the class, then checks to see that they haven't already been used in the factory call. If that is the case, they are called and attached to the model. So...

PostFactory::new()
    ->forAuthor(
        Author::new()->withAttributes(['name' => 'Bob'])
    )->create();

...wouldn't call defaultAuthor(), but...

PostFactory::new()->create();

...would call it.

@AlanHolmes and @andreich1980 would you two weigh in on this too as we've discussed this issue before 👌

andreich1980 commented 4 years ago

Sounds good for me

AlanHolmes commented 4 years ago

That sounds good to me!

bradroberts commented 4 years ago

You guys are awesome! Thanks so much for the response and for taking the time to work in a solution.

lukeraymonddowning commented 4 years ago

@all-contributors please add @bradroberts for ideas

allcontributors[bot] commented 4 years ago

@lukeraymonddowning

I've put up a pull request to add @bradroberts! :tada: