enums icon indicating copy to clipboard operation
enums copied to clipboard

Trait for string conversion

Open gmgarrison opened this issue 2 years ago • 5 comments

For enum fields, I like to keep a comment in the database that has all the enum values and text. It might be useful to have a Trait with a toString() to get this? I personally also include a $nameFirst parameter to specify if I want:

1 => Admin, 2 => Instructor, 3 => Student or Admin => 1, Instructor => 2, Student =>3

Thanks for the great package!

gmgarrison avatar Jun 08 '22 13:06 gmgarrison

Wouldn't ->name work for this?

stancl avatar Jun 08 '22 16:06 stancl

If I understand correctly, you would use ->name on a single enum value and ->names on the enum itself to get an array of names? I don't want either of those. I want a string that illustrates the entire associative array of a backed enum.

gmgarrison avatar Jun 09 '22 22:06 gmgarrison

So essentially something like this?

array_combine(FooEnum::names(), FooEnum::values());

stancl avatar Jun 11 '22 11:06 stancl

Yeah, that's the idea but it would be return a string instead of an array to be used like this in a create_table migration, for example: $table->unsignedTinyInteger('gender')->comment(\App\Enums\Student\Gender::toString());

Personally, I have my own trait that implements this function like this right (could easily be improved upon):

public static function toString(bool $nameFirst = true): string
    {
        $cases = static::cases();

        $array = array_column($cases, "value", "name");

        if ($nameFirst) {
            $array = array_flip($array);
        }

        $toReturn = "";
        foreach ($array as $index => $element) {
            $toReturn .= $index . " => " . $element . ", ";
        }
        $toReturn = substr($toReturn, 0, -2);
        return $toReturn;
    }

I don't know how popular or useful this would be to other people, just an idea. Thanks for considering!

gmgarrison avatar Jun 13 '22 02:06 gmgarrison

This actually isn't a bad idea, think a more common use case for this might be FooEnum::selectOptions(Callable c = null): array where you might want to orient the enum to fill up a "select Field option list". (index => name) The callable could allow you to override the standard output with something else. Also easy to user land create, but I'd imagine it's probably something extremely common and the majority of enums are intended for this purpose.

roni-estein avatar Aug 12 '22 06:08 roni-estein

So a summary:

  • possibly implement a function that returns key-value pairs (or the opposite)

    array_combine(FooEnum::names(), FooEnum::values());
    array_combine(FooEnum::values(), FooEnum::names());
    
  • support string output (the main goal here). Could be done using a callable. To support outputs like:

    Admin => 1, Instructor => 2, Student => 3
    
    <option value="1">Admin</option>
    <option value="2">Instructor</option>
    <option value="3">Student</option>
    

    Perhaps using syntax like:

    FooEnum::options(callback: Closure($key, $value): string, glue: $string);
    
    // Admin => 1, Instructor => 2, Student => 3
    FooEnum::options(fn ($key, $value) => "$key => $value", ", ");
    
    // <option value="1">Admin</option>
    // <option value="2">Instructor</option>
    // <option value="3">Student</option>
    FooEnum::options(fn ($key, $value) => "<option value='{$key}'>{$value}</option>", "\n");
    

With perhaps some optimizations for common use cases. I'll think about this, as well as other approaches for addressing the Blade templating specifically.

stancl avatar Jan 12 '24 21:01 stancl

Well regarding what I wrote here that's actually just the Options trait.

So this is strictly string-related.

To follow the naming convention the method would be something like stringOptions() or optionsAsString().

stancl avatar Jan 12 '24 21:01 stancl

See the linked commit. Ended up with this implementation:

it('can return a string of options from a backed enum')
    ->expect(Status::stringOptions(fn ($name, $value) => "$name => $value", ', '))
    ->toBe("PENDING => 0, DONE => 1");

it('can return a string of options from a pure enum')
    ->expect(Role::stringOptions(fn ($name, $value) => "$name => $value", ', '))
    ->toBe("ADMIN => ADMIN, GUEST => GUEST");

it('returns default HTML options from backed enums')
    ->expect(Status::stringOptions())
    ->toBe('<option value="0">Pending</option>\n<option value="1">Done</option>');

it('returns default HTML options from pure enums')
    ->expect(Role::stringOptions())
    ->toBe('<option value="ADMIN">Admin</option>\n<option value="GUEST">Guest</option>');

Think that works really well. Thanks for the suggestion!

stancl avatar Jan 12 '24 22:01 stancl

Sweet!! Thanks for the ongoing support!

gmgarrison avatar Jan 14 '24 14:01 gmgarrison

Will be tagging v1 tomorrow. Make sure to update your composer dependency to ^1.0 (once it's released).

stancl avatar Jan 14 '24 20:01 stancl