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

Sulu Form Bundle Laravel Package

sulu/sulu-form-bundle

SuluFormBundle adds dynamic form creation to the Sulu admin UI, letting content managers build forms for contact, sweepstake, or other use cases, position fields in a grid, and configure emails to visitors or themselves. Built on Symfony Form, compatible with Sulu 2.0+.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install and register the bundle

composer require sulu/form-bundle

The bundle requires Sulu >= 2.0. Register Sulu\Bundle\FormBundle\SuluFormBundle in config/bundles.php (Sulu apps list bundles explicitly) and import the bundle routing under a prefix so the form submit endpoint exists:

# config/routes/sulu_form.yaml
sulu_form:
    resource: "@SuluFormBundle/Resources/config/routing.xml"
    prefix: /forms

2. Minimal configuration + schema

At minimum set the mail fallbacks (forms no longer require sender/receiver per form since 2.0, so these are the safety net):

# config/packages/sulu_form.yaml
sulu_form:
    mail_from: "%env(SULU_ADMIN_EMAIL)%"
    mail_to: "%env(SULU_ADMIN_EMAIL)%"

Forms, translations and submitted form data are Doctrine entities — create the tables with your normal Sulu setup (bin/console sulu:build dev / doctrine:schema:update --force, or a migration in prod). The full config tree (mail templates, ajax templates, recaptcha, honeypot, form data) lives in DependencyInjection/Configuration.php; the human-readable version is Resources/doc/configuration.md.

3. Where to look first

  • Resources/doc/index.md → installation.md, then the dynamic-form and mailer chapters.
  • DependencyInjection/Configuration.php — the only reliable source of truth for option names in your installed version.
  • UPGRADE.md before any version bump (2.0 renamed services, removed magic getters, changed event names).

4. First use case: a contact form

In the admin, open Forms, create a form with a technical key (e.g. contact) — this key, not the numeric id, is what templates and code reference. Add fields (text, email, textarea), then place the Form content type on a page template and render it. Submitted data is written to the form-data table and appears in the admin form-data list; the notify mail goes to the form's sendTo, the confirm mail to the visitor.

Implementation Patterns

Render through the content type (content-manager driven). The Form content type stores the form key; the bundle's website controller builds the Symfony form, handles the POST and sends mails. This is the right default: content managers change fields without a deploy.

Custom controller when you need behaviour. For landing pages or AJAX you build/handle the Symfony form yourself with the bundle services (sulu_form.builder and sulu_form.handler — confirm exact ids in Resources/config/services.xml):

$form = $this->formBuilder->build('contact', $request->getLocale(), ['data' => $prefill]);
if ($this->formHandler->handle($form, $request)) {
    return $this->redirectToRoute('app_contact_success'); // PRG, avoid double submit
}
return $this->render('contact.html.twig', ['form' => $form->createView()]);

Inject the services via constructor (2.0 moved controllers to DI — don't use $this->get() in new code).

Hook into the lifecycle instead of forking the bundle. Listen to the save events to push submissions into a CRM, newsletter tool or custom table. Note the 2.0 rename: sulu_form.handler.saved became sulu_form.handler.save (with a post-save event); grep your listeners when upgrading. This is the cleanest extension point for side effects — keep the bundle's persistence untouched.

Static form types for developer-owned forms. Define a Symfony form type in your app, reference its service id/FQCN in the form configuration, and content managers still get the admin UI around it. The FormGeneratorCommand (see bin/console list sulu:form) can scaffold a type from a dynamic form definition — handy for "freeze" migrations where marketing wants a fixed layout.

Mail templates. Forms carry subject/recipient/template settings; the bundle renders them with Twig (Symfony form theming under the hood). Override the mail template per form for branding, or globally in sulu_form for a consistent house style. Verify the variable set exposed to the template (form data, locale) against Resources/views/ before assuming.

Field types and anti-spam. honeypot and recaptcha are ordinary field types — they only protect a form if added to its definition. Recaptcha needs keys and per-field constraints; honeypot should be hidden via CSS, not display:none on a wrapper a bot can detect. Mailchimp "list select" exists for newsletter signups (added in 2.0) and requires its own config.

Multi-locale. Forms are localized entities. Create a form in each locale (or copy the key) — a form existing only in de will not fall back silently on an en page. Always pass the request locale into the builder.

Testing. In test env, disable the mailer transport (null://) and POST to the submit route with KernelBrowser, then assert on the form-data table rather than on the mail, which is the flakiest assertion.

Gotchas and Tips

  • Field order and caching. Field ordering has historically been reset on save and forms are cached (a caching fix landed in 2.1). If edits don't appear, clear the cache and re-check the saved order in the admin before debugging templates.
  • Silent non-sending. Since 2.0 sender/receiver emails are optional per form — a form without sendTo and no fallback mail_to will happily save and store data but send nothing. Always configure the global mail_from / mail_to and check the mailer log, not just the form config.
  • Dynamic getters/setters removed. 2.0 dropped magic setter/getter on the dynamic form entity; code doing $form->getTitle() or similar breaks. Use explicit translation accessors.
  • Schema drift after upgrades. 2.1 upgraded Doctrine packages; re-run schema/migrations after every minor bump or form saving fails on a missing column. Attachments are stored as Sulu media — there is a flag to deactivate attachment saving, which you want on high-traffic forms to stop media growth.
  • Controller reference syntax. 2.0 changed how controllers are referenced in templates/content types. Copy the reference from the current docs rather than from an old project, or submissions 404 while the page renders fine.
  • No CSV export in core. The admin list for form data exists, but bulk CSV export has been an open request for a long time — plan a small custom command/controller if the client asks for it.
  • Small ecosystem (86 stars, ~0 dependents). Expect to read the source; there are no wrapper packages. Pin the minor version, watch UPGRADE.md, and keep custom code in listeners/form types rather than patching bundle templates so upgrades stay cheap.
  • Debug toolkit. bin/console debug:container sulu_form --show-private to find the real service ids, debug:event-dispatcher to confirm your listener is wired to sulu_form.handler.save, and the Symfony profiler's mail panel for rendered mails.
  • Recaptcha constraints are configured per field and were buggy in 2.0 — if validation never fires, check the constraint is attached to the field definition, not just the recaptcha key config.
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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core
nodisrupt/laravel-agent
sierratecnologia/media-manager