ex3v/formerrorsbundle
FormErrorsBundle for Symfony exports all form errors, including field and subform labels, to an array and provides a Twig extension to render them as a customizable list. Avoid boilerplate parsers and display complete validation errors in templates with all_form_errors(form).
Requirements check first. This bundle was written against Symfony 2.3 and is only tested there. Before installing, confirm you are on Symfony 2.x / early 3.x — if you are on Symfony 3.4+ or 4+, the root-form getErrors(true) already returns a flat FormErrorIterator (and form_errors(form) renders deep errors with labels via the form theme), so the bundle adds little beyond legacy support.
Install:
composer require ex3v/formerrorsbundle
Register it in app/AppKernel.php:
new Ex3v\FormErrorsBundle\FormErrorsBundle(),
Where to look first. Open the bundle's Resources/config/services.xml (or .yml) and its *Extension.php class. The README's value proposition is two things, so confirm both exist there: the service definition id and the Twig function name registered by the extension. Those two strings are all you need — the class itself is short and worth a 2-minute read, because it shows exactly how it walks subforms and pulls labels.
First use case. The canonical scenario: a long form fails validation, you redirect back with $form->getErrorsAsString()-style output but no field labels, or you only get the top-level error and lose the per-field ones. Replace the controller boilerplate with one call to the service, hand the array to Twig, and render a single summary block above the form:
// Controller after $form->handleRequest($request) fails isValid()
$errors = $this->get('ex3v.form_errors')->getAllErrors($form); // verify method name in the class
return $this->render('...', ['form' => $form->createView(), 'allErrors' => $errors]);
Then either loop the array yourself or use the bundle's Twig function — grep the extension class for getFunctions() to get the exact name before copying any snippet.
Global error summary at the top of a form. The most common pattern: render once, near {{ form_start(form) }}, a <ul> of every error including nested collections. This gives users a scannable list instead of hunting for red text on each field, and it is what the Twig extension was built for.
Redirect-after-submit with flashes. Instead of returning a 200 render on validation failure, persist the flattened array (or its string form) into the flash bag and redirect. Because the service returns plain strings with labels baked in, this works cleanly across the redirect and survives in any template that dumps app.flashes('error').
JSON API responses. The service exposes errors "to array," so it is a natural fit for an AJAX form endpoint: return new JsonResponse(['errors' => $errors], 422). This is arguably a better use of the bundle than the Twig side, since the array is already keyed/labeled and avoids writing a recursive form-error flattener by hand.
Reusable form-theme block. Wrap the service's output in a Twig block ({% block form_error_summary %}) in your form theme and reference it from every form. This keeps the template contract stable if you later swap the bundle out for native getErrors(true) — you change one block instead of dozens of templates.
Logging / monitoring. On a failed isValid() in a service layer or an event listener, pass the error array to your logger. Because labels are included, log lines are far more useful than Symfony's default error dumping, and you avoid re-implementing the subform walk in every listener.
Integration tip — keep it out of your domain layer. Treat the service as presentation infrastructure: call it at the controller or Twig boundary, not inside validators, entities, or form types. It reads form internals and is version-fragile; isolating it keeps a future Symfony upgrade to a single rip-out point.
Method and service names are undocumented in the excerpt. The README shows installation but not the exact call signature or Twig function name. Don't guess from blog posts — read services.xml and *Extension.php in vendor/ex3v/formerrorsbundle/ first, or you'll burn time on a ServiceNotFoundException.
No autowiring, no modern container support. This is an XML/YAML-configured Symfony 2 bundle with a fixed service id. On Symfony 4+ you'll need the id-based $container->get() (or a manual alias) — and even then the underlying Form::getErrors() API changed, so test before relying on it.
Labels can be missing. Errors attached to unmapped fields, hidden fields, or fields with 'label' => false will render with an empty or auto-generated label in the output. If your summary needs consistent human-readable names, set label explicitly on every field, or post-process the array before rendering.
Bubbled errors appear at the parent. Validation errors bubble up to the form root by default; the bundle's walker may then surface them once at the top level rather than against the offending child. If you see an error in the summary that isn't highlighted on a field, set 'error_bubbling' => false on that field's constraints rather than fighting the bundle.
Translation domain. Messages come from the validator and are already translated when the form is processed, but they use the validators domain. If you render them in an API response consumed by a multi-locale front end, ensure the request locale was set before isValid() was called — translating afterwards won't help.
Don't call it on an unsubmitted form. Like getErrorsAsString(), the service walks errors that only exist post-handleRequest + validation. Guard with $form->isSubmitted() && !$form->isValid() before invoking it.
Debugging. When the output is empty but you know validation failed, dump() the root form's getErrors(true) first to confirm the errors exist, then dump() the bundle's return value to see whether the walker dropped them. That two-step isolates "no errors" from "bundle failed to traverse."
Extension points. The cleanest escape hatch is to skip the Twig extension entirely and iterate the service's array inside your own template or form-theme block — you keep the traversal logic (the genuinely tedious part) while controlling markup. If you need to change which fields are included or how labels are resolved, fork the service class; with 11 stars and 0 dependents, upstream is unlikely to take changes, so pin the version in composer.json and vendor the fork locally if you modify it.
Maturity and support expectations. This is a single-author, README-only, low-traffic package written for a specific Symfony version. The composer.lock-level risk is low, but treat it as a convenience shim, not a foundation: plan for the day you delete it in favor of native getErrors(true) on newer Symfony.
How can I help you explore Laravel packages today?