Doctrine 2 и предзагрузка моделей по связи
В этом посте я расскажу о том, почему могут не грузиться значения свойств модели, полученной через связь в Doctrine 2.
Друг тут пожаловался, что при получении модели по связи один-к-одному у него не грузяся значения свойств. Например, такой код возвращал NULL.
1 2 3 |
$release = $em->getRepository('Model\SomeModel')->find(1); $user = $release->getCreateUserLink(); var_dump($user->nick); |
Свойство описывалось вот так:
1 2 3 4 5 |
/** * @OneToOne(targetEntity="User") * @JoinColumn(name="create_user", referencedColumnName="user_id") */ private $createUserLink; |
Дальше оказалось ещё интересней. При вызове метода toArray() из моего расширения для Doctrine, все свойства возвращались успешно. Начал копать и нашел в мануале такую информацию:
Defines that the annotated instance variable holds a reference that describes a many-to-one relationship between two entities.
Required attributes:
- targetEntity: FQCN of the referenced target entity. Can be the unqualified class name if both classes are in the same namespace. IMPORTANT: No leading backslash!
Optional attributes:
- cascade: Cascade Option
- fetch: One of LAZY or EAGER
- inversedBy – The inversedBy attribute designates the field in the entity that is the inverse side of the relationship
См. пруфлинк Получается, если тип загрузки (fetch) не указан, выполняется ленивая загрузка. Осталось узнать, что её инициирует. Это делает функций __load() из прокси-класса модели.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/** @private */ public function __load() { if (!$this->__isInitialized__ && $this->_entityPersister) { $this->__isInitialized__ = true; if (method_exists($this, "__wakeup")) { // call this after __isInitialized__to avoid infinite recursion // but before loading to emulate what ClassMetadata::newInstance() // provides. $this->__wakeup(); } if ($this->_entityPersister->load($this->_identifier, $this) === null) { throw new \Doctrine\ORM\EntityNotFoundException(); } unset($this->_entityPersister, $this->_identifier); } } |
И ведь верно, до загрузки модели из бд в памяти висит модель-пустышка, у которой значения всех свойств (кроме PK) равны NULL.
Солюшен.
Если вы хотите загрузить модель, то либо указываете в описании связи предзагрузку (что не рекомендуется делать по сообрежениям производительности), либо вызывайте после получения модели функцию __load().
1 2 3 4 |
$release = $em->getRepository('Model\SomeModel')->find(1); $user = $release->getCreateUserLink(); $user->__load(); var_dump($user->nick); |