simplethings/form-serializer-bundle
SimpleThings FormSerializerBundle serializes Symfony forms into JSON, exposing field structure, validation metadata, and options for client-side rendering. It integrates with the Form component to help build dynamic JavaScript forms and API-driven UIs while keeping form definitions in PHP.
composer require simplethings/form-serializer-bundle, then register it (AppKernel or config/bundles.php). Check composer.json first — the bundle dates from the Symfony 2.x era, so confirm it is compatible with your Symfony version and its dependency on the Form component plus whichever serializer/encoder layer you plan to use.Resources/config/services.xml (or DI extension) to confirm the exact service ID and constructor arguments, then the README snippet, then Serializer/FormSerializer.php to see which formats/encoders are supported. Service IDs have drifted between releases, so resolve from the container rather than hardcoding.// GET /products/{id}
$product = $repository->find($id);
$form = $this->createForm(ProductType::class, $product);
$serializer = $this->get('simplethings_form_serializer.form_serializer'); // verify ID
return new JsonResponse($serializer->serialize($form, 'json'));
The write path reuses the same type:
$form = $this->createForm(ProductType::class, new Product());
$data = $serializer->deserialize($form, $request->getContent(), 'json');
$form->submit($data, false); // clearMissing=false for PATCH semantics
if (!$form->isValid()) {
return new JsonResponse(['errors' => (string) $form->getErrors(true)], 400);
}
Start with a type containing two or three scalar fields and one nested form; add a CollectionType only once the basic round-trip works.
createForm(Type::class, $entity)), skip submit() and validation, and serialize. This keeps read serialization free of request semantics.deserialize() produces an array shaped to the form tree; submit() then runs transformers, listeners, and mapping. Treat this as the canonical flow and keep controllers thin.clearMissing explicitly to submit(): true for replacements (missing fields become null), false for partial updates. This is the most common source of “my PATCH wiped fields” bugs.CollectionType maps to JSON arrays/lists. Set allow_add, allow_delete, and by_reference deliberately; they affect both rendering and deserialization.$form->getErrors(true) into the same JSON/XML shape your success responses use, or define a small error form type so clients get structured field errors.['api' => true]) rather than branching in the type.mapped => false, empty_data, and data_class => null behave differently than an ORM-backed normalizer. Audit each type used for API output.getData(), getNormData(), and getViewData() differ after transforms; the bundle typically reads child data post-transform. Inspect FormSerializer when writing custom normalizers.'csrf_protection' => false) and set the method correctly; otherwise submit() fails in confusing ways.PRE_SUBMIT/POST_SUBMIT handlers and FormEvents execute during the deserialize-submit flow — guard against side effects (logs, dispatches, file moves) that were meant only for human submissions.$form->submit()/validation and any manual $validator->validate() call must match, or payloads silently pass or fail.deserialize() before submit(), call $form->getErrors(true, true) for nested errors, and use the profiler's form panel. Verify which Symfony/JMS serializer versions are actually wired, since encoder availability differs by release.How can I help you explore Laravel packages today?