spatie/laravel-options

从不同来源创建选项数组

1.1.1 2024-02-27 14:48 UTC

This package is auto-updated.

Last update: 2024-08-27 16:14:31 UTC


README

Latest Version on Packagist run-tests PHPStan Total Downloads

典型的Web应用程序通常有许多带有选项的选择字段。这个包使将枚举、模型、状态和数组转换为统一的选项结构变得简单。

假设你有以下枚举

enum Hobbit: string
{
    case Frodo = 'frodo';
    case Sam = 'sam';
    case Merry = 'merry';
    case Pippin = 'pippin';
}

你可以将其转换为以下选项

Options::forEnum(Hobbit::class)->toArray();

这将返回以下数组

[
    ['label' => 'Frodo', 'value' => 'frodo'],
    ['label' => 'Sam', 'value' => 'sam'],
    ['label' => 'Merry', 'value' => 'merry'],
    ['label' => 'Pippin', 'value' => 'pippin'],
]

支持我们

我们投入了大量资源来创建一流的开放式源代码包。你可以通过购买我们的付费产品之一来支持我们。

我们非常感激您从家乡寄给我们一张明信片,说明您正在使用我们的哪个包。您可以在我们的联系页面上找到我们的地址。我们将所有收到的明信片发布在我们的虚拟明信片墙上

安装

您可以通过composer安装此包

composer require spatie/laravel-options

您可以使用以下命令发布配置文件

php artisan vendor:publish --tag="options-config"

这是已发布的配置文件的内容

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',
];

用法

您可以这样创建一个Options对象(我们将在后面讨论其他内容,如枚举)

Options::forEnum(Hobbit::class);

您可以通过这种方式获取选项的数组表示形式

Options::forEnum(Hobbit::class)->toArray();

或JSON版本

Options::forEnum(Hobbit::class)->toJson();

您可以将选项作为响应的一部分返回到控制器中,它们将自动转换为JSON

class ShowHobbitsController{
    public function __invoke(RingBearer $ringBearer){
        return [
            'ring_bearer' => $ringBearer,
            'hobbit_options' => Options::forEnum(Hobbit::class)
        ]   
    }
}

操作选项

您可以按标签对选项进行排序

Options::forEnum(Hobbit::class)->sort();

或使用闭包来排序选项

Options::forEnum(Hobbit::class)->sort(fn(Hobbit $hobbit) => $hobbit->value);

您可以通过以下方式向选项添加额外的数据

Options::forEnum(Hobbit::class)->append(fn(Hobbit $hobbit) => [
    'ring_bearer' => $hobbit === Hobbit::Frodo || $hobbit === Hobbit::Sam
]);

这将导致以下选项数组

[
    ['label' => 'Frodo', 'value' => 'frodo', 'ring_bearer' => true],
    ['label' => 'Sam', 'value' => 'sam', 'ring_bearer' => true],
    ['label' => 'Merry', 'value' => 'merry', 'ring_bearer' => false],
    ['label' => 'Pippin', 'value' => 'pippin', 'ring_bearer' => false],
]

您可以过滤要包含的选项

Options::forEnum(Hobbit::class)->filter(fn(Hobbit $hobbit) => $hobbit === Hobbit::Frodo);

这将创建一个较小的选项数组

[
    ['label' => 'Frodo', 'value' => 'frodo'],
]

或拒绝特定的选项被包含

Options::forEnum(Hobbit::class)->reject(fn(Hobbit $hobbit) => $hobbit === Hobbit::Frodo);

这将创建此选项数组

[
    ['label' => 'Sam', 'value' => 'sam'],
    ['label' => 'Merry', 'value' => 'merry'],
    ['label' => 'Pippin', 'value' => 'pippin'],
]

可以添加一个唯一的null选项,如下所示

Options::forEnum(Hobbit::class)->nullable();

这将添加一个值为null的选项

[
    ['label' => '-', 'value' => null],
    ['label' => 'Frodo', 'value' => 'frodo'],
    ['label' => 'Sam', 'value' => 'sam'],
    ['label' => 'Merry', 'value' => 'merry'],
    ['label' => 'Pippin', 'value' => 'pippin'],
]

null选项的标签可以按如下方式更改

Options::forEnum(Hobbit::class)->nullable('Gandalf');

可以为null设置另一个值如下

Options::forEnum(Hobbit::class)->nullable(label: 'Gandalf', value: 'You Shall Not Pass');

可以通过更改options.php配置文件来更改选项中使用的键。例如

return [
    /*
     * The key used in an option to describe the label of the option
     */
    'label_key' => 'name',

    /*
     * The key used in an option to describe the value of the option
     */
    'value_key' => 'id',
];

将导致以下选项

[
    ['name' => 'Frodo', 'id' => 'frodo'],
    ['name' => 'Sam', 'id' => 'sam'],
    ['name' => 'Merry', 'id' => 'merry'],
    ['name' => 'Pippin', 'id' => 'pippin'],
]

与枚举一起使用

您可以创建原生PHP枚举、Spatie EnumsMyClabs Enums的选项,如下所示

Options::forEnum(Hobbit::class);

默认情况下,包将查找一个名为labels的静态方法,将枚举的标签作为数组返回

enum Hobbit: string
{
    case Frodo = 'frodo';
    case Sam = 'sam';
    case Merry = 'merry';
    case Pippin = 'pippin';
    
    public static function labels(): array
    {
       return [
           'frodo' => 'Frodo Baggins',
           'sam' => 'Sam Gamgee',
           'merry' => 'Merry Brandybuck',
           'pippin' => 'Pippin Took',
       ];
    }
}

现在选项数组将看起来像这样

[
    ['label' => 'Frodo Baggins', 'value' => 'frodo'],
    ['label' => 'Sam Gamgee', 'value' => 'sam'],
    ['label' => 'Merry Brandybuck', 'value' => 'merry'],
    ['label' => 'Pippin Took', 'value' => 'pippin'],
]

您可以使用另一个方法名来获取标签,如下所示

Options::forEnum(Hobbit::class, 'hobbitLabels');

或使用闭包来解析枚举的标签

Options::forEnum(Hobbit::class, fn(Hobbit $hobbit) => $hobbit->name. ' from the shire'));

与模型一起使用

您可以创建Laravel模型的选项,如下所示

Options::forModels(Wizard::class);

使用单个模型

Options::forModels(Wizard::first());

或模型集合

Options::forModels(Wizard::all());

您也可以传递一个Builder实例

Options::forModels(Wizard::query()->where('name', 'gandalf'));

默认情况下,模型的关键字(通常是id)将被用作值,而name字段用作标签。

您可以像这样更改值字段

Options::forModels(Wizard::class, value: 'uuid');

或者使用闭包来确定值

Options::forModels(Wizard::class, value: fn(Wizard $wizard) => $wizard->uuid());

您可以这样更改标签字段

Options::forModels(Wizard::class, label: 'full_name');

或者您可以使用闭包来解析标签

Options::forModels(Wizard::class, label: fn(Wizard $wizard) => $wizard->getName());

带有选择选项

如果您在很多地方使用模型的选项,那么每次手动定义标签和/或值字段可能会变得相当繁琐

Options::forModels(
    Wizard::class, 
    label: fn(Wizard $wizard) => $wizard->getUuid(),
    value: fn(Wizard $wizard) => $wizard->getName(),
); // A lot of times within your code base

您可以在模型(或任何PHP类)上实现Selectable,这将自动将模型转换为具有正确字段的选项

class Wizard extends Model implements Selectable
{
    public function toSelectOption(): SelectOption
    {
        return new SelectOption(
            $this->getName(),
            $this->getUuid()
        )
    }
}

现在您可以省略标签和值字段定义

Options::forModels(Wizard::class);

您还可以使用SelectOption传递一些额外的数据,就像我们之前看到的append方法一样

public function toSelectOption(): SelectOption
{
    return new SelectOption(
        $this->getName(),
        $this->getUuid(),
        ['color' => $this->color]
    )
}

现在选项数组将看起来像这样

[
    ['label' => 'Gandalf', 'id' => '...', 'color' => 'gray'],
    ['label' => 'Saruman', 'id' => '...', 'color' => 'white'],
]

如前所述,实现Selectable不仅限于模型。您可以在任何PHP类上实现它。在这种情况下,您可以创建如下选项

Options::forSelectableOptions([
    SelectableOption::find(1),
    SelectableOption::find(2),
    SelectableOption::find(3),
]);

带有状态

您可以使用Spatie的model-states包创建选项,如下所示

Options::forStates(RingState::class);

您可以传入一个模型(否则将创建一个临时模型)

Options::forStates(RingState::class, $ring);

该包将自动查找一个名为label的公共方法,用作标签

class LostRingState extends RingsState
{
    public function label(): string
    {
        return 'Lost';
    }
}

或一个名为label的公共属性

class DestroyedRingState extends RingsState
{
    public string $label = 'destroyed';
}

您可以更改用作标签的方法或属性的名称,如下所示

Options::forStates(RingState::class, label: 'ringLabel');

或使用闭包来解析状态的标签

Options::forStates(RingState::class, label: fn(RingState $state) => $state->label());

使用数组

您可以从关联数组创建一系列选项

Options::forArray([
    'gondor' => 'Gondor',
    'rohan' => 'Rohan',
    'mordor' => 'Mordor',
])

您也可以使用这样的普通数组

Options::forArray([
    'Gondor',
    'Rohan',
    'Mordor',
],useLabelsAsValue: true)

在这种情况下,标签和值将相等。

没有任何东西

最后,您可以创建一个空的选项列表,如下所示

Options::empty();

用于验证

选项可以被转换为Laravel验证规则

$request->validate([
    // ['in:frodo,sam,merry,pippin']
    'hobbit' => Options::forEnum(Hobbit::class)->toValidationRule()
]); 

当选项可为空时,验证规则将自动变为可为空

$request->validate([
    // ['nullable', 'in:frodo,sam,merry,pippin']
    'hobbit' => Options::forEnum(Hobbit::class)->nullable()->toValidationRule()
]);

迭代

您可以对一系列选项进行迭代

foreach(Options::forEnum(Hobbit::class) as $option){
    echo "<option value={$option['value']}>{$option['label']}</option>";
}

测试

composer test

更新日志

请参阅更新日志以获取有关最近更改的更多信息。

贡献

请参阅贡献指南以获取详细信息。

安全漏洞

请查阅我们的安全策略以了解如何报告安全漏洞。

鸣谢

许可证

MIT许可证(MIT)。请参阅许可证文件以获取更多信息。