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

Form Bundle Laravel Package

akyos/form-bundle

Configurable contact forms for Symfony (Contact Form 7 style): dynamic fields, submissions, export and Twig rendering. Depends on CoreBundle and CmsBundle. Requires PHP 8.4+ and Symfony 8.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check before you start: this is a Symfony bundle, not a Laravel package. There is no service provider, no facade, no config/form.php. If your day-to-day is Laravel, you will not drop this into a Laravel app — Laravel's Request, FormRequest, validation, and Blade have no mapping to what this bundle ships. You leverage it when you're working in (or migrating to) a Symfony 8 / PHP 8.4 codebase, or when you need a reference implementation of Contact Form 7-style forms.

Minimal steps

  1. Confirm the runtime: PHP >= 8.4 and Symfony ^8.0. Symfony 8 hard-requires PHP 8.4, so the "PHP 8.2+" note in some docs is stale.
  2. Install the bundle plus its hard Akyos dependencies — it will not boot without them:
    composer require akyos/form-bundle:^8.0
    
    You need akyos/core-bundle ^8.0 and akyos/cms-bundle ^8.0 present and enabled first.
  3. Register bundles in config/bundles.php (Core, Cms, then Form), in that order.
  4. Publish/verify config and mailer transport. Emails are the default side effect, so config/packages/mailer.yaml must point at something real before your first test.
  5. First use case: render the shipped contact form in a Twig template and post it from a controller. Use the bundle's form type, handleRequest(), redirect on valid submit.

Where to look first

  • The bundle's form types (the base "contact" type) — this is your extension surface.
  • The submission entity/repository and its export routine — this is the part that replaces your usual ContactMessage::create() + Mail::to() flow.
  • The Twig rendering helpers, since the README sells "rendu Twig prêt à l'emploi."
  • The admin builder controllers only if you're touching admin UI — see the 8.0.3 note below.

Skip it if you need Laravel-native forms. In Laravel, the equivalent day-to-day job (dynamic fields + stored submissions + export + email + anti-spam) is a migration, a model, a FormRequest, a Mailable, and a Blade partial — roughly a day of work, with full control and no Symfony coupling.

Implementation Patterns

Treat it as a configurable form engine, not a form builder. The value proposition is "define fields, get submissions stored, exported, and rendered." So the pattern that pays off is: define field sets once, reuse them across contexts, and keep your own business logic in listeners rather than in the form type.

Pattern 1 — Wrap the shipped form type instead of editing it. Subclass or set it as getParent(), then add your fields. This survives bundle upgrades, which matters because the package is at 0 stars and moving fast (patch releases changing request handling is a signal).

class EnquiryType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder->add('phone', TextType::class, ['required' => false]);
    }

    public function getParent(): string
    {
        return ContactType::class; // bundle type
    }
}

Register it as a form.type. Do not copy the vendor file into your app.

Pattern 2 — Controller as a thin adapter. Laravel devs reach for a FormRequest; here the form type is the validation layer. Keep the controller to three lines of intent: create, handle, redirect. Never fall through to rendering on success — the bundle does not redirect for you, and a refresh will resubmit.

Pattern 3 — Submissions are the integration point. Everything you'd do in a Laravel store() method — persist, notify Slack, fire a webhook, hit a CRM — belongs in an event listener on the bundle's submit event, not in the controller. This is the single most important habit for a Laravel dev: your controller stops being the orchestrator, and the event becomes it. It also means one listener covers the admin form, the public form, and any programmatic submission.

Pattern 4 — Override by convention, not by forking. Email templates and translations resolve from the bundle and can be shadowed by putting a same-named file in your app's templates/ or translations/. Copy the vendor file to the matching path in your project and edit there. Same idea for swapping the mailer: bind your own implementation to the bundle's mailer interface in services.yaml. This is the Symfony analogue of binding an interface in a Laravel service provider — reach for it before you patch vendor code.

Pattern 5 — Config-driven spam protection. reCAPTCHA v3 is wired through the Karser bundle. Enable and key it in the bundle config, then make sure the reCAPTCHA script is actually on the page in your base template. Config alone is not enough — a missing script tag yields a silent validation failure that looks like a server bug.

Pattern 6 — Export as an ops workflow. The export feature is for the person who owns the inbox, not the developer. Wire it into an admin route with proper access control from day one; it dumps personal data. If you're in the EU, that route is a GDPR surface, so log who exports what.

Pattern 7 — If you must touch admin builder code, use request bags. Any custom controller, decorator, or listener you write that reads request input must use $request->query->get(...) / $request->request->get(...). Request::get() was removed in Symfony 8. If you're porting Laravel muscle memory, $request->input('x') becomes $request->request->get('x') for POST and $request->query->get('x') for GET — and you must pick the right bag.

Gotchas and Tips

Version floor is a hard gate, and the docs disagree with themselves. README says PHP >= 8.4 / Symfony ^8.0; one assessment says PHP 8.2+. Trust the README and the composer constraint. On Symfony 8 you are on 8.4 regardless, so pin ^8.0.3 explicitly rather than ^8.0.

8.0.3 is not optional if you use admin builder editing. Symfony 8 removed Request::get(), which threw UndefinedMethodError when editing builder components. If admin editing breaks with that error, it's the version, not your code — bump to ^8.0.3. Audit your own code for ->get( on the request too; the bundle fix doesn't fix your controllers.

Zero stars, zero dependents, one maintainer-ish vendor. No community to lean on, and dependency churn is real (the 8.0.3 patch proves it). Mitigations: pin exact versions in composer.json, commit composer.lock, and avoid subclassing or reflecting into internals. Vendor-patch only as a last resort, with a note to revisit.

Three-bundle dependency chain is your first failure mode. Core → Cms → Form, in that order. A missing or version-mismatched cms-bundle produces confusing container errors rather than a clean "missing dependency" message. If the container won't compile, check the chain before you debug your own config.

Silent form failures usually mean reCAPTCHA, mailer, or CSRF — in that order.

  • reCAPTCHA: verify both keys and that the script tag renders. The Karser dependency is pulled at @dev stability in some references — treat that as a supply-chain risk and check what you actually resolved in the lock file.
  • Mailer: test against Mailtrap or a local SMTP before blaming the bundle. "Submissions save but no email arrives" is a transport problem ~90% of the time.
  • CSRF: don't hand-roll tokens around form_start()/form_end(). Use the helpers and let them do it.

Submissions persist but email fails silently. Design for this: your event listener should be the durable path (store first, then attempt notification), and you should monitor for submissions without a corresponding send. This bundle won't queue or retry for you.

No redirects, no queueing, no metrics. Three things a Laravel dev assumes come for free. Redirect explicitly on success. If volume grows, the synchronous mail send inside the request becomes your latency and timeout source — move notification into a Symfony Messenger handler rather than waiting for the bundle to grow one.

Debugging workflow that actually works

  • APP_DEBUG=true, then use the profiler at /_profiler: the Forms panel tells you whether validation failed and on which field, and the Events panel tells you whether your submit listener fired. This is the equivalent of Laravel Telescope and it answers most "why didn't it work" questions faster than logging.
  • dump($request->query->all(), $request->request->all()) when a value is unexpectedly null — confirms which bag holds it.
  • Temporarily dump() inside your submit listener to confirm the submitted payload shape before you write mapping logic against it. The docs are thin enough that the payload shape is empirical, not documented.

Laravel-dev translation table, to stop the reflexive wrong turn

Laravel habit Here
FormRequest for validation Rules live in the form type's field options
$request->input('x') $request->request->get('x') (POST) / $request->query->get('x') (GET)
Controller store() does everything Event listener does everything
Mail::to()->send() in controller Bundle mailer + overridable template
config/form.php config/packages/*.yaml, container parameters
Publish vendor views Copy same-named file into templates/
Service provider binding services.yaml interface→implementation

Extension points to prefer, ranked

  1. Config (recaptcha, mailer, templates) — cheapest, upgrade-safe.
  2. Subclassing the form type — safe.
  3. Template and translation shadowing — safe.
  4. Swapping the mailer implementation via interface binding — safe.
  5. Event listeners for persistence/integration — safe and the right home for business logic.
  6. Decorating admin controllers — last resort; most exposed to Symfony internals churn.

The honest verdict for a Laravel developer: treat this as a Symfony-only tool and as a pattern reference for building a CF7-style form system elsewhere. Its architecture — declarative fields, stored submissions, export, event-driven side effects — is a sound blueprint you can reproduce in Laravel with migrations, a FormRequest, a Mailable, and a FormSubmitted event, and you'd get better docs, active maintenance, and no three-bundle chain for the effort.

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.
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus