/**
  * Creates the translation for object being flushed
  *
  * @param TranslatableAdapter $ea
  * @param object $object
  * @param boolean $isInsert
  * @throws UnexpectedValueException - if locale is not valid, or
  *      primary key is composite, missing or invalid
  * @return void
  */
 private function handleTranslatableObjectUpdate(TranslatableAdapter $ea, $object, $isInsert)
 {
     $om = $ea->getObjectManager();
     $wrapped = AbstractWrapper::wrap($object, $om);
     $meta = $wrapped->getMetadata();
     $config = $this->getConfiguration($om, $meta->name);
     // no need cache, metadata is loaded only once in MetadataFactoryClass
     $translationClass = $this->getTranslationClass($ea, $config['useObjectClass']);
     $translationMetadata = $om->getClassMetadata($translationClass);
     // check for the availability of the primary key
     $objectId = $wrapped->getIdentifier();
     // load the currently used locale
     $locale = $this->getTranslatableLocale($object, $meta);
     $uow = $om->getUnitOfWork();
     $oid = spl_object_hash($object);
     $changeSet = $ea->getObjectChangeSet($uow, $object);
     $translatableFields = $config['fields'];
     foreach ($translatableFields as $field) {
         $wasPersistedSeparetely = false;
         $skip = isset($this->translatedInLocale[$oid]) && $locale === $this->translatedInLocale[$oid];
         $skip = $skip && !isset($changeSet[$field]);
         if ($skip) {
             continue;
             // locale is same and nothing changed
         }
         $translation = null;
         foreach ($ea->getScheduledObjectInsertions($uow) as $trans) {
             if ($locale !== $this->defaultLocale && get_class($trans) === $translationClass && $trans->getLocale() === $this->defaultLocale && $trans->getObject() === $object) {
                 $this->setTranslationInDefaultLocale($oid, $trans);
                 break;
             }
         }
         // lookup persisted translations
         if ($ea->usesPersonalTranslation($translationClass)) {
             foreach ($ea->getScheduledObjectInsertions($uow) as $trans) {
                 $wasPersistedSeparetely = get_class($trans) === $translationClass && $trans->getLocale() === $locale && $trans->getField() === $field && $trans->getObject() === $object;
                 if ($wasPersistedSeparetely) {
                     $translation = $trans;
                     break;
                 }
             }
         }
         // check if translation allready is created
         if (!$isInsert && !$translation) {
             $translation = $ea->findTranslation($wrapped, $locale, $field, $translationClass, $config['useObjectClass']);
         }
         // create new translation if translation not already created and locale is differentent from default locale, otherwise, we have the date in the original record
         $persistNewTranslation = !$translation && ($locale !== $this->defaultLocale || $this->persistDefaultLocaleTranslation);
         if ($persistNewTranslation) {
             $translation = $translationMetadata->newInstance();
             $translation->setLocale($locale);
             $translation->setField($field);
             if ($ea->usesPersonalTranslation($translationClass)) {
                 $translation->setObject($object);
             } else {
                 $translation->setObjectClass($config['useObjectClass']);
                 $translation->setForeignKey($objectId);
             }
         }
         if ($translation) {
             // set the translated field, take value using reflection
             $value = $wrapped->getPropertyValue($field);
             $content = $ea->getTranslationValue($object, $field);
             $translation->setContent($content);
             // check if need to update in database
             $transWrapper = AbstractWrapper::wrap($translation, $om);
             if (!empty($content) && ($isInsert || !$transWrapper->getIdentifier() || isset($changeSet[$field]))) {
                 if ($isInsert && !$objectId && !$ea->usesPersonalTranslation($translationClass)) {
                     // if we do not have the primary key yet available
                     // keep this translation in memory to insert it later with foreign key
                     $this->pendingTranslationInserts[spl_object_hash($object)][] = $translation;
                 } else {
                     // persist and compute change set for translation
                     if ($wasPersistedSeparetely) {
                         $ea->recomputeSingleObjectChangeset($uow, $translationMetadata, $translation);
                     } else {
                         $om->persist($translation);
                         $uow->computeChangeSet($translationMetadata, $translation);
                     }
                 }
             }
         }
         if ($isInsert && $this->getTranslationInDefaultLocale($oid) !== null) {
             // We can't rely on object field value which is created in non default locale.
             // If we provide translation for default locale as well, the latter is considered to be trusted
             // and object content should be overridden.
             $wrapped->setPropertyValue($field, $this->getTranslationInDefaultLocale($oid)->getContent());
             $ea->recomputeSingleObjectChangeset($uow, $meta, $object);
             $this->removeTranslationInDefaultLocale($oid);
         }
     }
     $this->translatedInLocale[$oid] = $locale;
     // check if we have default translation and need to reset the translation
     if (!$isInsert && strlen($this->defaultLocale)) {
         $this->validateLocale($this->defaultLocale);
         $modifiedChangeSet = $changeSet;
         foreach ($changeSet as $field => $changes) {
             if (in_array($field, $translatableFields)) {
                 if ($locale !== $this->defaultLocale) {
                     $ea->setOriginalObjectProperty($uow, $oid, $field, $changes[0]);
                     unset($modifiedChangeSet[$field]);
                 }
             }
         }
         $ea->recomputeSingleObjectChangeset($uow, $meta, $object);
         // cleanup current changeset only if working in a another locale different than de default one, otherwise the changeset will always be reverted
         if ($locale !== $this->defaultLocale) {
             $ea->clearObjectChangeSet($uow, $oid);
             // recompute changeset only if there are changes other than reverted translations
             if ($modifiedChangeSet) {
                 foreach ($modifiedChangeSet as $field => $changes) {
                     $ea->setOriginalObjectProperty($uow, $oid, $field, $changes[0]);
                 }
                 $ea->recomputeSingleObjectChangeset($uow, $meta, $object);
             }
         }
     }
 }
 /**
  * Checks if the translation entity belongs to the object in question
  *
  * @param TranslatableAdapter $ea
  * @param object              $trans
  * @param object              $object
  *
  * @return boolean
  */
 private function belongsToObject(TranslatableAdapter $ea, $trans, $object)
 {
     if ($ea->usesPersonalTranslation(get_class($trans))) {
         return $trans->getObject() === $object;
     }
     return $trans->getForeignKey() === $object->getId() && $trans->getObjectClass() === get_class($object);
 }
 /**
  * Creates all additional translations created
  * through repository
  *
  * @param TranslatableAdapter $ea
  * @param object $object
  * @param boolean $inserting
  * @return void
  */
 private function processAdditionalTranslations(TranslatableAdapter $ea, $object, $inserting)
 {
     $oid = spl_object_hash($object);
     if (isset($this->additionalTranslations[$oid])) {
         $om = $ea->getObjectManager();
         $uow = $om->getUnitOfWork();
         $meta = $om->getClassMetadata(get_class($object));
         $objectId = $ea->extractIdentifier($om, $object);
         $transClass = $this->getTranslationClass($ea, $meta->name);
         foreach ($this->additionalTranslations[$oid] as $field => $translations) {
             foreach ($translations as $locale => $content) {
                 $trans = null;
                 if (!$inserting) {
                     $trans = $ea->findTranslation($objectId, $meta->name, $locale, $field, $transClass);
                 }
                 if (!$trans) {
                     $trans = new $transClass();
                     $trans->setField($field);
                     $trans->setObjectClass($meta->name);
                     $trans->setForeignKey($objectId);
                     $trans->setLocale($locale);
                 }
                 $trans->setContent($ea->getTranslationValue($object, $field, $content));
                 if ($inserting && !$objectId) {
                     $this->pendingTranslationInserts[spl_object_hash($object)][] = $trans;
                 } elseif ($trans->getId()) {
                     $om->persist($trans);
                     $transMeta = $om->getClassMetadata($transClass);
                     $uow->computeChangeSet($transMeta, $trans);
                 } else {
                     $ea->insertTranslationRecord($trans);
                 }
             }
         }
     }
 }