elasticms/form-bundle
Generate dynamic forms from ElasticMS content configuration. This bundle builds forms out of your content types, keeping field definitions and structure in sync with your ElasticMS content model while rendering them in your Symfony application. Part of the elasticMS mono repository.
Accept the prerequisite first. This bundle is a thin Symfony layer over elasticMS content-type definitions. Nothing renders until you have a reachable elasticMS instance with at least one content type containing real fields (text, choice, date, file…). If you don't have that, stop here — there is no "hello world" form to demo, and no fixtures in the package.
Where to look, in order:
ems-project.github.io/#/dev/form-bundle/index.md. This is the only prose that exists; the README is a stub.vendor/ after install — specifically the DI extension (DependencyInjection/*Extension.php) and the class that maps an elasticMS field type to a Symfony form type. That mapping is the whole package; read it before writing any code, because it is the documentation.Installation reality check. There is no Laravel service provider and no php artisan vendor:publish flow. Two viable paths:
symfony/form, symfony/validator, symfony/twig-bridge, symfony/translation) and manually assemble the form factory + validator rather than booting the bundle. Verify the published package name and branch in the monorepo metadata first — this repo is marked [READONLY], and releases ship on parallel 6.9.x and 7.x lines that map to different Symfony versions.First use case to prove out: a single marketing/contact form whose fields live in one elasticMS content type. Fetch the definition, build the form, render it, POST it, validate it, and index the resulting document back into elasticMS. That end-to-end loop exercises every moving part (definitions, mapping, validation, persistence) and takes an afternoon.
Definition → form type. The central pattern is a single reusable form type that takes a content type name (or raw definition) and recursively adds children. Don't generate PHP form classes per form — that defeats the point. Typical flow:
$definition = $this->emsClient->getContentType('contact'); // cache this
$form = $this->forms->create(ContentTypeFormType::class, null, [
'content_type' => $definition,
]);
Controller shape. GET builds and renders; POST binds request data, calls $form->isValid(), and on success transforms $form->getData() into an elasticMS document payload before indexing. Keep the transform in a dedicated class — you will reuse it for pre-filling edit forms.
Render as a schema, not as Twig. Symfony's FormView is designed for Twig form themes. In a Laravel/Blade or Inertia frontend, the higher-leverage pattern is to serialize the form view (name, type, label, choices, constraints, errors) to JSON in one place and render it with your own Blade/Vue components. One adapter, all forms — and it keeps Symfony's Twig dependency out of your runtime.
Validation dual-track. Map elasticMS constraints to Symfony Constraint objects (the bundle already does part of this). If your controllers are Laravel-native, either run the Symfony Validator on the bound data and mirror the rules as Laravel Rule objects, or — cleaner — validate once with Symfony and translate violations into Laravel's ValidationException so $errors and @error behave normally.
Cache definitions aggressively. Content-type definitions change rarely and API round-trips per page render are the main latency risk. Wrap the client call in Cache::remember() keyed by content type name + a checksum/version, with a short TTL (5–15 min) plus a manual bust on publish.
Multi-tenant / A/B variant pattern. Resolve the content type name from tenant, locale, or experiment bucket (contact_{tenant}_{locale}) at request time and pass it into the form type options. This is the package's strongest use case: no per-tenant PHP branches, and marketing can ship variants without a deploy.
Testing. Fake the client behind an interface returning a fixture JSON definition. Golden-file test the schema serializer — that's where field-mapping regressions surface, not in the form itself.
VerifyCsrfToken middleware will both try to own the token. Pick one — usually disable the Symfony token in the form options and let Laravel's middleware handle it, or exempt the route.messages/validators domains), not Laravel's lang/. Labels from elasticMS are usually pre-translated; constraint messages are not. Normalize both to one source before shipping.6.9.x and 7.x are maintained in parallel. Pin deliberately and check the Symfony version constraint in composer.json — a mismatch produces confusing DI errors rather than a clean composer conflict.FormView name tree. Nearly every "field is missing" bug is either a definition cache hit on stale data or a mapping branch that silently skipped the field.[READONLY]; issues and PRs go to ems-project/elasticms. With one star and zero dependents, there is effectively no community Q&A — expect to read source, and price that into the estimate.How can I help you explore Laravel packages today?