Подтвердить что ты не робот

ArrayCollection (Коллекция форм) столкновение индекса в Symfony 2

Я использую Symfony2 для создания моей страницы. Когда я пытаюсь обновить коллекцию форм (как описано в записи поваренной книги "" Как встроить коллекцию форм"), я получаю столкновение индексов интерфейса и индексов ArrayCollection в бэкэнде.

У меня есть отношение User ↔ Address (OneToMany). Пользователь хочет создать/обновить/удалить свои адреса, поэтому он может добавлять/удалять в интерфейсе с помощью элементов нового адреса javascript. Он делает следующее:

(1) Добавляет новый адрес (имеет индекс: 0)

(2) Добавляет новый адрес (имеет индекс: 1) и мгновенно удаляет этот адрес снова

(3) Добавляет новый адрес (имеет индекс: 2).

Когда он нажимает кнопку сохранения, следующий код сохраняет/обновляет пользователя (и его адреса):

 $this->em->persist($user);
 $this->em->flush();

Новые адреса, например, затем корректно сохраняются в базе данных. Теперь пользователь хочет обновить адрес, например. с индексом 0. Когда он нажимает на кнопку сохранения, он обновляет адрес с помощью "index 0", но в то же время он снова добавляет адрес с "индексом 2" в базу данных (объект). Чтобы лучше понять проблему, я нарисовал небольшую иллюстрацию (ручная работа, извините за мои плохие навыки искусства):

Collection error image Теперь у меня есть два раза адрес с "индексом 1" в моем объекте/базе данных. Я знаю, почему это происходит, потому что первый адрес "index 1" сопоставляется с элементом ArrayCollection "номер 1", а второй отображается на "номер 2" (из-за имени интерфейса "index 2" ). Вы можете сказать: "он просто заполняет адреса, пока не достигнет индекса интерфейса в бэкэнд". Но как я могу исправить это поведение?

Примечание по сайту: Такое поведение возникает с использованием аякс-запросов, потому что если вы перезагрузите страницу после нажатия кнопки "Сохранить", она правильно вернет адреса в интерфейсе с индексами в бэкэнд.

Мое предложение справиться с этой ситуацией:

Повторное индексирование индексов интерфейса после нажатия кнопки "Сохранить" на стороне сервера индексов. Является ли это ясным/единственным решением для моей проблемы?

4b9b3361

Ответ 1

Да, это проблема коллекции форм Symfony, и у нее нет простого решения imho. Но я должен спросить, почему бы вам не сделать то же самое, что делает обновление страницы? Вы можете обновить только фрагмент html с помощью коллекции. HTML-код для фрагмента может быть получен с сервера. Вернемся к вашему вопросу - да, переиндексирование - хорошее решение, пока вы не захотите самостоятельно написать собственный тип коллекций.

symfony/symfony/issues/7828

Аналогичная проблема с проверкой в ​​коллекции - symfony/symfony/issues/7468.

Ну, я думаю, что тип коллекции по умолчанию и учебник в документах Symfony имеют некоторые недостатки. Надеюсь, что поможет.

Ответ 2

Я столкнулся с этой проблемой пару раз за последние два года. Обычно, следуя учебнику Symfony "Как встроить коллекцию форм" , эта работа отлично справляется. Вам нужно немного кодировать javascript, чтобы добавить функциональность "редактировать/обновлять" , но кроме этого - вы должны быть в порядке, используя этот подход.

Если, с другой стороны, у вас действительно сложная форма, которая использует AJAX для проверки/сохранения/вычисления/бизнес-логики/и т.д., я обнаружил, что обычно лучше хранить конечные данные в массиве в сессия. После отправки формы внутри блока if($form->isValid()){...} у вас будет

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

Я хотел бы предупредить о том, что вы будете осторожны с сериализацией своих данных. Вы можете получить некоторые неудобные исключения или неправильное поведение, если вы используете сущности (см. мой question).

Извините, я не могу предоставить больше кода, но решение этой проблемы иногда довольно сложно.

Ответ 3

Я столкнулся с этой проблемой на стороне клиента, изменив код Javascript/JQuery, указанный в документации Symfony.

Вместо нумерации новых элементов путем подсчета подэлементов я просматриваю последний идентификатор элемента и извлекаю его индекс с регулярным выражением.

При добавлении элемента я увеличиваю последний индекс на 1. Таким образом, я никогда не использую тот же индекс.

Вот мой код:

// 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;
}