Pregunta Colisión de índice ArrayCollection (Colección de formularios) en Symfony 2


Estoy usando Symfony2 para construir mi página. Cuando trato de 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 de la interfaz y los índices de ArrayCollection en el back-end.

Tengo la relación Usuario <-> Dirección (OneToMany). Un usuario quiere crear / actualizar / eliminar sus direcciones, por lo tanto, puede agregar / eliminar en la interfaz con la ayuda de los elementos de la nueva dirección javascript. Él hace lo siguiente:

(1) Agrega nueva dirección (tiene índice: 0)

(2) Agrega una nueva dirección (tiene índice: 1) y elimina de inmediato esta dirección nuevamente

(3) Agrega 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();

Por ejemplo, las direcciones nuevas se conservan correctamente en la base de datos. Ahora el usuario quiere actualizar la dirección, p. con índice 0. Cuando ahora hace clic en el botón Guardar, actualiza la dirección con "índice 0", pero al mismo tiempo, agrega nuevamente la dirección con "índice 2" a la base de datos (objeto). Para comprender mejor el problema, he dibujado una pequeña ilustración (hecho a mano, perdón por mis malas habilidades artísticas):

Collection error image Ahora, tengo dos veces la dirección con "índice 1" dentro de mi objeto / base de datos. Sé por qué sucede esto, es porque la primera dirección "índice 1" se asigna al elemento "número 1" de ArrayCollection, y la segunda se asigna al "número 2" (debido al nombre de la interfaz "índice 2"). Puedes decir: "simplemente llena las direcciones, hasta que llega al índice de frontend en el back-end" ... Pero, ¿cómo puedo solucionar este comportamiento?

Nota del sitio: Este comportamiento se produce mediante el uso de solicitudes ajax, ya que si volviera a cargar la página después de hacer clic en "Guardar botón", reindexaría correctamente las direcciones en la interfaz con los índices en el back-end.

Mi sugerencia para manejar esa situación:

Reindexar los índices frontend después de hacer clic en guardar con el lado del servidor índices ¿Es esta una solución clara / única para mi problema?


18
2018-06-27 16:21


origen


Respuestas:


Sí, este es un problema de la colección de formularios de Symfony y no tiene una solución fácil. 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 html con la colección. El código HTML para el fragmento puede provenir del lado del servidor. De vuelta a su pregunta, sí, reindexar es una buena solución hasta que no desee probar escribir un tipo de colección personalizado.

symfony / symfony / issues / 7828

Hay un problema similar con la validación en la colección - symfony / symfony / issues / 7468.

Bueno, creo que el tipo de recopilación predeterminado y el tutorial en documentos de Symfony tienen algunos inconvenientes. Espero que sea de ayuda.


7
2017-07-02 10:03



Me encontré con este problema un par de veces durante los últimos dos años. Por lo general, siguiendo el tutorial de Symfony Cómo incrustar una colección de formularios hace bien el trabajo Necesitas hacer un poco de codificación de JavaScript para agregar la funcionalidad de "editar / actualizar", pero aparte de eso, deberías estar bien usando este enfoque.

Si, por otro lado, tiene una forma realmente compleja que utiliza AJAX para validar / guardar / cálculo / lógica comercial / 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 if($form->isValid()){...} bloquear, tendrías

$collection = new ArrayCollection($mySessionPlainArray);
$user->setAddress($collection);

me gustaría advertir debe tener cuidado con la serialización de sus datos; es posible que obtenga algunas excepciones incómodas o una mala conducta si está usando entidades (consulte mi pregunta)

Lamento no poder proporcionar más código, pero la solución a este problema a veces es bastante compleja.


1
2017-07-08 21:39



He abordado este tema desde el lado del cliente modificando el código JavaScript / Jquery que se proporciona en la Documentación de Symfony.

En lugar de numerar los elementos nuevos 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;
}

1
2018-03-03 22:01