Пару слов про Doctrine 2 Identity Map

cache-iconНу что мои траварищи, эту заметку я пишу после тяжелого трудового дня в поисках одного коварного бага. Было тяжело, но интересно. Я познал, так сказать, прелести внутреннестей и внутренности прелестей Doctrine 2 ODM.Дело было так. Есть страничка, как полагается контроллер, экшен, вид. В виде вызывается несколько блоков. Понадобилось мне получить в контроллере ещё кое какие данные, а именно MongoId одного объекта по его ID из MySQL. В контроллере делаем запрос:

Вроде бы всё просто. Получаем MongoId по SqlId. Однако после этого почему-то падал один из блоков. Не буду вдаваться в подробности, расскажу лишь, что у нас у документа SomeDoc есть параметр slug.

 

Вот с такими аксессорами и мутаторами.

Идея то была хорошаая. Можно вызовом $someDoc->getSlug() получать slug, а если его нет – то автоматически генерить и возвращать. Но это всё в теории… А на практике….

Засада

idMapperSketch

В основном контроллере я получал объект SomeDoc, потом в виде блока делал вызов getSlug() а ещё дальше в коде выполнялось сохранение объекта. А засада состоит в том, что код работает примерно так:

  1. Получаем документ по sqlId. Сохраняем в IdentityMap. Это вроде кэша доктрины для одинаковых сущностей в контексте запроса. При этом, у этого объекта заполнено только поле id. Мы ведь не просили другие 🙂
  2. В виде вызываем getSlug(), хм, ну надо же слага нет, заполняем его пустой строкой.
  3. Сохраняем.
  4. PROFIT! EPIC FAIL!

В разных местах юзается один и тот же объект, а т.к. он уже был загружен ранее – то второй вызов не грузит его. Проверить это можно сохранив первый объектв например в Zend_Registry, и сдампив его второй раз потом.

Решение

Ну понятно, что надо модифицировать вызов getSlug(), чтобы он нам такую вот заподляночку не делал. Я долго копался в Doctrine и сделал так:

Иными словами мы при вызове getSlug() просто догружаем данные из БД в случае, когда документ в состоянии MANAGED (получен из БД, а не инстанцирован в коде) и если он не Embedded. После обновления геттеров и сеттеров не забудьте перегенерить прокси-классы.

Ссылки

Entities and the Identity Map

3 Comments

  1. Используй события, Люк, и да прибудет с тобою сила!

    Костыль начался еще с “$this->slug = strtolower(\Service::translit($slug));” в getSlug(), и явно проявил себя при необходимости заюзать EM в сущности.

Leave a Comment