thephpleague / factory-muffin

Enables the rapid creation of objects for testing
https://factory-muffin.thephpleague.com/
MIT License
531 stars 72 forks source link

Mongo embedded relations #388

Closed penoonan closed 8 years ago

penoonan commented 9 years ago

I ran into a lot of problems trying to get Factory Muffin to generate embedded relations for an application that uses Mongo. The solution I ended on is fairly simple, but I had a hell of a time getting to that point. So I'm not sure if this is a documentation issue or if it might be more of a feature request.

Here is the solution I landed on (embedding 'contact' document into an 'event' model):

    // factories/all.php

    $faker = new \League\FactoryMuffin\Faker\Faker();

    $embedded_contact = function() use($faker) {
        $definitions = [
            'first_name' => $faker->firstName(),
            'email' => $faker->email(),
            // ... etc
        ];

        return array_map(
            function($item) { return $item(); },
            $definitions
        );
    }

    $fm->define('My\Models\Event', [
        'title' => Faker::text(75),
        'contact' => $embedded_contact
    ]);

But I'd really rather be able to explicitly define 'contact' as an embedded object in factory muffin that relates to an actual 'My\Models\Contact' model in my app. A couple possibilities ...

It would be nice if I could define the 'My\Models\Contact' model as embedded, so that I can relate it to other models like normal and it will always be embedded:

    $fm->define('My\Models\Contact')->embedded()->addDefinitions([ ... ]);

    $fm->define('My\Models\Event')->addDefinitions([
        'title' => Faker::text(75),
        'contact' => 'factory|My\Models\Contact'
    ]);

Or it would be nice if I could define the contact like normal and designate it as being embedded when I declare it in the Event definition:


    $fm->define('My\Models\Contact')->addDefinitions([ ... ]);

    $fm->define('My\Models\Event')->addDefinitions([
        'title' => Faker::text(75),
        'contact' => 'embeddedFactory|My\Models\Contact'
    ]);

Or the docs could just be more explicit about how to use embedded documents, or I could be missing something completely obvious. I'd definitely be open to submitting a pull request but probably not until mid June or so.

Anyway thanks for a great library!

GrahamCampbell commented 9 years ago

$faker = new \League\FactoryMuffin\Faker\Faker();

We do provide a faker facade you know. :)

I'd definitely be open to submitting a pull request but probably not until mid June or so.

I'm planning on giving our docs some love in the first week of July. The upgrading docs need completing, and the docs for 3.0 feel a bit clunky since they've been hacked together from the 2.x docs.

penoonan commented 9 years ago

We do provide a faker facade you know. :)

Huh! Weird. I knew there was a facade, and I'm using it for all non-embedded things, but for some reason I thought I had to import a faker instance into closures, otherwise if I ran a seed all the results would be identical. But I have just tested that assumption and can see that it's not the case. Now I'm not even sure where I got the idea. :P

GrahamCampbell commented 9 years ago

Now I'm not even sure where I got the idea. :P

D'no. Both are valid ways of doing it I guess. You just won't be able to use the unique generators if you're not using the same instance. :)