spatie/laravel-options

repository·main·Indexed 42 days ago

https://github.com/spatie/laravel-options

A Laravel package that provides a unified way to transform Enums, Eloquent models, arrays, and Spatie model states into a consistent option structure (label/value pairs) for use in web application select fields and Laravel validation rules.

Tokens
5.7K
Snippets
21
Records
22
Agent score
52%

What's inside Laravel Options

  1. Implement Selectable for models and classes

    main

    To avoid manually defining label and value fields every time you use a model in Options, implement the Selectable interface on your class. This allows you to define a toSelectOption() method that returns a SelectOption object.

    This method can also include extra data that will be appended to the resulting options array.

    class Wizard extends Model implements Selectable
    {
        public function toSelectOption(): SelectOption
        {
            return new SelectOption(
                $this->getName(),
                $this->getUuid(),
                ['color' => $this->color]
            );
        }
    }
    
    // Usage becomes simple:
    Options::forModels(Wizard::class);
  2. Install spatie/laravel-options

    main

    Install the package via Composer and optionally publish the configuration file to customize the keys used for option labels and values.

    composer require spatie/laravel-options
    
    php artisan vendor:publish --tag="options-config"
  3. Configure option label and value keys

    main

    After publishing the config file, you can define which keys are used to represent the label and the value in the resulting option arrays. By default, these are label and value.

    return [
        /*
         * The key used in an option to describe the label of the option
         */
        'label_key' => 'label',
    
        /*
         * The key used in an option to describe the value of the option
         */
        'value_key' => 'value',
    ];
  4. Configure option key names

    main

    You can change the keys used for label and value in the output array by modifying the options.php configuration file.

    Example configuration:

    return [
        'label_key' => 'name',
        'value_key' => 'id',
    ];

    This will change the output from ['label' => '...', 'value' => '...'] to ['name' => '...', 'id' => '...'].

  5. Convert an Enum to options

    main

    You can transform a PHP Enum into a unified list of options (label and value pairs) using Options::forEnum(). This is useful for populating select fields in web applications.

    enum Hobbit: string
    {
        case Frodo = 'frodo';
        case Sam = 'sam';
        case Merry = 'merry';
        case Pippin = 'pippin';
    }
    
    $options = Options::forEnum(Hobbit::class)->toArray();
    
    // Returns:
    // [
    //     ['label' => 'Frodo', 'value' => 'frodo'],
    //     ['label' => 'Sam', 'value' => 'sam'],
    //     ['label' => 'Merry', 'value' => 'merry'],
    //     ['label' => 'Pippin', 'value' => 'pippin'],
    // ]
  6. Create options from Enums

    main

    You can generate an Options object from native PHP enums, Spatie Enums, or MyClabs Enums using Options::forEnum(ClassName::class).

    By default, the package looks for a static labels() method on the enum to resolve labels. You can also specify a custom method name or use a closure to resolve labels.

    To get the data in a specific format, use ->toArray() or ->toJson(). When returning an Options object from a Laravel controller, it will be automatically converted to JSON.

    // Basic usage
    Options::forEnum(Hobbit::class);
    
    // Get array or JSON
    Options::forEnum(Hobbit::class)->toArray();
    Options::forEnum(Hobbit::class)->toJson();
    
    // Custom label method
    Options::forEnum(Hobbit::class, 'hobbitLabels');
    
    // Closure for labels
    Options::forEnum(Hobbit::class, fn(Hobbit $hobbit) => $hobbit->name . ' from the shire');
  7. Manipulate and filter options

    main

    Once an Options object is created, you can transform it using several methods:

    • sort(): Sorts options by label. You can pass a closure for custom sorting.
    • append(closure): Adds additional data to every option.
    • filter(closure): Includes only options that pass the truth test.
    • reject(closure): Excludes options that pass the truth test.
    • only(...$items): Includes only the specified items.
    • except(...$items): Excludes the specified items.
    • nullable(label: string, value: mixed): Adds a null option with a custom label and value.
    // Sorting
    Options::forEnum(Hobbit::class)->sort();
    Options::forEnum(Hobbit::class)->sort(fn(Hobbit $hobbit) => $hobbit->value);
    
    // Appending data
    Options::forEnum(Hobbit::class)->append(fn(Hobbit $hobbit) => [
        'is_important' => $hobbit === Hobbit::Frodo
    ]);
    
    // Filtering
    Options::forEnum(Hobbit::class)->filter(fn(Hobbit $h) => $h === Hobbit::Frodo);
    Options::forEnum(Hobbit::class)->reject(fn(Hobbit $h) => $h === Hobbit::Frodo);
    
    // Inclusion/Exclusion
    Options::forEnum(Hobbit::class)->only(Hobbit::Frodo, Hobbit::Sam);
    Options::forEnum(Hobbit::class)->except(Hobbit::Frodo, Hobbit::Sam);
    
    // Nullable options
    Options::forEnum(Hobbit::class)->nullable();
    Options::forEnum(Hobbit::class)->nullable(label: 'Gandalf', value: 'You Shall Not Pass');
  8. Use options for Laravel validation

    main

    You can convert an Options object into a Laravel validation rule using toValidationRule(). This is useful for validating that an incoming request value exists within your defined options.

    If you have called ->nullable() on your options, the resulting validation rule will automatically include the nullable rule.

    $request->validate([
        // Validates that 'hobbit' is one of the enum values
        'hobbit' => Options::forEnum(Hobbit::class)->toValidationRule()
    ]);
    
    // If nullable() was called, it becomes a nullable validation rule
    $request->validate([
        'hobbit' => Options::forEnum(Hobbit::class)->nullable()->toValidationRule()
    ]);
  9. Create options from Laravel Models

    main

    Generate options from Laravel models using Options::forModels(). You can pass a class name, a single model instance, a collection of models, or a Query Builder instance.

    By default, the model's primary key is used as the value and the name field is used as the label. You can customize these using the value and label parameters (either via field names or closures).

    // From a class
    Options::forModels(Wizard::class);
    
    // From a single instance
    Options::forModels(Wizard::first());
    
    // From a collection
    Options::forModels(Wizard::all());
    
    // From a query builder
    Options::forModels(Wizard::query()->where('name', 'gandalf'));
    
    // Customizing label and value
    Options::forModels(Wizard::class, value: 'uuid');
    Options::forModels(Wizard::class, label: 'full_name');
    Options::forModels(Wizard::class, label: fn(Wizard $wizard) => $wizard->getName());
  10. Create options from Model States

    main

    If you are using spatie/laravel-model-states, you can generate options directly from states using Options::forStates(StateClass::class).

    The package looks for a label() public method or a label public property on the state class. You can customize the label resolution via the label parameter.

    // Basic usage
    Options::forStates(RingState::class);
    
    // Passing a specific model instance
    Options::forStates(RingState::class, $ring);
    
    // Customizing label resolution
    Options::forStates(RingState::class, label: 'ringLabel');
    Options::forStates(RingState::class, label: fn(RingState $state) => $state->label());
  11. Create options from Arrays

    main

    You can create options from associative or plain arrays using Options::forArray().

    • Associative Array: Keys become values, values become labels.
    • Plain Array: If useLabelsAsValue: true is passed, both labels and values will be identical.
    // Associative array
    Options::forArray([
        'gondor' => 'Gondor',
        'rohan' => 'Rohan',
    ]);
    
    // Plain array with labels as values
    Options::forArray([
        'Gondor',
        'Rohan',
    ], useLabelsAsValue: true);