Intereting Posts
DOM Parser для выделения ключевых слов, не работающих Входные массивы HTML Simpletest browser (php) на сайте asp, который не позволяет напрямую связывать Динамические поля / свойства в Doctrine2 – как? Как настроить собственный заголовок REQUEST в PHP Загрузка данных из URL с помощью NSData В чем разница между self :: $ bar и static :: $ bar в PHP? Ошибка PHP Parse: синтаксическая ошибка, неожиданный T_ENCAPSED_AND_WHITESPACE, ожидающий T_STRING или T_VARIABLE или T_NUM_STRING обмениваться сеансом между классическим ASP и PHP, чем использовать базу данных Неустранимая ошибка: использование $ this, если не в контексте контекста объяснения? как получить результаты в реальном времени с помощью jquery? Разделить строку на переменные PHP PHP mysqli_real_escape_string возвращает пустую строку Проверка формы отправки – PHP $ .ajax используется для объединения ввода из предыдущих полей формы на странице – некоторые проблемы

Как заставить Doctrine обновить поля типа массива?

У меня есть объект Doctrine с полем типа массива:

/** * @ORM\Table() */ class MyEntity { (...) /** * @var array $items * * @ORM\Column( type="array" ) */ private $items; /** * @param SomeItem $item */ public function addItem(SomeItem $item) { $this->items[] = $item; } (...) } 

Если я добавлю элемент в массив, этот код работает правильно:

 $myEntityObject->addItems(new SomeItem()); $EntityManager->persist($myEntityObject); $EntityManager->flush(); 

$myEntityObject сохраняется в базе данных с правильными данными (массив сериализуется и десериализуется при запросе базы данных).

К сожалению, когда я изменяю один из объектов внутри массива без изменения размера этого массива, Doctrine ничего не делает, если я пытаюсь сохранить изменения в базе данных.

 $items = $myEntityObject->getItems(); $items[0]->setSomething(123); $myEntityObject->setItems($items); $EntityManager->persist($myEntityObject); $EntityManager->flush(); print_r($myEntityObject); 

Хотя, print_r в последней строке этого кода отображает данные измененного объекта, Doctrine не знает, что что-то было изменено внутри массива, если размер массива не изменился. Есть ли способ заставить Doctrine сохранять изменения, внесенные в эту область (или нежно сообщать об изменениях в этом поле, которые необходимо сохранить)?

Doctrine использует идентичный оператор (===) для сравнения изменений между старыми и новыми значениями. Оператор, используемый на одном объекте (или массиве объектов) с разными данными, всегда возвращает true. Есть другой способ решить эту проблему, вы можете клонировать объект, который необходимо изменить.

 $items = $myEntityObject->getItems(); $items[0] = clone $items[0]; $items[0]->setSomething(123); $myEntityObject->setItems($items); // ... 

Или измените метод setItems() (нам нужно клонировать только один объект, чтобы сохранить весь массив)

 public function setItems(array $items) { if (!empty($items) && $items === $this->items) { reset($items); $items[key($items)] = clone current($items); } $this->items = $items; } 

Что касается второго вопроса:

Кто-нибудь знает, как сохранить политику отслеживания по умолчанию для других полей и использовать NotifyPropertyChanged только для поля, в котором хранится массив?

Вы не можете установить политику отслеживания только для одного поля.

Просто нашел в документации способ решить мою проблему:

http://docs.doctrine-project.org/en/latest/reference/change-tracking-policies.html

Это требует большого количества изменений в коде, но оно работает. Кто-нибудь знает, как сохранить политику отслеживания по умолчанию для других полей и использовать NotifyPropertyChanged только для поля, в котором хранится массив?

Способ, которым я исправил это в своем коде, состоял в том, чтобы использовать createQueryBuilder и просто создать запрос на обновление. Таким образом, доктрина никак не может сказать ничего 🙂

Поэтому я пошел от этого

 $em = $this->getDoctrine()->getManager(); $matchEntity = $em->getReference('MyBundleBundle:Match', $match_id); $matchEntity->setElement($element); $matchEntity->setTeamHomeColour($data['team_a_colour']); $matchEntity->setTeamAwayColour($data['team_b_colour']); 

К этому:

 $repository = $this->getDoctrine()->getRepository('MyBundleBundle:Match'); $query = $repository->createQueryBuilder('u') ->update() ->set('u.element', ':element') ->set('u.teamHomeColour', ':thomecolour') ->set('u.teamAwayColour', ':tawaycolour') ->where('u.matchId = :match') ->setParameter('element', $element) ->setParameter('thomecolour', $data['team_a_colour']) ->setParameter('tawaycolour', $data['team_b_colour']) ->setParameter('match', $matchEntity) ->getQuery(); $query->execute(); 

Его еще несколько строк кода, но нет клонирования или какой-либо другой магии. Просто скажите доктрине прямо, чтобы сделать проклятое обновление! Надеюсь это поможет.

Примечание. В моей ситуации это был элемент $, который не был установлен. Я отключил все совпадения в предыдущем запросе, и доктрина просто не увидела его и поэтому отказалась обновить элемент.