Заполнение свойств из Embedded другого документа

На днях столкнулись с коллегой с одним занимательным багом. По какой-то причине не заполняся Embedded документ в Doctrine ODM. При всём при этом, когда мы его дампили, то он исправно показывался, а вот до самой MongoDB так и не доходил.

Проблема

Суть баги можно выразить вот таким псевдокодом.

После этого при дампе объекта $b в нём в свойстве someEmbeddedOneField лежит наш Embedded документ, а вот при сохранении – ничего не сохраняется.

Причина проблемы

После долгих ночных изысканий выяснилось, что проблема кроется в том, что доктрина при сохранении документов проходится по их дереву, от родителя к потомкам (Embedded). Когда она добирается до нашего Embedded документа, то получает ссылку на Embedded из объекта a. А ведь он то в базе сохранён и пересохранять его не надо. Поэтому нет запроса. В PHP объекты передаются по ссылке, вот и получается, что у нас в объекте b в поле someEmbeddedOneField стоит ссылка на Embedeed объекта а.

Возможные решения

Костыль

Это было моё первое решение, но оно мне не очень понравилось, поэтому я начал искать дальше.

С ним всё работает, однако он сбрасывает статусы для ВСЕХ экземпляров этого класса в течении HTTP-запроса. Т.е. потенциальное поле для багов. Поэтому и стал копать дальше.

Решение получше

Делаем новый объект, и передаём туда значения.

Решение ещё лучше

Просто клонируем объект, полученный из другого документа.

А теперь, правильное решение

У предыдушего варианта есть один недостаток. Он клонирует все объекты не разбирая, новые они (клонирование в этом случчае не нужно) или уже есть в БД (клонирование нужно). Поэтому надо узнавать, а сохранён ли объект в БД, т.е. является ли он managed в терминологии Doctrine. Это можно сделать так:

А в мутатор добавить вызов этой функции.

Да, функцию getEmbeddedForSetter лучше убрать в ваш сервисный слой.

Ссылки

EntityState (это про ORM на самом деле, но прочитать стоит)

2 Comments

  1. Спасибо огромное, очень помогли. Долго не мог понять, почему не сохраняются Embedded документы. Теперь все стало намного понятнее.

    1. Рад помочь, сам с этими граблями долго просидел)

Leave a Comment