Validación de una colección de formularios incrustados en Symfony 4.3
La opción de incrustar una colección de formularios en otro es útil para implementar interfaces ricas y bien estructuradas. Sin embargo, la documentación no toca todos los detalles que se debe considerar, en particular lo relativo a la validación de los datos.
Vamos a asumir que ya leíste los documentos oficiales, y por lo tanto has implementado todo esto:
- Una entidad "cabecera" y otra "detalle", relacionadas 1 a N, con sus respectivas reglas de validación.
- Clases de formulario (type) para cada una, con la segunda incrustada mediante una colección (CollectionType) en la primera.
- Plantillas twig y el código JS necesario para agregar y eliminar elementos de la colección.
- Un controlador que coordina las operaciones.
Teniendo en cuenta que todo esto puede haberte tomado bastante trabajo, encontrarás bastante decepcionante que las validaciones asociadas a la entidad "detalle" no sean ejecutadas. Sin importar cuánto te hayas esmerado en escribir las reglas, ellas serán ignoradas porque a la documentación le falta mencionar unos cuantos detalles.
La cascada que ya no va
En primer lugar, debes indicar explícitamente que deseas ejecutar las reglas de validación de la entidad "detalle". Hasta Symfony 3, ello se conseguía mediante la opción cascade_validation
; en la actualidad, debes declarar una constraint Valid()
en las opciones de la colección. La declaración debería incluir lo siguiente:
use Symfony\Component\Form\Extension\Core\Type as Core; use Symfony\Component\Validator\Constraints as Assert; [...] ->add('xxx', Core\CollectionType::class, [ [...] 'constraints' => [ new Assert\Valid(), new Assert\Count([ 'min' => 1 ]), ], [...]
Adicionalmente, si la colección debe satisfacer otras condiciones, como un número mínimo o máximo de elementos, puedes aprovechar de incluir la constraint Count()
u otras.
¿Y dónde está el error?
Aunque el código de validación ahora esté ejecutándose, es posible que los errores no aparezcan en el formulario. Puedes confirmar que este sea el caso al observar que:
- El formulario no se procesa (porque
->isValid()
r - etorna false).
- No se muestra errores al usuario.
- Los errores efectivamente aparecen en el web debug toolbar.
La solución es agregar las llamadas a form_errors()
que pueda faltar en la plantilla; tanto la asociada al formulario "cabecera", como la correspondiente al "detalle". Esto último es particulamente relevante si has personalizado el despliegue del segundo. ✦