zenstruck / foundry

A model factory library for creating expressive, auto-completable, on-demand dev/test fixtures with Symfony and Doctrine.
https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html
MIT License
609 stars 63 forks source link

[Question] [Help needed] How to filter data returned by `random` based on type? #542

Closed pkimtani closed 6 months ago

pkimtani commented 6 months ago

Hello! I recently came across this library and I am now trying it out in my project. I have a use-case for which I couldn't find a way to use the existing documentation to help me and therefore decided to ask here.

I am using version 1.23.x due to PHP language version restrictions.

Consider the following entities: Theme:

ThemeImages:

Now I want to generate some dataset with following requirements:

I am trying to solve this with using Story where I create the dataset something like:

        // TODO: Need to make sure that there exists a theme with status = 1 and status = 0
        ThemeFactory::createMany(5);

        // Create children themes only from parent theme with status = 1
        // TODO: Need to make sure that there exists a theme with status = 1 and status = 0
        ThemeFactory::createMany(5, function () {
            return [
                'parent' => ThemeFactory::random(['status' => 1]),
            ];
        });

When creating theme images (like below) I can filter themes with status 1, but I couldn't find a way to filter children themes (parent is not null)

         ThemeImageFactory::createMany(5, function () {
            return [
                'theme' => ThemeFactory::randomRange(0, 0, [
                    'status' => 1,
                    'parent' => 'IS NOT NULL' // <- this doesn't work for me but is desired
                ]),
            ];
        });

Could you help me if this is solvable with existing scope of this version of the library or if there's any other better alternative?

Thanks in advance!

pkimtani commented 6 months ago

I found a way to workaround my problem

I added a few custom functions to my ThemeFactory:

    public function asChild(ThemeFactory $parentTheme = null)
    {
        return $this->addState(['parent' => $parentTheme ?? ThemeFactory::new()]);
    }

    public function activeStatus(int $status = 1)
    {
        return $this->addState(['status' => $status]);
    }

And then from my ThemeStory, I use it like:

    public function build(): void
    {
        ThemeFactory::new()
            ->asChild()
            ->activeStatus()
            ->afterPersist(function ($theme) {
                ThemeImageFactory::new(['theme' => $theme])->create(); // This is where the magic happens
            })
            ->create();
    }

Guess I just needed to think a bit more and read the documentation again and again to find this. 😆