foundry icon indicating copy to clipboard operation
foundry copied to clipboard

[2.0] Customize Faker's locale

Open camille-guerber opened this issue 1 year ago • 6 comments

Hello,

in the previous version v1.38.2 I could change the faker local this way but I'm not able anymore to do it. Since v2.* I have this message "Method 'configuration' not found in LocalizedModelFactory"

Here is my code :

abstract class LocalizedModelFactory extends PersistentProxyObjectFactory
{
    /**
     * @return Proxy<TModel>&TModel
     */
    final public static function createOneLocalized(?string $locale = null, array $attributes = []): Proxy
    {
        if (null !== $locale) {
            $locale = sprintf('%s_%s', strtolower($locale), strtoupper($locale));


           self::configuration()->setFaker(Factory::create(
                sprintf('%s_%s', strtolower($locale), strtoupper($locale))
           ));
        }

        $attributes['fakerLocale'] = $locale;

        return self::createOne($attributes);
    }


Thanks for your help

camille-guerber avatar Jul 01 '24 16:07 camille-guerber

Maybe @kbond ? Thanks

camille-guerber avatar Jul 02 '24 08:07 camille-guerber

Hi @camille-guerber

The method Factory::configuration() was marked as @internal in 1.x and should not be used in userland, and no BC policy should be expected from internal class/methods.

By the way, IMO this implementation seems buggy, since you were changing "globally" the faker instance:

$object1 = SomeFactory::createOne(); // faker is used with default, let's say "en_US"
$object2 = SomeFactory::createOneLocalized('fr'); // faker is used with "fr_FR"
$object3 = SomeOtherFactory::createOne(); // faker will still be used with "fr_FR", but "en_US" would have been expected

I think you should consider refactor to something like this:

akbstract class LocalizedModelFactory extends PersistentProxyObjectFactory
{
    protected Faker\Generator|null $faker = null;

    public function localized(string $local): static
    {
        $clone = clone $this;
        $clone->faker = Faker\Factory::create(
            sprintf('%s_%s', strtolower($locale), strtoupper($locale)) // be careful, this might be buggy as well, for instance `en_EN` does not exist
        );

        return $clone;
    }

    protected function getFaker(): Faker\Generator
    {
		return $this->faker ?? self::faker();
	}
}

nikophil avatar Jul 03 '24 12:07 nikophil

Hello @nikophil thanks for your answer, I'm not able to call "localized" neither "getFaker" from "createOneLocalized" function, any idea ?

camille-guerber avatar Jul 04 '24 14:07 camille-guerber

I think what you'd need to do is something like this assuming you're extending the abstract class @nikophil suggested:

    /**
     * @return Proxy<TModel>&TModel
     */
    final public static function createOneLocalized(string $locale, array $attributes = []): Proxy
    {
        return self::new()->localized($locale)->create($attributes);
    }

kbond avatar Jul 04 '24 14:07 kbond

the advantage of having a method localized() is that it's just another state, that could be composed with the other ones:

SomeLocalizedFactory::new()->localized('fr')->withName()->create();

the problem of this approach is that every faker() calls in SomeLocalizedFactory::default() won't be localized...

I've thought a little bit about it on how we could integrate this in Foundry, but I did not find any interesting way to do it, because on how faker works... :shrug:

nikophil avatar Jul 04 '24 17:07 nikophil

Thanks @kbond and @nikophil you helped me a lot, what about this ?

/**
* @return Proxy<TModel>[]&TModel[]
*/
final public static function createManyLocalized(int $number, ?string $locale = null, array $attributes = []): array
{
    return self::new()->localized($locale)->???
}

camille-guerber avatar Jul 05 '24 15:07 camille-guerber

Hi,

sorry for the late reply, but what you could do is:

/**
* @return Proxy<TModel>[]&TModel[]
*/
final public static function createManyLocalized(int $number, ?string $locale = null, array $attributes = []): array
{
    return self::new()->localized($locale)->many($number)->create();
}

I'm wondering if I won't add this localized() method into Foundry :thinking:

nikophil avatar Oct 24 '24 18:10 nikophil