distilleries/form-builder 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

distilleries/form-builder

Composer 安装命令:

composer require distilleries/form-builder

包简介

Based on laravel-form-builder (https://github.com/kristijanhusak/laravel-form-builder). That add default component and add view system.

README 文档

README

Scrutinizer Code Quality Code Coverage Build Status Total Downloads Latest Stable Version License

Laravel 5 Form Builder

Based on laravel-form-builder (https://github.com/kristijanhusak/laravel-form-builder). I add default no editable form and few complex form fields. I add the validation system directly in the form part.

Table of contents

  1. Installation
  2. Basic usage
  3. Type of form
  4. Form
  5. FormView
  6. FormValidator 1. Use the validation client side 2. Use the validation server side 3. Check the rules on your controller
  7. List of fields
  8. Input
  9. Choice 1. Select 2. Radio 3. Checkbox 4. Ajax
  10. Tag
  11. Upload
  12. TinyMce
  13. Textarea
  14. Button
  15. Address Picker
  16. Form
  17. Controller
  18. Troubleshooting

##Installation

Add on your composer.json

    "require": {
        "distilleries/form-builder": "2.*",
    }

run composer update.

Add Service provider to config/app.php:

    'providers' => [
        // ...
       'Distilleries\FormBuilder\FormBuilderServiceProvider',
    ]

And Facade (also in config/app.php)

    'aliases' => [
        // ...
        'FormBuilder'       => 'Distilleries\FormBuilder\Facades\FormBuilder',
    ]

Export the configuration:

php artisan vendor:publish --provider="Distilleries\FormBuilder\FormBuilderServiceProvider"

Export the views (optional):

php artisan vendor:publish --provider="Distilleries\FormBuilder\FormBuilderServiceProvider"  --tag="views"

###Basic usage

Creating form classes is easy. With a simple artisan command I can create form:

    php artisan make:form Forms/PostForm

you create form class in path app/Forms/PostForm.php that looks like this:

<?php namespace App\Forms;

use Distilleries\FormBuilder\FormValidator;

class PostForm extends FormValidator
{
    public static $rules        = [];
    public static $rules_update = null;

    public function buildForm()
    {
        // Add fields here...

         $this->addDefaultActions();
    }
}

You can add fields which you want when creating command like this:

php artisan make:form Forms/SongForm --fields="name:text, lyrics:textarea, publish:checkbox"

And that will create form in path app/Forms/SongForm.php with content:

<?php namespace App\Forms;

use Distilleries\FormBuilder\FormValidator;

class SongForm extends FormValidator
{
    public static $rules        = [];
    public static $rules_update = null;

    public function buildForm()
    {
        $this
            ->add('name', 'text')
            ->add('lyrics', 'textarea')
            ->add('publish', 'checkbox');

         $this->addDefaultActions();
    }
}

##Type of form

###Form

This is the base class from the package https://github.com/kristijanhusak/laravel-form-builder/tree/laravel-4. It use to add the fields and generate the form. Check the readme to know how use the component.

###FormView Extend the class Form to add a render with edit.

####Use the view To display an not editable form you can use form_view or form_rest_view. To display a specific field you can use form_widget_view.

 {!! form_view($form) !!}

In your form field you can add an option to not display this field on the view noInEditView.

For example in user form I add a choice to allow the password change. I don't want it in the view part.

    $this->add('change_password', 'checkbox', [
        'default_value' => 1,
        'label'         => _('Check it if you want change your password'),
        'checked'       => false,
        'noInEditView'  => true
    ]);

Other way, you have a sub form and you don't want display some fields. You can specify an option call do_not_display_ plus the name of the field.

Example I have a customer form and this form use a sub form user. On the user form I don't want display the role choice:

       $this->add('user', 'form', [
           'label' => _('User'),
           'icon'  => 'user',
           'class' => \FormBuilder::create('Distilleries\Expendable\Forms\User\UserForm', [
               'model'                  => $this->getUserModel(),
               'do_not_display_role_id' => true
           ])
       ]);

###FormValidator Extend the FormView and add the system of validation.

  public static $rules = [];
  public static $rules_update = null;

The both table use the rules of laravel. If the $rules_update keep in null the $rules is use to validate the form.

####Use the validation client side By default I use jQuery validation Engine for the javascript validation. When you add a field you can add an option validation to add the javascript validation.

   $this->add('email', 'email',
    [
        'validation' => 'required,custom[email]',
    ]);

####Use the validation server side

If you have a form User like this:

<?php namespace Project\Forms;

use Distilleries\FormBuilder\FormValidator;


class UserForm extends FormValidator {

    public static $rules = [
        'email'    => 'required|email|unique:users',
        'password' => 'required|min:8',
        'status'   => 'required|integer',
        'role_id'  => 'required|integer',
    ];

    public static $rules_update = [
        'id'      => 'required',
        'email'   => 'required|email|unique:users,email',
        'status'  => 'required|integer',
        'role_id' => 'required|integer',
    ];

    // ------------------------------------------------------------------------------------------------


    public function buildForm()
    {

        $this
            ->add($this->model->getKeyName(), 'hidden')
            ->add('email', 'email',
                [
                    'label'      => _('Email'),
                    'validation' => 'required,custom[email]',
                ]);

        $id = $this->model->getKey();

        if (!empty($id))
        {
            $this->add('change_password', 'checkbox', [
                'default_value' => 1,
                'label'         => _('Check it if you want change your password'),
                'checked'       => false,
                'noInEditView'  => true
            ]);
        }

        $this->add('password', 'password',
            [
                'label'      => _('Password'),
                'attr'       => ['id'=>'password'],
                'validation' => 'required',
                'noInEditView'  => true
            ])
            ->add('password_match', 'password',
                [
                    'label'      => _('Repeat Password'),
                    'validation' => 'required,equals[password]',
                    'noInEditView'  => true
                ])
            ->add('status', 'choice', [
                'choices'     => StaticLabel::status(),
                'empty_value' => _('-'),
                'validation'  => 'required',
                'label'       => _('Status')
            ])
            ->add('role_id', 'choice', [
                'choices'     => \Role::getChoice(),
                'empty_value' => _('-'),
                'validation'  => 'required',
                'label'       => _('Role')
            ])
            ->addDefaultActions();
    }

    protected function getUpdateRules()
    {
        $key                           = \Input::get($this->model->getKeyName());
        static::$rules_update['email'] = 'required|email|unique:users,email,' . $key;

        return parent::getUpdateRules();
    }

    // ------------------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------------------

}

You can see the password field is not require on the update. I have an other specific rule. I want check if the email address is unique without if the email is use by your-self.

In the FormValidator you have two methods to get the update or general rules (getGeneralRules, getUpdateRules) . You can override them to return the good rules. That what I do in the UserForm. I override the method getUpdateRules to add the id of user for the validation.

####Check the rules on your controller:

   $form = FormBuilder::create('Project\Forms\UserForm', [
    'model' => new User
   ]);
       
   if ($form->hasError())
   {
       return $form->validateAndRedirectBack();
   }
   

validateAndRedirectBack do only a redirect back with errors and Inputs.

   Redirect::back()->withErrors($this->validate())->withInput(Input::all());

##List of fields

###1 Input

Can be one of those type:

Field Type
text <input type="text" />
email <input type="email" />
url <input type="url" />
tel <input type="tel" />
number <input type="number" />
date <input type="date" />
search <input type="search" />
password <input type="password" />
hidden <input type="hidden" />
number <input type="number" />
file <input type="text" />
    $this->add('first_name', 'text', [
        'validation' => 'required',
        'label'      => _('First name')
    ])

###2 Choice

####2.1 Select

 $this->add('subscription', 'choice', [
        'choices' => ['monthly' => 'Monthly', 'yearly' => 'Yearly'],
        'empty_value' => '==== Select subscription ===',
        'multiple' => false // This is default. If set to true, it creates select with multiple select posibility
    ])

####2.2 Radio

$this->add('subscription', 'choice', [
       'choices' => ['monthly' => 'Monthly', 'yearly' => 'Yearly'],
       'selected' => 'monthly',
       'expanded' => true
   ])

###2.3 Checkbox

$this->add('subscription', 'choice', [
     'choices' => ['monthly' => 'Monthly', 'yearly' => 'Yearly'],
     'selected' => ['monthly', 'yearly']
     'expanded' => true,
     'multiple' => true
 ])

###2.4 Ajax The tag component is base on select2.

Add the javascript on your bower components:

    "dependencies": {
        "select2": "~3.5.2"
    }

This component is use to search an element, or multiple elements.

    $this-> ->add('user_id', 'choice_ajax', [
       'action'     => action('Admin\UserController@postSearch'),
       'validation' => 'required',
       'formatter'  => [
           'id'      => 'id',
           'libelle' => 'email',
       ],
       'label'      => _('User')
   ]);
Field Explain
action The url of the action for the autocomplete
validation The rules of the javascript validation
formatter To display an element select2 need to know who is the value and who is the text. You can use , to concat fields ex: 'libelle' => 'first_name,last_name',.
label The translation of the label display
maximum_selection_size If you want limit the number of elements selectable. By default -1 no limit
multiple If is a select mutiple or not
minimumInputLength Minimum of char needed before send the search request. By default 2 char.
allowClear Allow to remove the value from the field.

This code is an example of controller method for the search:

   // ------------------------------------------------------------------------------------------------
   public function postSearch()
   {

       $ids = Input::get('ids');


       if (!empty($ids))
       {
           $data = $this->model->whereIn($this->model->getKeyName(), $ids)->get();

           return Response::json($data);
       }

       $term  = Input::get('term');
       $page  = Input::get('page');
       $paged = Input::get('page_limit');

       if (empty($paged))
       {
           $paged = 10;
       }

       if (empty($page))
       {
           $page = 1;
       }
       if (empty($term))
       {
           $elements = array();
           $total    = 0;
       } else
       {
           $elements = $this->model->search($term)->take($paged)->skip(($page - 1) * $paged)->get();
           $total    = $this->model->search($term)->count();

       }

       return Response::json([
           'total'    => $total,
           'elements' => $elements
       ]);

   }

Render editable:

choice_ajax

choice_ajax_multiple

Render not editable:

choice_ajax_view

###3 Tag The tag component is base on select2.

Add the javascript on your bower components:

    "dependencies": {
        "select2": "~3.5.2"
    }
    $this->add('cc', 'tag', [
        'label'       => _('CC')
    ])

Render editable:

cc

Render not editable:

cc_view

###4 Upload The upload field use moximanager to link the elements with all the media components.

   $this->add('file', 'upload',
   [
       'label'      => _('File'),
       'validation' => 'required',
       'extensions' => 'csv,xls,xlsx',
       'view'       => 'files',
   ]);

Render editable:

cc

###5 TinyMce If you want use a rich content editor you can use tinymce.

    $this->add('description', 'tinymce', [
        'label'      => _('Description')
    ]);

Render editable:

tinymce

Render not editable:

tinymce_view

###6 Textarea The textarea work like a text field.

    $this->add('description', 'textarea', [
        'label'      => _('Description')
    ]);

###7 Button You can add a button to submit your form or to back at the last page.

    $this->add('submit', 'submit',
    [
        'label' => _('Save'),
        'attr'  => [
            'class' => 'btn green'
        ],
    ], false, true)
    ->add('back', 'button',
    [
        'label' => _('Back'),
        'attr'  => [
            'class'   => 'btn default',
            'onclick' => 'window.history.back()'
        ],
    ], false, true);
                

Render editable:

button

The button submit for the part not editable is never render.

###8 Address Picker

The address picker base on http://logicify.github.io/jquery-locationpicker-plugin/

Add the javascript on your bower components:

    "dependencies": {
        "jquery-locationpicker-plugin": "~0.1.12"
    }
$this->add('address', 'address_picker', [
    'default_value' => [
               'lat'     => 10,
               'lng'     => 10,
               'street'  => '42 Wallaby Way',
               'city'    => 'Sydney',
               'country' => 'Australia',
               'default' => '42 Wallaby Way, Sydney, Australia',
           ]
       ]
]);

Render editable:

address_picker

Render not editable:

address_picker_view

###9 Form You can add a form in a form. It pretty cool when you compose a big form to split it in multiple. For example I have a profile form with an address. I use the address on the profile form.

  $this
    ->add('address', 'form', [
        'label' => _('Address'),
        'icon'  => 'globe',
        'class' => \FormBuilder::create('Project\Forms\AddressForm', [
            'model'                     => $address,
            'do_not_display_profile_id' => true
        ])
    ]);

Render editable:

form

Render not editable:

form_view

##Controller

You can use the trait Distilleries\FormBuilder\States\FormStateTrait to add in your controller the default methods use with the form.

Example: I created a UserForm class:

<?php namespace App\Forms;

use Distilleries\FormBuilder\FormValidator;

class UserForm extends FormValidator
{
    public static $rules        = [
        'email'=>'required'
    ];
    public static $rules_update = null;

    public function buildForm()
    {
        $this
            ->add('id', 'hidden')
            ->add('email', 'email');

         $this->addDefaultActions();
    }
}

I created a controller app/Http/Controllers/FormController:

<?php namespace App\Http\Controllers;


use App\Forms\UserForm;
use Distilleries\FormBuilder\States\FormStateTrait;

class FormController extends Controller {

	use FormStateTrait;
	/*
	|--------------------------------------------------------------------------
	| Welcome Controller
	|--------------------------------------------------------------------------
	|
	| This controller renders the "marketing page" for the application and
	| is configured to only allow guests. Like most of the other sample
	| controllers, you are free to modify or remove it as you desire.
	|
	*/

	/**
	 * Create a new controller instance.
	 *
	 * @return void
	 */
	public function __construct(\App\User $model, UserForm $form)
	{
		$this->model = $model;
		$this->form = $form;
	}

	/**
	 * Show the application welcome screen to the user.
	 *
	 * @return Response
	 */
	public function getIndex()
	{

		return $this->getEdit();

	}

}

I add the controller on the route file :

Route::controllers([
	'form' => 'FormController'
]);

Like you can see I inject the model and the form on the constructor. On the published template I add my style resources/views/vendor/form-builder/state/form.blade.php

<html>
<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
    <script src="//cdn.datatables.net/1.10.5/js/jquery.dataTables.min.js"></script>
    <!-- Latest compiled and minified CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">

    <!-- Optional theme -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css">
    <link rel="stylesheet" href="//cdn.datatables.net/1.10.5/css/jquery.dataTables.min.css">

    <!-- Latest compiled and minified JavaScript -->
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
    <script src="/vendor/datatable-builder/js/datatable.js"></script>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-12">
            @include('form-builder::form.partial.errors')
            <div class="tabbable tabbable-custom boxless tabbable-reversed ">
                @yield('form')
            </div>
        </div>
    </div>
</div>
</body>
</html>

That it you have your form link to the user model.

##Troubleshooting

When you use the trait on your controller remove the route cache to be sure the routes are correctly generated.

php artisan route:cache && php artisan route:list

distilleries/form-builder 适用场景与选型建议

distilleries/form-builder 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 20.21k 次下载、GitHub Stars 达 61, 最近一次更新时间为 2015 年 02 月 11 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 distilleries/form-builder 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 distilleries/form-builder 我们能提供哪些服务?
定制开发 / 二次开发

基于 distilleries/form-builder 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 20.21k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 63
  • 点击次数: 0
  • 依赖项目数: 3
  • 推荐数: 0

GitHub 信息

  • Stars: 61
  • Watchers: 6
  • Forks: 23
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2015-02-11