Giter Site home page Giter Site logo

laravel-form-builder's Introduction

laravel-form-builder

A library for building & rendering forms in Laravel.

We originally developed this library for our internal systems which are based off of Bootstrap 4 and CoreUI. We've tried to not be too opinionated about markup; however the library does generate markup with Bootstrap 4 classes in mind.

If you're not using Bootstrap 4, or are using an older version, you'll need to add compatible CSS classes to handle the styling of components.

This library is in early release and is pending unit tests.

Table of Contents

Installation

composer require balfour/laravel-form-builder

Creating a Form

You can either create your form on the fly by constructing a Form, or you can create a custom class such as CreateUserForm which builds the components in the class constructor.

namespace App\Forms;

use App\Models\Role;
use Balfour\LaravelFormBuilder\Form;
use Balfour\LaravelFormBuilder\Components\Checkboxes;
use Balfour\LaravelFormBuilder\Components\EmailInput;
use Balfour\LaravelFormBuilder\Components\MobileNumberInput;
use Balfour\LaravelFormBuilder\Components\NumberInput;
use Balfour\LaravelFormBuilder\Components\PhoneNumberInput;
use Balfour\LaravelFormBuilder\Components\Row;
use Balfour\LaravelFormBuilder\Components\TextInput;

class CreateUserForm extends Form
{
    public function __construct()
    {
        $this->route('post.create_user')
            ->button('Create')
            ->with([
                TextInput::build()
                    ->name('first_name')
                    ->required(),
                TextInput::build()
                    ->name('last_name')
                    ->required(),
                EmailInput::build()
                    ->required()
                    ->rule('unique:users'),
                Row::build()
                    ->with([
                        MobileNumberInput::build()
                            ->rule('unique:users'),
                        PhoneNumberInput::build()
                            ->name('office_number')
                            ->rule('unique:users'),
                    ]),
                Row::build()
                    ->with([
                        NumberInput::build()
                            ->name('phone_extension')
                            ->rule('unique:users'),
                        TextInput::build()
                            ->name('skype')
                            ->rule('unique:users'),
                    ]),
                Checkboxes::build()
                    ->name('roles')
                    ->options(Role::class)
                    ->setVisibility(auth()->user()->can('assign-role')),
            ]);
    }
}

You can create the form object in your controller and pass it through to your view.

return view('create_user', ['form' => new CreateUserForm()])

In your view, you can then call the render method on the form.

<html>
<head>
    <title>Create User</title>
</head>
<body>
{!! $form->render !!}
</body>
</html>

Filling a Form

The $form->fill() method can be used to set the default values for all form components.

This method can either take an array or key => value pairs, or a model.

As an example, here is an EditUserForm which populates from an existing user model.

namespace App\Forms;

use App\Models\Role;
use App\Models\User;
use Balfour\LaravelFormBuilder\Form;
use Balfour\LaravelFormBuilder\Components\Checkboxes;
use Balfour\LaravelFormBuilder\Components\EmailInput;
use Balfour\LaravelFormBuilder\Components\MobileNumberInput;
use Balfour\LaravelFormBuilder\Components\NumberInput;
use Balfour\LaravelFormBuilder\Components\PhoneNumberInput;
use Balfour\LaravelFormBuilder\Components\Row;
use Balfour\LaravelFormBuilder\Components\TextInput;
use Illuminate\Validation\Rule;

class EditUserForm extends Form
{
    public function __construct(User $user)
    {
        $this->route('post.edit_user', [$user])
            ->button('Save')
            ->with([
                TextInput::build()
                    ->name('first_name')
                    ->required(),
                TextInput::build()
                    ->name('last_name')
                    ->required(),
                EmailInput::build()
                    ->required()
                    ->disabled(),
                Row::build()
                    ->with([
                        MobileNumberInput::build()
                            ->rule(Rule::unique('users')->ignore($user)),
                        PhoneNumberInput::build()
                            ->name('office_number')
                            ->rule(Rule::unique('users')->ignore($user)),
                    ]),
                Row::build()
                    ->with([
                        NumberInput::build()
                            ->name('phone_extension')
                            ->rule(Rule::unique('users')->ignore($user)),
                        TextInput::build()
                            ->name('skype')
                            ->rule(Rule::unique('users')->ignore($user)),
                    ]),
                Checkboxes::build()
                    ->name('roles')
                    ->options(Role::class)
                    ->setVisibility(auth()->user()->can('assign-role'))
                    ->defaults(function () use ($user) {
                        return $user->roles
                            ->pluck('id')
                            ->toArray();
                    }),
                ToggleSwitch::build()
                    ->name('is_two_factor_auth_enforced')
                    ->label('2 Factor Authentication Enforced')
                    ->onLabel('Yes')
                    ->offLabel('No'),
                ToggleSwitch::build()
                    ->name('is_enabled')
                    ->label('Account Enabled')
                    ->onLabel('Yes')
                    ->offLabel('No'),
            ])->fill($user);
    }
}

When we construct the form, we just need to pass in a user model and all components will be populated from the model.

use App\Forms\EditUserForm;
use App\Models\User;

$user = User::find(3);
$form = new EditUserForm($user);

echo $form->render();

Form Validation

The library will automagically generate validation rules for you based on the nested components of the form. The $form->getValidationRules() method can be called to generate the rules.

The validation of the actual form data is left up to you.

Controller Validation

use App\Forms\CreateUserForm;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;

class UserController extends Controller
{
    public function postCreate(Request $request)
    {
        $request->validate((new CreateUserForm())->getValidationRules());
    }
}

Form Request Validation

namespace App\Http\Requests;

use App\Forms\CreateUserForm;
use Illuminate\Foundation\Http\FormRequest;

class CreateUserRequest extends FormRequest
{
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return (new CreateUserForm())->getValidationRules();
    }
}

Components

The following components are bundled into this package:

You can also create your own custom components by implementing ComponentInterface, or FormControlInterface which extends ComponentInterface.

Checkbox (single)

use Balfour\LaravelFormBuilder\Components\Checkbox;

Checkbox::build()
    ->name('remember_me')
    ->label('Remember me for my next visit')
    ->defaults(1);
    
Checkbox::build()
    ->name('agree')
    ->label('I agree to the terms and conditions')
    ->rule('accepted');

Checkboxes (multiple)

use App\Models\Role;
use Balfour\LaravelFormBuilder\Components\Checkboxes;

$user = auth()->user();

// using an array of options
$roles = Role::pluck('name', 'id')
    ->toArray();

Checkboxes::build()
    ->name('roles')
    ->options($roles)
    ->defaults(function () use ($user) {
        return $user->roles
            ->pluck('id')
            ->toArray();
    });

// using a model, or options class
// the class must have a static listify() method which returns an array of key => value pairs
Checkboxes::build()
    ->name('roles')
    ->options(Role::class)
    ->setVisibility(auth()->user()->can('assign-role'))
    ->defaults(function () use ($user) {
        return $user->roles
            ->pluck('id')
            ->toArray();
    });
    
// using a callable to resolve options
Checkboxes::build()
    ->name('roles')
    ->options(function () {
        return Role::pluck('name', 'id')
            ->toArray();
    });

DateInput

use Balfour\LaravelFormBuilder\Components\DateInput;

// if no label is given, it's automagically generated from the component's name
DateInput::build()
    ->name('start_date');
   
// we can add a custom validation rule on top of the automagically generated ones
DateInput::build()
    ->name('start_date')
    ->rule('after:today');

EmailInput

use Balfour\LaravelFormBuilder\Components\EmailInput;

EmailInput::build()
    ->name('email');
    
// here's another custom validation rule on top of the 'email' one
EmailInput::build()
    ->name('email')
    ->rule('unique:users,email');

FieldSet

use Balfour\LaravelFormBuilder\Components\DateInput;
use Balfour\LaravelFormBuilder\Components\FieldSet;

FieldSet::build()
    ->legend('General')
    ->with([
        DateInput::build()
            ->name('start_date')
            ->required(),
        DateInput::build()
            ->name('end_date')
            ->required(),
    ]);

FileInput

use Balfour\LaravelFormBuilder\Components\FileInput;

FileInput::build()
    ->name('photo')
    ->required()
    ->mimes(['image/jpeg'])
    ->maxSize('5120')

HiddenInput

use Balfour\LaravelFormBuilder\Components\HiddenInput;

HiddenInput::build()
    ->name('user_id')
    ->defaults(1);

MobileNumberInput

use Balfour\LaravelFormBuilder\Components\MobileNumberInput;

MobileNumberInput::build()
    ->defaults(auth()->user()->mobile_number);

NumberInput

use Balfour\LaravelFormBuilder\Components\NumberInput;

NumberInput::build()
    ->name('age');

PasswordInput

use Balfour\LaravelFormBuilder\Components\PasswordInput;

PasswordInput::build();

// if you want a custom label...
PasswordInput::build()
    ->name('Your Password');

PhoneNumberInput

use Balfour\LaravelFormBuilder\Components\PhoneNumberInput;

PhoneNumberInput::build()
    ->defaults(auth()->user()->phone_number);

RadioButtonGroup

use Balfour\LaravelFormBuilder\Components\RadioButtonGroup;

RadioButtonGroup::build()
    ->name('food_preference')
    ->options([
        [
            'key' => 'chicken',
            'value' => 'Chicken',
        ],
        [
            'key' => 'beef',
            'value' => 'Beef',
        ],
    ])
    ->defaults('chicken');
    
// you can also add icons
RadioButtonGroup::build()
    ->name('food_preference')
    ->options([
        [
            'key' => 'chicken',
            'value' => 'Chicken',
            'icon' => 'fas fa-egg',
        ],
        [
            'key' => 'beef',
            'value' => 'Beef',
            'icon' => 'fas fa-hamburger',
        ],
    ])
    ->defaults('chicken');

RichTextEditor

use Balfour\LaravelFormBuilder\Components\RichTextEditor;

// this will render a textarea with a 'wysiwyg' class
// it's up to you to instantiate a rich text editor on this element, such as with
// TinyMCE or Froala Editor
RichTextEditor::build()
    ->name('description')
    ->rows(10)
    ->required();

Row

use Balfour\LaravelFormBuilder\Components\DateInput;
use Balfour\LaravelFormBuilder\Components\Row;

Row::build()
    ->with([
        DateInput::build()
            ->name('start_date')
            ->required(),
        DateInput::build()
            ->name('end_date')
            ->required(),
    ]);

Select

use App\Models\Country;
use Balfour\LaravelFormBuilder\Components\Select;

// using an array of options, and include a default 'empty' option
Select::build()
    ->name('country_id')
    ->options([
        1 => 'South Africa',
        2 => 'Amsterdam',
        3 => 'Italy',
    ])
    ->hasEmptyOption();

// using a model, or options class
// the class must have a static listify() method which returns an array of key => value pairs
Select::build()
    ->name('country_id')
    ->options(Country::class)
    ->defaults(1);
    
// using a callable to resolve options
Select::build()
    ->name('country_id')
    ->options(function () {
        return [
            1 => 'South Africa',
            2 => 'Amsterdam',
            3 => 'Italy',
        ];
    });

TextArea

use Balfour\LaravelFormBuilder\Components\TextArea;

TextArea::build()
    ->name('description')
    ->rows(15)
    ->required()
    ->defaults('This is the default description.');

TextInput

use Balfour\LaravelFormBuilder\Components\TextInput;

TextInput::build()
    ->name('first_name')
    ->required()
    ->defaults(auth()->user()->first_name);
    
// you can show a placeholder message
TextInput::build()
    ->name('first_name')
    ->required()
    ->placeholder('Your First Name')
    ->defaults(auth()->user()->first_name);

// you can also customise the type, and add a custom validation rule
TextInput::build()
    ->name('email')
    ->type('email')
    ->required()
    ->defaults(auth()->user()->email)
    ->rule('unique:users,email');

TimePicker

use Balfour\LaravelFormBuilder\Components\TimePicker;

// the component is rendered as an input with a 'time-picker' class
// you'd need to use a timepicker js lib of your choice to render it
TimePicker::build()
    ->name('start_time')
    ->required()
    ->defaults('14:30');

ToggleSwitch

use Balfour\LaravelFormBuilder\Components\ToggleSwitch;

ToggleSwitch::build()
    ->name('two_factor_authentication_enabled')
    ->defaults(true);
    
// use custom on and off labels
ToggleSwitch::build()
    ->name('subscribe')
    ->onLabel('Yes')
    ->offLabel('No')
    ->defaults(true);

laravel-form-builder's People

Contributors

matthewgoslett avatar nicja avatar

Stargazers

 avatar

Watchers

James Cloos avatar  avatar Stuart O'Brien avatar  avatar  avatar Gert avatar Gcobani Poswa avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.