Getting Started
- Confirm your app is a Laravel Enso application first. This package is tightly coupled to Enso’s backend conventions and Vue form renderer; it is not a standalone generic Laravel form package.
- Install with Composer:
composer require laravel-enso/forms
- Let Enso/package discovery register the service provider. If your Enso version requires publishing config/assets, follow the package README for that version, then clear caches:
php artisan config:clear
php artisan cache:clear
namespace App\Forms;
use LaravelEnso\Forms\App\Services\Form;
class PostForm extends Form
{
protected function template(): array
{
return [
'fields' => [
'title' => [
'label' => 'Title',
'type' => 'input',
'validation' => 'required|max:255',
],
'body' => [
'label' => 'Body',
'type' => 'textarea',
'validation' => 'required',
],
],
];
}
}
- Return the form from the Enso controller action used by the frontend, typically for
create and edit:
public function create(Post $post)
{
return ['form' => new PostForm($post)];
}
- Render it with the Enso form component on the Vue side. The backend form class produces the JSON contract; the Enso frontend renders fields, validation hints, buttons, and layout.
Implementation Patterns
- One form class per resource/action. Use
PostForm for the resource, then create variants such as PostCreateForm/PostEditForm only when the field set, permissions, or layout genuinely differs.
- Reuse field fragments. Keep common fields in protected methods or a small base form class and merge them into
template():
protected function template(): array
{
return [
'fields' => array_merge($this->commonFields(), [
'published_at' => [
'label' => 'Published at',
'type' => 'date',
'validation' => 'nullable|date',
],
]),
];
}
- Keep the form as the UI contract, not the source of truth for security. Field definitions drive rendering and client-side validation hints. Always enforce authorization and validation server-side with policies, FormRequests, or controller validation.
- Mirror validation rules. Keep form field
validation rules aligned with backend request rules so the UI and API agree. Treat frontend validation as UX only.
- Populate from the model deliberately. Pass the model into the form for edit screens, but whitelist what is exposed. Avoid dumping full model attributes into options or hidden fields.
- Use Enso-friendly field types. Standard inputs, textarea, select, date, checkbox, and file/upload types should match what the Enso frontend renderer supports. For selects, provide stable option values and labels.
- Load relationship data efficiently. If select options come from related models, eager-load or query only needed columns. Avoid building large option lists inline for big tables; use remote search/select endpoints where Enso supports them.
- Control field visibility with authorization. Hide or disable fields for users who cannot edit them, and enforce the same rule in the controller. Do not rely on a hidden field being absent.
- Integrate with Enso tables and actions. A resource usually has an Enso table, a form class, CRUD controller actions, and frontend routes. Keep field names consistent across table columns, form fields, request validation, and model fillable attributes.
- Use custom field types only end-to-end. If you add a custom field builder/type on the backend, confirm the Vue renderer knows that type. Otherwise the JSON will be valid but the frontend may render nothing or fall back incorrectly.
- Prefer extension by subclassing/overriding. Extend the package
Form class, override template(), add protected helper methods, and keep vendor files untouched.
Gotchas and Tips
- Enso coupling is the biggest gotcha. If you are not using Laravel Enso, this package will not give you a complete standalone form solution. You would need to reproduce the frontend contract and rendering layer.
- Pin compatible versions. Laravel, PHP, Enso core, and frontend package versions must align. Upgrade Enso and forms together, then smoke-test create/edit forms.
- Field names are a contract. Renaming a field key can break edit forms, validation, request mapping, table columns, and frontend payloads. Treat form field keys as API-level identifiers.
- Clear caches after config changes. Enso/Laravel config caching can make form configuration changes appear ignored. Run
php artisan config:clear and relevant cache clears when debugging.
- Do not trust client-side validation. The generated form JSON may include validation metadata, but users can bypass it. Enforce rules in FormRequests/controllers and authorize every action.
- Watch null/empty normalization. Selects, dates, checkboxes, and nullable fields often differ between
null, '', 0, and false. Normalize before saving and be explicit in validation rules.
- Avoid N+1 queries in form options. Building a form that loads relationship options per field can silently explode query counts. Eager-load or cache stable option lists.
- Hide sensitive fields explicitly. Do not assume the form only shows what the model has. Audit form classes for IDs, tokens, internal flags, and relationship data.
- Debug the generated payload directly. Inspect the form’s array/JSON representation from a controller or tinker session, e.g.
dd((new PostForm($post))->toArray()) or the equivalent serialization method for your version. Also inspect the network response in the browser.
- Check the frontend renderer when a field is missing. If the backend JSON contains the field but the UI does not, the issue is usually an unsupported
type, malformed options, or a frontend component that does not handle that field configuration.
- Use extension points, not vendor edits. Subclass the form service, override template methods, add app-level base form classes, and use supported config/field registration. Vendor changes are lost on Composer update.