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 Handler Bundle Laravel Package

runroom-packages/form-handler-bundle

Symfony bundle that streamlines form handling with reusable handler services, typed form objects, and validation wiring so controllers stay thin. Integrates with Symfony Forms and Doctrine to process submissions and keep business logic out of controllers.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with Composer: composer require runroom-packages/form-handler-bundle. If you're on Symfony Flex and a recipe exists, the bundle registers itself; otherwise add Runroom\Packages\FormHandlerBundle\RunroomFormHandlerBundle::class => ['all' => true] to config/bundles.php.
  • Where to look first: open the bundle source itself (vendor/runroom-packages/form-handler-bundle/). The public surface is small — read the FormHandler interface and the abstract base class before anything else, then the service definitions under Resources/config/config. The bundle's real job is to give you a typed object that owns "what happens after $form->isValid()", so the interface is the whole contract.
  • Confirm compatibility: check the composer.json constraints for the PHP and Symfony versions you're running. This is a low-traffic package, so it will not have been tested against every Symfony minor.
  • First use case: take an existing controller action that validates a form and persists an entity in-line, and extract that persist/flash/redirect logic into a handler class implementing the bundle's handler contract. The controller then becomes roughly handleRequest → isSubmitted && isValid → $handler->handle($form).

Implementation Patterns

  • One handler per FormType. Keep the handler as a thin service: inject the EntityManagerInterface (or repositories, mailers, dispatchers), implement the handler method, and let it do only the side effects. The FormType stays a pure description of the form; the handler stays a pure description of the consequences.
  • Create vs. edit handlers. Create a small abstract base holding the shared "bind form data to entity, flush" logic, and two concrete handlers for the new/edit cases. This avoids the usual if ($entity->getId() === null) branching inside one controller.
  • Controller wiring. Type-hint the handler in the action signature and let Symfony's autowiring resolve it. Because handlers are services, this also means you can decorate them — useful for adding logging or transaction wrapping without touching the handler.
  • Transactional safety. Wrap the handler call in $em->wrapInTransaction(...) (or your own beginTransaction/commit with rollback in catch) when the handler performs more than one write. The bundle will not do this for you.
  • API responses. In a JSON/API context, reuse the same handler but skip the redirect — have the handler return the created/updated entity (or a result object) and let the controller shape the response. If the shipped contract returns void, add a thin wrapper service rather than forking the interface.
  • Testing. Handlers are the easiest thing in the codebase to test: instantiate with a mocked entity manager, build a form with $this->createForm(...) in a KernelTestCase, submit valid data, assert flush() was called exactly once and the expected flash/event happened.
  • Integration tip: treat the handler as the seam between the HTTP layer and the domain. If a handler grows past ~50 lines, it's usually a sign that a domain service should be extracted and the handler should only orchestrate validate → call service → flash → redirect.

Gotchas and Tips

  • The repo you linked is a read-only split. Do not open issues or PRs there — the canonical source lives in the Runroom monorepo. If you need to patch something, fork and use a Composer vcs repository entry, or vendor-patch it.
  • Effectively unmaintained in practice. One star and zero dependents means you are the QA team. Read the source end-to-end (it's small) before adopting it; don't assume the README is current. Pin the version explicitly in composer.json and be prepared to own it.
  • Don't double-flush. A very common mistake is to have the handler call $em->flush() and then also flush in the controller (or rely on handleRequest doing so). Pick one place. Same for $em->persist() — persist in the handler, flush once, at the end.
  • Do not put validation in the handler. Validation belongs in the FormType/constraints. The handler should only run after isValid() is true; if you find yourself throwing domain exceptions for user-input problems, the constraint is missing.
  • Exceptions break the form re-render. If the handler throws after a successful validation, the controller's "render the form again" path is already gone. Catch recoverable errors, attach them to the form via a FormError, and re-render; let truly unexpected exceptions bubble to the error handler.
  • Debugging registration. bin/console debug:container --tag=<handler tag> (check the bundle's service definitions for the exact tag) tells you whether your handler was picked up. If it isn't, you probably forgot the interface implementation or the service isn't public/autoconfigured under services.yaml.
  • Debugging behaviour. Because the handler is a service, bin/console debug:container Your\Handler shows the injected arguments — the fastest way to spot a wrong entity manager (e.g. a second connection) or a missing mailer.
  • Config quirks. Any bundle-level configuration is likely minimal (a small Configuration.php). Read it before assuming options exist; do not copy config snippets from blog posts against a different version.
  • Extension points. The intended extension points are (a) implementing the handler contract yourself, (b) decorating the handler service, and (c) subclassing the abstract handler base. Avoid modifying vendor code; the read-only split makes upstreaming fixes awkward, so keep your customisations in your own namespace.
  • Migration cost is low, but plan an exit. Since the abstraction is thin, migrating off it later is mostly a matter of moving the handle() bodies back into command/Domain services. Keep your handlers free of bundle-specific types (other than the interface) so that removal is mechanical.
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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package