pkaratanev/nova-repeatable-fields

一个Laravel Nova字段。

v1.4.0 2021-01-19 09:45 UTC

This package is auto-updated.

Last update: 2024-09-19 18:38:47 UTC


README

注意

强烈建议您使用Nova灵活内容包,而不是此包

Nova灵活内容

Nova灵活内容包正在积极维护,允许您将任何有效的Nova字段用作子字段。由于其他承诺,此包仅偶尔维护,并且不太可能添加新功能,因此新用户应强烈考虑使用Nova灵活内容包而不是此包。

希望迁移到Nova灵活内容包的此包现有用户需要做一些工作来迁移数据。请参阅下文附录提供的迁移数据潜在解决方案。

Nova应用程序的可重复字段

此包包含一个Laravel Nova字段,可以创建可重复的“子”字段集。Nova用户可以自由创建、重新排序和删除多个行数据,这些数据通过您定义的子字段。数据以JSON格式保存到数据库中。

示例

Nova repeatable field set on Nova form view

安装

您可以通过composer将此包安装到使用Nova的Laravel应用程序中

composer require pkaratanev/nova-repeatable-fields

用法

要添加重复字段,请在您的Nova资源中使用Pkaratanev\NovaRepeatableFields\Repeater字段

namespace App\Nova;

use Pkaratanev\NovaRepeatableFields\Repeater;

// ...

class Petstore extends Resource
{
    // ...

    public function fields(Request $request)
    {
        return [
            // ...

            Repeater::make('Dogs'),

            // ...
        ];
    }
}

为了使用此包,您还应确保您的Nova资源所代表的Eloquent模型将您希望用作重复字段属性的属性转换为数组

namespace App;

// ...

class Petstore extends Model
{
    protected $casts = [
        'dogs' => 'array'
    ]
}

底层数据库字段应为stringtext类型字段。

配置

此包包含各种选项,您可以使用这些选项定义重复器内的子字段

addField

参数:array

您创建的每个重复字段至少应包含一个通过addField添加的子字段。addField方法接受一个子字段配置选项数组

Repeater::make('Dogs')
    ->addField([
        // configuation options
    ])

配置选项包括

label
[
    'label' => 'Dog name',
    //...
]

所有子字段至少必须定义一个“标签”。这是一个人类可读的字符串,将在Nova UI中显示。

name
[
    'name' => 'dog_name',
    //...
]

默认情况下,子字段的name(用于在数据库中保存数据)将自动使用子字段label的蛇形版本生成。或者,您可以自由地覆盖此约定并定义一个要使用的自定义名称。

type
[
    'type' => 'number',
    //...
]

默认情况下,子字段的输入类型将是标准文本字段。如果需要,您可以定义不同的字段类型。当前支持的子字段类型有:“text”、“number”、“select”、“textarea”。

placeholder
[
    'placeholder' => 'Name that dog',
    //...
]

默认情况下,输入的placeholder将与子字段的label相同。然而,您可以使用此选项定义一个自定义占位符,该占位符将显示为替代。

width

[
    'width' => 'w-1/2',
    //...
]

如果您选择将子字段以行形式显示(而不是堆叠形式 - 见下方的 displayStackedForm 选项),您可以使用 Tailwind 的分数宽度类 定义字段的宽度。除非您想定义所有字段的宽度,否则您不需要定义宽度。如果没有为任何子字段输入宽度,则所有子字段将具有相同的宽度。

请注意,您可以混合和匹配宽度。例如,您可以将前两个字段的宽度设置为 50%,使用 w-1/2,然后将最后一个字段设置为全宽度,使用 w-full

如果您以堆叠布局显示子字段,则宽度选项将没有效果。

选项
[
    'options' => [
        'fido' => 'Fido',
        'mr_bubbles' => 'Mr Bubbles',
        'preston' => 'Preston'
    ],
    //...
]

如果您正在定义的子字段的 type 为 'select',您需要定义一个用于选择字段的选项数组。这些使用键值对数组定义。

属性
[
    'attributes' => [
        'min' => 1,
        'max' => '20',
        'style' => 'color: red'
    ],
    //...
]

通过 attributes 键,您可以使用关联数组定义您希望通过 v-bind 添加到输入中的任何自定义属性。这些将通过 v-bind 添加。例如,您可能希望向数字字段添加最小或最大步长,或将样式属性添加到文本字段。

添加按钮文本

Repeater::make('Dogs')
    ->addButtonText('Add new dog');

您可以配置用于在 Nova UI 中添加新组子字段的按钮文本。默认情况下,此按钮标记为 '添加行',但您可以使用 addButtonText 选项覆盖此文本。

摘要标签

Repeater::make('Dogs')
    ->summaryLabel('Dogs');

详细视图和索引视图会显示使用重复字段输入的数据的摘要。默认情况下,这将显示行数,例如 '3 行',以及一个链接,用于展开以显示输入的完整数据

Nova repeatable field set on Nova index view - collapsed state

您可以覆盖此摘要文本,例如为 '3 只狗'

Nova repeatable field set on Nova index view - expanded state

显示堆叠表单

Repeater::make('Dogs')
    ->displayStackedForm();

默认情况下,一组子字段将作为一系列水平对齐的输入字段显示

Nova repeatable field set on Nova form view - default horizontal fields

这对于只有 2 或 3 个子字段的重复字段来说效果很好,但是对于较大的字段集,显示重复子字段的上对下堆叠表单通常是一个更可用的布局。您可以使用此选项切换到堆叠布局。

初始行数

Repeater::make('Dogs')
    ->initialRows(4);

设置在表单初始化时将预先添加的行数。对于具有现有行的表单,它将附加到设置的行数。

最大行数

Repeater::make('Dogs')
    ->maximumRows(4);

设置行数的上限。达到此限制后,您将无法添加新行。

标题

Repeater::make('Dogs')
    ->heading('Dog');

设置每行之间的标题(例如,狗 #1,狗 #2)。仅当与 "displayStackedForm" 一起使用时才有效。

附录 - 将数据迁移到 Nova 灵活内容

本指南仅适用于希望使用 Nova 灵活内容包的现有用户,并希望了解如何迁移数据。

请注意,以下解决方案仅作为指南。您需要自行实现和测试针对您数据解决方案,并且强烈建议在运行任何会更改多个数据库行的代码之前备份任何数据。

对于您使用以下代码导致的现有数据更改,我概不负责。明白了?好的,让我们继续...

本指南假设您已经 安装了 Nova 灵活内容包,并且您已经 设置了一个用于要迁移的数据的布局

接下来,在您的应用程序中创建一个新的 artisan 命令: php artisan make:command MigrateRepeaterData

添加以下代码,使您的命令看起来像这样

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Schema;

class MigrateRepeaterData extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'nfc:migrate';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Migrate your repeater data to be compatible with Nova Flexible Content';


    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        // Get the model to run this command for
        $model = $this->ask('Which model do you want to migrate data for?  Enter the full namespace e.g. App\Post');

        if(! class_exists($model)){
            $this->error("Sorry - could not find a model called {$model}");
            return;
        }

        // Get the attribute on the model that holds the old repeater data
        $attribute = $this->ask('Which model attribute holds the data you want to migrate?');

        if(! Schema::hasColumn((new $model)->getTable(), $attribute) ){
            $this->error("Sorry - could not find a database column  called {$attribute} for {$model}");
            return;
        }

        // Get the Nova Flexible Content layout name
        $layout = $this->ask('What is the name of the Nova Flexible Content layout for this data?');

        $models = $model::all();

        if ($this->confirm("About to migrate data for {$models->count()} models.  Do you wish to continue?")) {
            $models->each(function($model) use ($attribute, $layout){
                $model->$attribute = $this->updateValues($model->$attribute, $layout);
                $model->save();
            });

            $this->info('All done!  Please check your data to ensure it was migrated correctly');
        }
    }

    protected function updateValues($data, $layout)
    {
        // Skip anything that is not an array with elements and keep the value the same
        if(! $data){
            return $data;
        }

        return collect($data)
            ->map(function($attributes) use ($layout){
                return [
                    // Create a random key
                    'key' => $this->generateKey(),
                    // my_nova_flexible_content_layout should match the name
                    // you gave to your Nova Flexible Content layout
                    'layout' => $layout,
                    // The data for a given repeater 'row'
                    'attributes' => $attributes
                ];
            })
            ->all();
    }

    protected function generateKey()
    {
        if (function_exists("random_bytes")) {
            $bytes = random_bytes(ceil(16/2));
        }
        elseif (function_exists("openssl_random_pseudo_bytes")) {
            $bytes = openssl_random_pseudo_bytes(ceil(16/2));
        }
        else {
            throw new \Exception("No cryptographically secure random function available");
        }
        return substr(bin2hex($bytes), 0, 16);
    }
}

变更日志

有关最近更改的更多信息,请参阅 变更日志

鸣谢

许可证

麻省理工学院许可证(MIT)。请参阅许可证文件以获取更多信息。