metalogico / laravel-formello
A Laravel package for generating Bootstrap 5 forms based on models
Requires
- php: ^8.0
- laravel/framework: ^9.0|^10.0|^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^10.4
- pestphp/pest: ^3.8
- pestphp/pest-plugin-laravel: ^3.2
README
Formello
A Laravel package for generating Bootstrap 5 forms based on models. Laravel 9+
Formello is a comprehensive form generation and handling tool for Laravel applications, inspired by Django forms.
🎉 Motivation
The Laravel ecosystem offers powerful tools for building applications, from full-featured admin panels like Nova and Filament to complex form-handling libraries. However, I felt there was a need for a tool that sits in the "sweet spot" between these solutions.
Formello was created for developers who need to generate forms quickly without the overhead of a complete admin panel, but who also want a simpler, more intuitive API than more complex form libraries. It's designed to automate the repetitive aspects of form creation while giving you full control over the final output.
Currently, Formello ships with built-in support for Bootstrap 5, and support for Tailwind CSS is coming soon™!
If you use this project, please consider giving it a ⭐.
✨ Features
- Easy form definition using Laravel classes
- Automatic form rendering
- Support for various field types:
- Text
- Textarea
- Select (with multiple)
- Select2
- Radio
- Checkboxes
- Toggle
- Range
- Date
- DateTime
- Upload
- Hidden
- Customizable widgets
- Automatic error handling and display
- Form validation integration
🛠️ How to install
- Install the package via Composer:
composer require metalogico/laravel-formello
- Publish the assets:
php artisan vendor:publish --tag=formello-assets
- (Optional) Auto-publish assets on update
To ensure that Formello's assets are automatically updated every time you run composer update
, you can add a command to the post-update-cmd
script in your project's composer.json
file.
"scripts": { "post-update-cmd": [ "@php artisan vendor:publish --tag=formello-assets --force" ] }
This will overwrite the existing assets with the latest ones from the package.
😎 How to use
Creating a Form
Create a new form class that extends Metalogico\Formello\Formello
.
Here's a simple example for a product form.
<?php namespace App\Forms; use Metalogico\Formello\Formello; use Metalogico\Formello\Widgets\SelectWidget; class ProductForm extends Formello { protected function create(): array { return [ 'method' => 'POST', 'action' => route('products.store'), ]; } protected function edit(): array { return [ 'method' => 'POST', 'action' => route('products.update', $this->model->id), ]; } protected function fields(): array { return [ 'name' => [ 'label' => __('Product Name'), 'help' => 'Enter the name of the product', ], 'description' => [ 'label' => __('Description'), ], 'category_id' => [ 'label' => __('Category'), 'widget' => 'select', 'choices' => Category::pluck('name', 'id')->toArray(); ], 'in_stock' => [ 'label' => __('In Stock'), ], ]; } }
Remember to add these fields to your model's $fillable
array otherwise Formello will not render them.
class Product extends Model { // ... protected $fillable = [ 'name', 'category_id', 'description', 'in_stock', ]; }
Using the provided artisan command
You can generate a basic formello file using this command:
php artisan make:formello --model=Product
The script will generate a skeleton file that contains a basic field definition for each fillable field found in your model.
Rendering the Form
In your controller for an empty form (create action):
public function create() { // create the form $formello = new ProductForm(Product::class); // pass it to the view return view('products.create', [ 'formello' => $formello ]); }
or, for an edit form:
public function edit(Product $product) { // pass the model to the form $formello = new ProductForm($product); // pass it to the view return view('products.edit', [ 'formello' => $formello ]); }
Then in you blade template:
{!! $formello->render() !!}
If you want to render only the fields (without the <form> tag) you can use:
@foreach ($formello->getFields() as $name => $field) {!! $formello->renderField($name) !!} @endforeach
Conditional Logic
You can use isCreating()
and isEditing()
methods in your form class to dynamically change fields, labels, rules, or other options based on the form's mode.
Here's an example of how to use these methods to change a field's behavior:
protected function fields(): array { $fields = [ 'name' => [ 'label' => __('User Name'), 'help' => 'Enter the name of the user', ], 'password' => [ 'label' => __('Password'), 'type' => 'password', 'required' => $this->isCreating(), 'help' => $this->isEditing() ? 'Leave the field empty to keep the current password' : '', ], ]; return $fields; }
Creating Custom Widgets
Formello is designed to be extensible, allowing you to create your own custom widgets. This is useful when you need a specific form control that isn't included in the default set.
To create a custom widget, you need to follow these steps:
First of all, the config file!
You need to have the config file to add the widget in the Formello list of available widgets.
php artisan vendor:publish --tag=formello-config
In this file you will see a list of all the available widgets.
Add your widget to the list with a name, for example: star-rating
.
1. Create a Widget Class
Then, create a new PHP class for your widget. This class must extend the Metalogico\Formello\Widgets\BaseWidget
class.
You can place this class anywhere in your project, for example, in app/Widgets
.
To maintain a clean separation of concerns, the getViewData
method should return an array of data that will be used to render the widget.
To set the template you can use the getTemplate
method.
Here is an example of a StarRatingWidget
class:
<?php namespace App\Widgets; use Metalogico\Formello\Widgets\BaseWidget; class StarRatingWidget extends BaseWidget { public function getViewData(string $name, $value, array $config, array $errors): array { return [ 'name' => $name, 'value' => $value, 'config' => $config, 'errors' => $errors, ]; } public function getTemplate(): string { return "widgets.star-rating"; } }
2. Create the Widget's Blade Template
Next, create the Blade template that will render the widget's HTML. For instance, you can create the file resources/views/widgets/star-rating.blade.php
:
<div class="mb-3"> <label for="{{ $name }}" class="form-label">{{ $config['label'] }}</label> <input type="number" name="{{ $name }}" id="{{ $name }}" value="{{ $value }}" class="form-control @if ($errors) is-invalid @endif" min="1" max="5"/> @if ($errors) <div class="invalid-feedback"> <ul> @foreach ($errors as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif </div>
3. Use the Custom Widget in Your Form
Once you have created your widget class, you can use it in your Formello form by specifying the fully qualified class name in the widget
option for a field.
<?php namespace App\Forms; use Metalogico\Formello\Formello; class ProductForm extends Formello { // ... create() and edit() methods protected function fields(): array { return [ // ... other fields 'rating' => [ 'label' => __('Product Rating'), 'widget' => 'star-rating', ], ]; } }
Formello will automatically instantiate your widget class and call its render
method to generate the HTML for the form field.
🎨 Asset Management - Modular System
Formello uses a modular and flexible system for loading JavaScript and CSS assets, avoiding conflicts with themes that already include the same libraries.
How It Works
1. Widget-Based Asset Management
Each widget defines its own assets through the getAssets()
method (optional):
public function getAssets(?array $fieldConfig = null): ?array { return [ 'scripts' => ['flatpickr.min.js'], 'styles' => ['flatpickr.min.css'], ]; }
2. Blade Directives
Use the new blade directives in your layout:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Your App</title> <!-- Your existing CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <!-- Formello CSS - loads only what's needed --> @formelloStyles </head> <body> <!-- Your content --> <!-- Your existing JS --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <!-- Formello JS - loads only what's needed --> @formelloScripts </body> </html>
3. Custom Widgets
Custom widgets can optionally implement getAssets()
:
class CustomWidget extends BaseWidget { // The getAssets() method is OPTIONAL public function getAssets(?array $fieldConfig = null): ?array { return [ 'scripts' => ['my-custom-lib.js'], 'styles' => ['my-custom-styles.css'], ]; } // If you don't implement getAssets(), the widget still works }
Supported Libraries
Library | Widgets that use it | Assets loaded |
---|---|---|
select2 |
SelectWidget, Select2Widget | select2.min.js, select2.min.css, select2-bootstrap-5-theme.min.css |
flatpickr |
DateWidget, DateTimeWidget | flatpickr.min.js, l10n/it.js, flatpickr.min.css |
imask |
TextWidget (with mask) | imask.min.js |
pickr |
ColorWidget, ColorSwatchWidget | pickr.min.js, nano.min.css |
jodit |
WysiwygWidget | jodit.min.js, jodit.min.css |
⚖️ License
Laravel Formello is open-sourced software licensed under the MIT license.
🍺 Donations
If you really like this project and you want to help me please consider buying me a beer 🍺