Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trait for string conversion #12

Closed
gmgarrison opened this issue Jun 8, 2022 · 10 comments
Closed

Trait for string conversion #12

gmgarrison opened this issue Jun 8, 2022 · 10 comments

Comments

@gmgarrison
Copy link

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!

@stancl
Copy link
Member

stancl commented Jun 8, 2022

Wouldn't ->name work for this?

@gmgarrison
Copy link
Author

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.

@stancl
Copy link
Member

stancl commented Jun 11, 2022

So essentially something like this?

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

@gmgarrison
Copy link
Author

gmgarrison commented Jun 13, 2022

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!

@roni-estein
Copy link

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.

@stancl
Copy link
Member

stancl commented Jan 12, 2024

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
Copy link
Member

stancl commented Jan 12, 2024

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 stancl closed this as completed in 6684067 Jan 12, 2024
@stancl
Copy link
Member

stancl commented Jan 12, 2024

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!

@gmgarrison
Copy link
Author

Sweet!! Thanks for the ongoing support!

@stancl
Copy link
Member

stancl commented Jan 14, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants