dariotilgner/liform
Serialize Symfony Forms into JSON Schema for documentation, validation, and client-side form generation. Works with generators like liform-react or json-editor, and powers LiformBundle. Use as a standalone library to keep backend and frontend forms in sync.
Installation
composer require dariotilgner/liform
Add to composer.json if not auto-loaded:
"autoload": {
"psr-4": {
"App\\": "app/",
"DarioTilgner\\Liform\\": "vendor/dariotilgner/liform/src/"
}
}
Run composer dump-autoload.
First Use Case Convert a Symfony Form to JSON Schema in a Laravel controller:
use DarioTilgner\Liform\Liform;
use Symfony\Component\Form\FormInterface;
public function getSchema(FormInterface $form)
{
$liform = new Liform();
$schema = $liform->transform($form);
return response()->json($schema);
}
Key Files
src/Liform.php: Core transformer class.src/Type/: Type-specific schema generators (e.g., TextType.php).Define Symfony Form
$builder = $this->createFormBuilder($data);
$builder->add('name', TextType::class);
$builder->add('email', EmailType::class);
$form = $builder->getForm();
Transform to JSON Schema
$liform = new Liform();
$schema = $liform->transform($form);
// $schema = [
// "type": "object",
// "properties": {
// "name": {"type": "string"},
// "email": {"type": "string", "format": "email"}
// }
// ]
Integrate with API Responses
return response()->json([
'schema' => $schema,
'form_data' => $form->getData()
]);
FormFactory to generate forms dynamically and transform them on-the-fly.@Assert\Length) to JSON Schema keywords (minLength, maxLength).
$builder->add('bio', TextType::class, [
'constraints' => [new Length(['min' => 10])]
]);
CollectionType or FormType for nested objects/arrays.
$builder->add('addresses', CollectionType::class, [
'entry_type' => AddressType::class,
'allow_add' => true
]);
validator()->make($data, $schema).vee-validate or formik) for dynamic rendering.Unsupported Types
src/Type/ for coverage.Liform or create custom type handlers (see below).Constraint Mismaps
@Assert\Callback) won’t translate to JSON Schema.$liform->setLogger(new \Monolog\Logger('liform'));
Circular References
User ↔ Profile) may cause infinite loops.$liform->setMaxDepth(5) to limit recursion.Default Values
data option may not always map to JSON Schema’s default.$builder->add('status', ChoiceType::class, [
'choices' => ['active', 'inactive'],
'default' => 'active'
]);
$liform->setDebug(true); // Logs unsupported types/constraints
$transformer = $liform->getTransformer();
$transformer->setDebug(true);
Custom Type Handlers
Create a new type class (e.g., CustomType.php) extending AbstractType:
namespace App\Liform\Type;
use DarioTilgner\Liform\Type\AbstractType;
class CustomType extends AbstractType {
public function getSchema() {
return ['type' => 'string', 'custom' => true];
}
}
Register it in Liform:
$liform->addType('custom', CustomType::class);
Override Default Behavior
Replace the default Transformer:
$liform->setTransformer(new \App\CustomTransformer());
Post-Processing Modify the schema after transformation:
$schema = $liform->transform($form);
$schema['additionalProperties'] = false; // Enforce strict schema
draft-07. Override with:
$liform->setSchemaVersion('draft-06');
CollectionType maps to array. Force object for keyed collections:
$builder->add('items', CollectionType::class, [
'entry_type' => ItemType::class,
'by_reference' => false,
'allow_add' => true
]);
$liform->setArrayAsObject(true);
$cacheKey = 'form_schema_'.$form->getName();
$schema = Cache::remember($cacheKey, 60, function() use ($form) {
return $liform->transform($form);
});
How can I help you explore Laravel packages today?