Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Liform Laravel Package

pitch/liform

Liform is a Laravel package for building and rendering forms from reusable, structured definitions. It helps keep fields, validation, and Blade views consistent, making complex forms easier to define, customize, and maintain across Laravel applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Liform turns a form definition into a JSON Schema document. It is built around the Symfony Form component (via symfony/form), so in a Laravel app you either install it standalone with composer require ph-fritsche/liform and build Symfony\Component\Form\FormFactory instances manually, or wrap it in a small service provider. It is not a native Laravel form builder — expect to bridge Form types yourself.

First steps:

  1. Install and sanity-check: composer require ph-fritsche/liform. Confirm the Symfony Form version resolved matches what Liform expects; mismatched majors are the most common first failure.
  2. Look at the converter first: Liform\Resolver and Liform\Transformer\* are where schema is generated. Start there rather than in the docs, which are thin.
  3. First use case: define one AbstractType, build the form with a factory, and run it through the converter to emit a schema array. Serve that array from a controller as application/json so a frontend can validate against it.

A minimal flow:

$factory = Forms::createFormFactory(); // or a container-provided factory
$form = $factory->create(MyResourceType::class, $existingModel);
$schema = (new \Liform\Liform())->transform($form);
return response()->json($schema);

Implementation Patterns

Schema-per-resource endpoint. The most common pattern is one controller action per resource that builds the form and returns the schema. Cache the output keyed by resource name and a version hash, since schema generation walks the whole form tree and is not free.

Reuse the same form type for validation and schema. Define a single AbstractType (or set of types) and use it in two places: the Laravel request/form validation path, and the Liform schema endpoint. This keeps client-side JSON Schema validation and server-side rules from drifting.

DTO/model-backed forms with transformers. If you attach data transformers (e.g. entity-to-id, date strings, money), the schema reflects the underlying field types, not the transformed output. Keep transformers on the model side and document the wire format explicitly, or map the form to a simple DTO so the schema stays honest.

Constraint-to-schema mapping. Symfony validation constraints (NotBlank, Length, Regex, Range) map into schema keywords. Put validation constraints on the Form type rather than in separate Laravel validators if you rely on Liform to produce required, minLength, pattern, etc. Otherwise you get a permissive schema and duplicate rules.

Composition for nested resources. Use CollectionType and nested form types; Liform emits items/properties accordingly. Keep nesting shallow — deep trees produce noisy $ref-less schemas that are hard for a frontend to consume.

Extension points for custom types. For custom field types or constraints, register a transformer (subclass the relevant Liform\Transformer and register it in the resolver) instead of post-processing the schema array. Post-processing is quick but brittle once you have more than two overrides.

Pair with a schema validator. Feed the output into opis/json-schema (PHP) or ajv (JS) in tests to assert the schema is well-formed and that sample payloads validate as expected.

Gotchas and Tips

Unchecked types and values (v1.1.2). v1.1.2 fixes a bug where a value was set for unchecked types. If you are on v1.1.1 or earlier and see default/enum/value noise on checkboxes and radio groups that were never checked, upgrade — this bugfix is the whole reason for the patch. Pin at least ^1.1.2 if your schemas contain checkbox or unchecked choice fields.

Symfony Form dependency creep. Liform assumes Symfony Form semantics: data mappers, empty_data, getData()/getNormData() differences. In Laravel this means you are effectively maintaining two form layers. Keep the Symfony side isolated behind a single service so you can swap or drop it later.

Schema is derived from the form, not your Eloquent model. Column types, casts, and Laravel validation rules are invisible to Liform. Anything not expressed as a Form field or constraint will not appear in the schema. Treat the schema as authoritative only for what you encoded in the form.

Choice fields are a common surprise. ChoiceType with dynamic choices resolves to enum only if the choice loader has run; lazy or entity-backed loaders can produce empty or partial enums. Warm the loader before calling transform(), and cache only after choices are resolved.

Empty vs. missing fields. empty_data and required interact in ways that do not map cleanly to JSON Schema's required and default. Verify how optional fields render — an implicit empty string default can silently appear in default.

Cache invalidation. Cache keys must include the form type, any dynamic choice source, and the package version. A schema cached on v1.1.1 with the unchecked-value bug will stay stale after upgrading unless you bust it.

Debugging: dump $form->all() and each child's getConfig()->getType() before transforming. Most "missing property" or "wrong type" reports are a child type or a not-yet-resolved choice loader, not a Liform bug.

Escaping and formats. Date/datetime fields emit format based on the widget and input config; string fields rarely carry format at all. If clients depend on format, set it explicitly via a transformer rather than relying on defaults.

Extending constraints: custom validators do not automatically produce schema keywords. Either map them through a transformer or accept that they are server-only and document it — otherwise clients will under-validate.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle