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.
- Installation
- Basic usage
- Type of form
- Form
- FormView
- FormValidator 1. Use the validation client side 2. Use the validation server side 3. Check the rules on your controller
- List of fields
- Input
- Choice 1. Select 2. Radio 3. Checkbox 4. Ajax
- Tag
- Upload
- TinyMce
- Textarea
- Button
- Address Picker
- Form
- Controller
- 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" /> |
<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:
Render not editable:
###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:
Render not editable:
###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:
###5 TinyMce If you want use a rich content editor you can use tinymce.
$this->add('description', 'tinymce', [
'label' => _('Description')
]);
Render editable:
Render not editable:
###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:
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:
Render not editable:
###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:
Render not editable:
##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