javascript - entitytype - symfony form collection bundle
Colisión del índice ArrayCollection(Colección de formularios) en Symfony 2 (3)
Estoy usando Symfony2 para construir mi página. Cuando intento actualizar una colección de formularios (como se describe en la entrada del libro de cocina " Cómo incrustar una colección de formularios "), obtengo una colisión de los índices del frontend y los índices de la colección Array en el backend.
Tengo la relación de Usuario <-> Dirección (OneToMany). Un usuario desea crear / actualizar / eliminar sus direcciones, por lo tanto, puede agregar / eliminar en la interfaz con la ayuda de los elementos de direcciones nuevas de la parte javascript. Él hace lo siguiente:
(1) Agrega nueva dirección (tiene índice: 0)
(2) Agrega una nueva dirección (tiene índice: 1) y la vuelve a eliminar instantáneamente
(3) Agrega una nueva dirección (tiene índice: 2).
Cuando hace clic en el botón Guardar, el siguiente código guarda / actualiza al usuario (y sus direcciones):
$this->em->persist($user);
$this->em->flush();
Las nuevas direcciones, por ejemplo, se conservan correctamente en la base de datos. Ahora el usuario desea actualizar la dirección, por ejemplo, con el índice 0. Cuando ahora hace clic en el botón Guardar, actualiza la dirección con "índice 0", pero al mismo tiempo, agrega de nuevo la dirección con "índice 2" a la base de datos (objeto). Para comprender mejor el problema, dibujé una pequeña ilustración (hecha a mano, perdón por mis malas habilidades artísticas):
Ahora, tengo dos veces la dirección con "índice 1" en mi objeto / base de datos. Sé por qué sucede esto, es porque la primera dirección del "índice 1" se asigna al elemento "número 1" de ArrayCollection, y la segunda se asigna al "número 2" (debido al nombre de frontend "índice 2"). Puede decir: "solo llena las direcciones, hasta que alcanza el índice de frontend en el backend" ... ¿Pero cómo puedo corregir este comportamiento?
Nota del sitio: este comportamiento se produce al usar solicitudes ajax, porque si vuelve a cargar la página después de hacer clic en el botón "Guardar", se reindexarán las direcciones en el frontend correctamente con los índices en el backend.
Mi sugerencia para manejar esa situación:
Volver a indexar los índices frontales después de hacer clic en guardar con los índices del lado del servidor. ¿Es esta una solución clara / única para mi problema?
He solucionado este problema en el lado del cliente modificando el código Javascript / Jquery que figura en la documentación de Symfony.
En lugar de numerar los nuevos elementos contando los subelementos, estoy mirando la identificación del último elemento y extrayendo su índice con una expresión regular.
Al agregar un elemento, estoy incrementando el último índice en 1. De esa manera, nunca uso el mismo índice.
Aquí está mi código:
// Initializing default index at 0
var index = 0;
// Looking for collection fields in the form
var $findinput = $container.find('':input'');
// If fields found then looking for last existing index
if ( $findinput.length > 0 ) {
// Reading id of last field
var myString = $findinput.last().attr(''id'')
// Setting regular expression to extract number from id containing letters, hyphens and underscores
var myRegex = /^[-_A-Za-z]+([0-9]+)[-_A-Za-z]*$/
// Executing regular expression on last collection field id
var test = myRegex.exec(myString);
// Extracting last index and incrementing by 1
if (test.length > 0) index = parseInt(test[1]) + 1;
}
Me encontré con este problema un par de veces durante los últimos dos años. Por lo general, seguir el tutorial de Symfony Cómo incrustar una colección de formularios hace bien el trabajo. Necesita agregar un poco de codificación javascript para agregar la funcionalidad "editar / actualizar", pero aparte de eso, debería estar bien usando este enfoque.
Si, por otro lado, tiene una forma realmente compleja que utiliza AJAX
para validar / guardar / calcular / lógica empresarial / etc, he encontrado que generalmente es mejor almacenar los datos finales en una matriz en la sesión. Después de enviar el formulario, dentro del bloque if($form->isValid()){...}
, tendría
$collection = new ArrayCollection($mySessionPlainArray);
$user->setAddress($collection);
Me gustaría advertirle que tenga cuidado con la serialización de sus datos; es posible que obtenga algunas excepciones incómodas o mal comportamiento si está utilizando entidades (consulte mi question ).
Lo siento, no puedo proporcionar más código, pero la solución a este problema a veces es bastante compleja.
Sí, este es un problema de la colección de formularios de Symfony y no tiene una solución fácil imho. Pero tengo que preguntar, ¿por qué no haces exactamente lo mismo que hace la actualización de la página? Puede actualizar solo el fragmento de código html con la colección. El código HTML para el fragmento puede provenir del lado del servidor. Volviendo a su pregunta, sí, reindexar es una buena solución hasta que no desee intentar escribir un tipo de colección personalizada por su cuenta.
Hay un problema similar con la validación en la colección - symfony/symfony/issues/7468 .
Bueno, creo que el tipo de colección predeterminado y el tutorial en los documentos de Symfony tienen algunos inconvenientes. Espero que sea de ayuda.