/**
  * Get document fields
  *
  * @param Document $document Document
  * @return array
  */
 private function getFormFields(Document $document)
 {
     $reflection = new \ReflectionClass($document->getClass());
     if ($reflection->implementsInterface('Graviton\\I18nBundle\\Document\\TranslatableDocumentInterface')) {
         $instance = $reflection->newInstanceWithoutConstructor();
         $translatableFields = $instance->getTranslatableFields();
     } else {
         $translatableFields = [];
     }
     $result = [];
     foreach ($document->getFields() as $field) {
         if ($field instanceof Field) {
             list($type, $options) = $this->resolveFieldParams($translatableFields, $field->getFieldName(), $field->getType());
             $result[] = [$field->getFormName(), $type, array_replace(['property_path' => $field->getFieldName()], $options)];
         } elseif ($field instanceof ArrayField) {
             list($type, $options) = $this->resolveFieldParams($translatableFields, $field->getFieldName(), $field->getItemType());
             $result[] = [$field->getFormName(), 'collection', ['property_path' => $field->getFieldName(), 'type' => $type, 'options' => $options]];
         } elseif ($field instanceof EmbedOne) {
             $result[] = [$field->getFormName(), 'form', ['property_path' => $field->getFieldName(), 'data_class' => $field->getDocument()->getClass(), 'required' => $field->isRequired()]];
         } elseif ($field instanceof EmbedMany) {
             $result[] = [$field->getFormName(), 'collection', ['property_path' => $field->getFieldName(), 'type' => 'form', 'options' => ['data_class' => $field->getDocument()->getClass()]]];
         }
     }
     return $result;
 }
 /**
  * Get field names
  *
  * @param Document $document Document
  * @return array
  */
 private function getFieldNames(Document $document)
 {
     $result = [];
     foreach ($document->getFields() as $field) {
         $result[$field->getFieldName()] = $field->getExposedName();
     }
     return $result;
 }
 /**
  * Get document fields
  *
  * @param Document $document Document
  * @param string   $prefix   Field prefix
  * @return array
  */
 private function getFormDataMap(Document $document, $prefix = '')
 {
     $result = [];
     foreach ($document->getFields() as $field) {
         if ($field instanceof EmbedOne) {
             $result = array_merge($result, $this->getFormDataMap($field->getDocument(), $prefix . $field->getExposedName() . '.'));
         } elseif ($field instanceof EmbedMany) {
             $result = array_merge($result, $this->getFormDataMap($field->getDocument(), $prefix . $field->getExposedName() . '.0.'));
         }
         if ($field->getExposedName() !== $field->getFormName()) {
             $result[$prefix . $field->getExposedName()] = $field->getFormName();
         }
     }
     return $result;
 }
 /**
  * Get document fields
  *
  * @param Document $document Document
  * @param string   $prefix   Field prefix
  * @return array
  */
 private function getTranslatableFields(Document $document, $prefix = '')
 {
     $reflection = new \ReflectionClass($document->getClass());
     if ($reflection->implementsInterface('Graviton\\I18nBundle\\Document\\TranslatableDocumentInterface')) {
         $instance = $reflection->newInstanceWithoutConstructor();
         $translatableFields = $instance->getTranslatableFields();
     } else {
         $translatableFields = [];
     }
     $result = [];
     foreach ($document->getFields() as $field) {
         if ($field instanceof Field) {
             if (in_array($field->getFieldName(), $translatableFields, true)) {
                 $result[] = $prefix . $field->getExposedName();
             }
         } elseif ($field instanceof EmbedOne) {
             $result = array_merge($result, $this->getTranslatableFields($field->getDocument(), $prefix . $field->getExposedName() . '.'));
         } elseif ($field instanceof EmbedMany) {
             $result = array_merge($result, $this->getTranslatableFields($field->getDocument(), $prefix . $field->getExposedName() . '.0.'));
         }
     }
     return $result;
 }
 /**
  * Recursive doctrine document processing
  *
  * @param Document $document      Document
  * @param string   $exposedPrefix Exposed field prefix
  * @return array
  */
 private function processDocument(Document $document, $exposedPrefix = '')
 {
     $result = [];
     foreach ($document->getFields() as $field) {
         if ($field instanceof Field) {
             if ($field->getType() === 'extref') {
                 $result[] = $exposedPrefix . $field->getExposedName();
             }
         } elseif ($field instanceof ArrayField) {
             if ($field->getItemType() === 'extref') {
                 $result[] = $exposedPrefix . $field->getExposedName() . '.0';
             }
         } elseif ($field instanceof EmbedOne) {
             $result = array_merge($result, $this->processDocument($field->getDocument(), $exposedPrefix . $field->getExposedName() . '.'));
         } elseif ($field instanceof EmbedMany) {
             $result = array_merge($result, $this->processDocument($field->getDocument(), $exposedPrefix . $field->getExposedName() . '.0.'));
         }
     }
     return $result;
 }