Одновременное управление несколькими сущностями с отношениями OneToMany

Я реализовал транслируемое поведение через отношения сущностей, поэтому у меня есть сущность topic со свойством id с отношением OneToMany к topic_i18n с идентификатором темы, lang_code и содержимым.

Могу ли я установить приватную $locale; свойство объекта topic, чтобы метод объекта __toString() темы отображал содержимое/имя или что-то еще из объекта topic_i18n? Как я мог это сделать?

Еще одно сомнение, которое у меня есть, которое может быть распространено на любой контекст, где происходят отношения OneToMany, заключается в том, что когда я хочу вставить новый объект topic_i18n, мне сначала нужно создать или в настоящее время иметь объект topic, а затем создать объект i18n. У меня нет опыта работы со слоями/менеджерами обслуживания сущностей, но я думаю, что мог бы использовать парадигму, чтобы иметь возможность управлять обеими сущностями как одним, но не знаю, как поступить и правильно ли это. Может ли кто-нибудь дать подсказку, мнение или что-то, основанное на его опыте?

Заранее спасибо!

PD: Я знаю о пакете доктрин поведения, но сейчас это невозможно.


person peris    schedule 02.02.2012    source источник


Ответы (1)


Я думаю, то, как вы это сделали, очень хорошо.

Вы можете добавить/переопределить некоторые методы для получения ваших данных i18n, такие как getTitle($locale) (или get*Whatever*), которые добавляют некоторую логику для поиска подходящего значения в коллекции topic_i18n.

// in your Topic class
public function getTitle()
{
    return $this
        ->getTopicI18nCollection()
        ->findByLocale($this->getLocale()) // actually findByLocale does not exist, you will have to find another way, like iterating over all collection
        ->getTitle()
    ;
}

Проблема с автоматизацией __toString или других заключается в переключении локали или в том, как определить локаль по умолчанию для использования по умолчанию.

Эту проблему можно решить с помощью прослушивателя событий доктрины postLoad, который устанавливает текущую локаль для любого объекта, полученного вашим EntityManager ( http://www.doctrine-project.org/docs/orm/2.1/en/reference/events.html#lifecycle-events), используя запрос или информация о сеансе, например.

Используя symfony2, это может выглядеть так:

# app/config/config.yml
services:
    postload.listener:
        class: Translatable\LocaleInitializer
        arguments: [@session]
        tags:
            - { name: doctrine.event_listener, event: postLoad }


// src/Translatable/LocaleInitalizer.php
class LocaleInitializer
{
    public function __construct(Session $session) 
    {
        $this->session = $session;
    }

    public function postLoad(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();
        if ($entity implements TranslatableInterface) { // or whatever check
            $entity->setLocale($this->session->getLocale());
        }
    }
}

И, наконец, вам не нужно получать объект темы для создания нового объекта topic_i18n, вы можете просто вставить объект i18n независимо друг от друга. (но вам придется обновить ранее извлеченные коллекции).

person Florian Klein    schedule 02.02.2012
comment
Большое спасибо, ваше объяснение - это то, что я искал! Не могли бы вы объяснить, почему findByLocale() не будет существовать? Это связано с тем, что локаль является частной переменной, а не @ORM\column? Еще один вопрос, который у меня есть, заключается в том, чтобы иметь возможность управлять обоими объектами, как один, я должен создать сервисный уровень/менеджер или просто добавить необходимые поля/переменные в сущность темы и зарегистрировать слушателя для события prepersist и там получить переменные от Entity , создать экземпляр объекта Entity_i18n и установить их для него? Я имею в виду, что я хотел бы иметь возможность запускать $t = new Topic();$t->setLocale('es');$t->setContent(foo); и упорствовать - person peris; 03.02.2012