/**
  * @param object $object
  * @param array  $config
  * @param int    $level
  *
  * @return array
  *
  * @SuppressWarnings(PHPMD.NPathComplexity)
  * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  */
 protected function normalizeObjectByConfig($object, $config, $level)
 {
     if (!ConfigUtil::isExcludeAll($config)) {
         throw new \RuntimeException(sprintf('The "%s" must be "%s".', ConfigUtil::EXCLUSION_POLICY, ConfigUtil::EXCLUSION_POLICY_ALL));
     }
     if (!array_key_exists(ConfigUtil::FIELDS, $config)) {
         throw new \RuntimeException(sprintf('The "%s" config does not exist.', ConfigUtil::FIELDS));
     }
     $fields = $config[ConfigUtil::FIELDS];
     if (!is_array($fields)) {
         throw new \RuntimeException(sprintf('The "%s" config must be an array.', ConfigUtil::FIELDS));
     }
     $result = [];
     foreach ($fields as $fieldName => $fieldConfig) {
         $value = null;
         if (is_array($fieldConfig)) {
             if (ConfigUtil::isExclude($fieldConfig)) {
                 continue;
             }
             $propertyPath = !empty($fieldConfig[ConfigUtil::PROPERTY_PATH]) ? $fieldConfig[ConfigUtil::PROPERTY_PATH] : $fieldName;
             if ($this->dataAccessor->tryGetValue($object, $propertyPath, $value) && null !== $value) {
                 $childFields = isset($fieldConfig[ConfigUtil::FIELDS]) ? $fieldConfig[ConfigUtil::FIELDS] : null;
                 if (is_string($childFields)) {
                     if ($value instanceof \Traversable) {
                         $childValue = [];
                         foreach ($value as $val) {
                             $childVal = null;
                             $this->dataAccessor->tryGetValue($val, $childFields, $childVal);
                             $childValue[] = $childVal;
                         }
                     } else {
                         $childValue = null;
                         if (!$this->dataAccessor->tryGetValue($value, $childFields, $childValue)) {
                             continue;
                         }
                     }
                     $value = $childValue;
                 } elseif (is_array($childFields)) {
                     $value = $this->normalizeObjectByConfig($value, $fieldConfig, $level + 1);
                 }
             }
         } elseif (!$this->dataAccessor->tryGetValue($object, $fieldName, $value)) {
             continue;
         }
         $result[$fieldName] = $value;
     }
     if (isset($config[ConfigUtil::POST_SERIALIZE])) {
         $result = call_user_func($config[ConfigUtil::POST_SERIALIZE], $result);
     }
     return $result;
 }
 /**
  * @param mixed  $entity
  * @param string $entityClass
  * @param array  $config
  *
  * @return array
  */
 protected function serializeItem($entity, $entityClass, $config)
 {
     if (!$entity) {
         return [];
     }
     $result = [];
     $entityMetadata = $this->doctrineHelper->getEntityMetadata($entityClass);
     $resultFields = $this->getFieldsToSerialize($entityClass, $config);
     foreach ($resultFields as $field) {
         $value = null;
         if ($this->dataAccessor->tryGetValue($entity, $field, $value)) {
             $targetConfig = $this->getFieldConfig($config, $field);
             if ($entityMetadata->isAssociation($field)) {
                 if ($value !== null) {
                     if (!empty($targetConfig['fields'])) {
                         if (is_string($targetConfig['fields'])) {
                             $value = $this->dataAccessor->getValue($value, $targetConfig['fields']);
                             $value = $this->dataTransformer->transform($entityClass, $field, $value, $targetConfig);
                         } else {
                             $value = $this->serializeItem($value, $entityMetadata->getAssociationTargetClass($field), $targetConfig);
                         }
                     } else {
                         $value = $this->dataTransformer->transform($entityClass, $field, $value, $targetConfig);
                     }
                 }
             } else {
                 $value = $this->dataTransformer->transform($entityClass, $field, $value, $targetConfig);
             }
             $result[$this->getResultFieldName($field, $targetConfig)] = $value;
         } elseif ($this->isMetadataField($field)) {
             $result[$this->getResultFieldName($field, $this->getFieldConfig($config, $field))] = $this->getMetadataFieldValue($entity, $field, $entityMetadata);
         }
     }
     return $result;
 }
 /**
  * @param mixed  $entity
  * @param string $entityClass
  * @param array  $config
  *
  * @return array
  */
 protected function serializeItem($entity, $entityClass, $config)
 {
     if (!$entity) {
         return [];
     }
     $result = [];
     $entityMetadata = $this->doctrineHelper->getEntityMetadata($entityClass);
     $resultFields = $this->fieldAccessor->getFieldsToSerialize($entityClass, $config);
     foreach ($resultFields as $field) {
         $value = null;
         if ($this->dataAccessor->tryGetValue($entity, $field, $value)) {
             $targetConfig = ConfigUtil::getFieldConfig($config, $field);
             if ($entityMetadata->isAssociation($field)) {
                 if ($value !== null) {
                     if (!empty($targetConfig[ConfigUtil::FIELDS])) {
                         $targetEntityClass = $entityMetadata->getAssociationTargetClass($field);
                         $targetEntityId = $this->dataAccessor->getValue($value, $this->doctrineHelper->getEntityIdFieldName($targetEntityClass));
                         $value = $this->serializeItem($value, $targetEntityClass, $targetConfig);
                         $items = [$value];
                         $this->loadRelatedData($items, $targetEntityClass, [$targetEntityId], $targetConfig);
                         $value = reset($items);
                         if (isset($targetConfig[ConfigUtil::POST_SERIALIZE])) {
                             $value = $this->postSerialize($value, $targetConfig[ConfigUtil::POST_SERIALIZE]);
                         }
                     } else {
                         $value = $this->dataTransformer->transform($entityClass, $field, $value, $targetConfig);
                     }
                 }
             } else {
                 $value = $this->dataTransformer->transform($entityClass, $field, $value, $targetConfig);
             }
             $result[$field] = $value;
         } elseif ($this->fieldAccessor->isMetadataProperty($field)) {
             $result[$field] = $this->fieldAccessor->getMetadataProperty($entity, $field, $entityMetadata);
         }
     }
     return $result;
 }