nomensa/form-builder

v0.52.0 2019-08-07 16:34 UTC

README

商业案例

本包通过提供以下需求的解决方案,减少了应用程序开发的时间和成本

  • 业务流程涉及填写许多、长、复杂的表单。
  • 表单“所有权”在不同的用户角色之间传递。
  • 表单在其生命周期中通过“状态”移动,不同的字段变为可编辑/可见。
  • 版本控制 - 表单上的问题可能在将来某天更改,但针对它们的答案必须与填写表单时的问题保持一致。
  • 跨多个表单版本进行报告。在表单上的一些问题更改的情况下,必须能够生成包含两个版本的报告。

开发者案例

FormBuilder旨在通过提供以下功能来减少开发者的复杂性和重复性

  • 能够将长而复杂的表单定义为JSON结构,并让应用程序标记HTML。
  • 能够选择应用于标记中元素的CSS类名。
  • Artisan命令用于创建所需的数据库迁移、模型、控制器以及创建新的表单模式。

无障碍案例

尽管最终责任在于开发者使界面无障碍,但FormBuilder不会妨碍这一点。在定义如何标记表单时已遵循当前标准,但如果需要实现边缘情况,已设置了覆盖系统所有部分的条款。

表单“状态”

每个表单可以具有多个状态,并且表单中的每个字段在每个状态中都可以用以下4种方式之一进行标记。

可能值是

  • 可编辑 - 可见并可编辑
  • 只读 - 可见但不能编辑
  • 隐藏 - 不可见但可编辑(例如,通过自定义JavaScript)
  • 忽略 - 不包括在表单标记中

它们可以想象为一个可编辑性和可见性的2x2矩阵。

            ---------------------
    ^       | hidden | editable |
    |       |--------|----------|
editability | ignore | readonly |
            ---------------------
              visibility -->

让我们以学校家庭作业作为简单的例子。想象一个简单的测验表单由学生开始,学生必须填写3个答案字段。提交后,表单传递给教师,前3个答案字段现在变为只读,并揭示一个名为'反馈'的第四个字段,只有教师可以填写。当教师提交表单时,所有4个字段都变为只读,学生和教师都无法编辑字段,但他们都可以以只读状态查看它们。

在上面的例子中,表单有3个状态

  1. 学生查看字段的方式
  2. 教师查看字段的方式
  3. 最终状态中字段显示的方式

它们通过方案中的键值对对象为每个字段设置。状态给出了键名称,与该表单相关的人类描述,值是特定字段如何显示。

这是为第一个答案字段设置状态对象的方式

"states": {
    "student-answering": "editable",
    "teacher-marking": "readonly",
    "final-view": "readonly"
}

遗留状态值

代码库目前包含对一些已弃用值的支持。这些特定用例的值是FormBuilder最初为的应用程序留下的遗产,将不支持未来的版本。

仅供参考,不应使用

  • editable_if_true_else_ignore
  • editable_if_true_else_readonly
  • hidden-for-learner
  • readonly_for_owner

显示模式

显示模式描述了用户在请求期间如何与表单交互。它只能是以下4个CRUD动词之一:创建、读取、更新、删除。

  • 您可以使用->setDisplayMode(string $verb)方法在FormBuilder实例上设置它。
  • 您可以使用->isDisplayMode(string $verb)方法检查FormBuilder是否处于特定显示模式,该方法返回一个布尔值。
  • 您可以使用->getDisplayMode()方法获取它。

它通常简单地实现为一个枚举变量,可以用来确定像在自定义组件中显示什么按钮或文字之类的信息(例如,按钮是否说“创建”或“更新”)。

然而,显示模式的一个内置用途是在字段渲染时。如果一个表单在读取模式下渲染,则当前状态下可编辑的字段将被覆盖为只读。 (注意:反之则不成立,如果显示模式是“更新”,则只读字段不会被强制变为可编辑)。

入门

按照以下步骤安装很简单

使用安装命令将包添加到composer.json

$ composer require nomensa/form-builder

config/app.php文件中添加服务提供者

'providers' => [
    ...
    Nomensa\FormBuilder\FormBuilderServiceProvider::class,
];

config/app.php文件中添加别名

'aliases' => [
    ...
    'FormBuilder' => Nomensa\FormBuilder\FormBuilder::class,
    'CSSClassFactory' => Nomensa\FormBuilder\BootstrapCSSClassFactory::class,
],
  • 运行php artisan formbuilder:install
  • 添加路由声明
  • 运行数据库迁移以重建数据库模式
  • 包含FormBuilder JavaScript脚本

创建基本的第一表单

运行artisan命令创建表单,让我们称它为"我的第一个表单"

$ php artisan formbuilder:make-form MY-FORM "My First Form"

现在在您的编辑器中打开/app/FormBuilder/Forms/MY-FORM/schema.json,并粘贴以下代码

[
 {
   "type": "dynamic",
   "rows": [
     {
       "editing_instructions": "Welcome to my great form."
     },
     {
       "columns": [
         {
           "field": "first-form-name",
           "label": "Name",
           "type": "text",
           "helptext": "What people call you",
           "states": {
             "state-1": "editable",
             "state-2": "readonly"
           }
         }
       ]
     },
     {
       "title": "Time",
       "columns": [
         {
           "field": "first-form-love-kittens",
           "label": "I love kittens",
           "type": "checkbox",
           "states": {
             "state-1": "editable",
             "state-2": "readonly"
            }
         }
       ]
     }
   ]
 }
]

现在我们在控制器中创建FormBuilder实例,并加载此表单

<?php
 
namespace App\Http\Controllers;
 
class MyGreatFormController extends Controller
{
    
    ...
    
    public function create() 
    {
        $entryForm = EntryForm::where('slug','my-form')->firstOrFail();
        
        $formVersion = $entryForm->currentFormVersion;
        $formBuilder = $formVersion->getFormBuilder();
        
        // TODO: In a future release this will be tidied so errors are pulled from the session automatically
        $errors = new MessageBag();
        
        $arrSession = session()->all();
        if (isSet($arrSession['errors'])) {
            $errors = $arrSession['errors']->getBag('default');
        }
        $formBuilder->errors = $errors;
        
        $formBuilder->setState('editing');
        $formBuilder->setDisplayMode('creating');
        
        return view('form.create', $formBuilder->viewData);
    }
    
}    

然后在视图中,这个库真正帮您节省了很多代码!

// form/create.blade.php

<h1>My Great Form</h1>

{{ Form::open() }}

    {!! $formBuilder->markup() !!}
    
    {{ Field::submit('Save') }}

{{ Form::close() }}

待办事项:完成此部分以描述表单提交的创建/读取/更新和删除。

贡献者

阅读CONTRIBUTING.md

依赖项

FormBuilder依赖于Laravel Collective的HTML和表单包。

Artisan命令

FormBuilder提供了一些Artisan命令,以简化生活

  • formbuilder:install - 在您的应用程序中创建所需的数据库迁移、模型和控制台。它还创建一个用于存储模式文件夹,以及一个用于任何blade模板的文件夹。
  • formbuilder:make-form [Form Code] [Form Title] - 在文件系统中创建新的表单模式,并在数据库表中创建相应的条目。

布局

FormBuilder假定行-列布局,但没有假设任何CSS框架。提供了一个开箱即用的Bootstrap类工厂,但如果您喜欢不同的框架或您自己的自定义CSS类,您可以编写一个实现CSSClassFactory的类,并在config/app.php中切换别名以引用它。

字段类型

除了显然的预期类型,如texttextareaselectcheckbox (单数)之外,FormBuilder还提供了一些多选,使界面更加易于访问

  • checkboxes - 所有具有共享名称前缀的多个复选框
  • radios - 一组具有共享名称的单选按钮

自定义组件

尽管表单上的大多数输入字段都是常见的,但有时您需要做一些不同的事情。为此,任何表单模式都可以包含自定义组件,允许您做任何事情。

首先,在FormBuilder组件文件夹中创建一个Blade模板(例如,/views/components/formbuilder/example-component.blade.php

其次,按照以下方式在表单模式中添加对其的引用

[
  {
    "type": "example-component"
  }
]

如果您的模板将包含任何需要在请求中读取的输入字段,请按如下方式命名它们在field-mappings

例如,假设您的自定义组件包含一个名为“address[gps-location]”的隐藏输入元素。以下架构配置将确保它可以从请求变量中读取。

[
  {
    "type": "logbook-hospital-select",
    "field-mappings": {
      "address.gps-location": "GPS Location"
    }
  }
]

最后,如果您想在多个表单中重复使用相同的自定义组件,您可能想将其注入一些变量以供Blade使用。您可以在架构中的componentData中声明任何变量作为键值对来完成此操作。

[
  {
    "type": "file-upload",
    "componentData": {
      "instructions": "Please attach an image of a kitten."
    }
  }
]  

有趣的边缘情况

由于表单构建器是作为特定客户应用的组成部分开发的,因此它考虑了一些其他表单构建器包没有考虑的边缘情况。

  • 单选按钮的类型,客户要求用户显式设置一个值,没有预先选择。

数据库模型表

这个库包含了8个表的迁移。这些迁移将被Laravel自动发现。如果您想禁用发现,您可以退出包发现并将迁移复制到您的应用程序代码中。

entry_form_types

分组输入表单的类别(entry_forms)。

entry_forms

包含输入表单(这些可以简单地称为“表单”)(这些可以简单地称为“表单”)。每一行属于entry_form_types中的一行。

form_versions

定义表单的当前和旧版本架构(它包含哪些字段),以适应未来的更改和现有提交的向后兼容性。每一行属于entry_forms中的一行。

workflows (弃用)

最初引入是为了存储工作流的描述,因此实例可以属于它。工作流将描述是否由一个角色启动然后传递给另一个或反之亦然。在实践中,这很令人困惑,并且工作流最好通过良好的表单提交状态(form_submission_status_id)或由控制器设置的表单元数据来表示。

form_instances (弃用)

这是form_submissionsform_versions之间的链接,将在未来的版本中删除。

form_submission_statuses

表单在其生命周期中移动的命名阶段。

form_submissions

用户对特定表单版本进行的具体数据提交。目前每一行属于form_instances中的一行,但在此弃用时,它将属于form_versions中的一行。

form_submission_fields

保存特定表单提交的特定字段的数据。每一行属于form_submissions中的一行。

form_associations

一个连接表,用于关联其他表单提交的form_submissions。`type`列是一个人性化的缩写,描述了根表单提交与目标表单提交之间的关系(例如,a_goal_of或a_reflection_on)