@param \ReflectionProperty $property
@param $structure

@return array
969224
protected function buildPropertyAnnotation($property, &$structure) {
        $field = array(
            'name' => $this->convertNaming($property->getName()),
            'type' => 'string',
        );
        $association = array();
        $validators = array();
        $skipValidator = false;
        $saveField = false;
        $fieldIsId = false;
        $annotations = $this->annoReader->getPropertyAnnotations($property);
        foreach ($annotations as $annotation) {
            $className = get_class($annotation);
            /** Get Constraints from Symfony Validator */
            if (strpos(get_class($annotation), 'Symfony\Component\Validator\Constraints') === 0) {
                $validators[] = array_merge(
                    array('field'=>$this->convertNaming($property->getName())),
                    $this->getValidator(substr($className, 40),$annotation)
                );
            }
            switch(get_class($annotation)) {
                case 'Tpg\ExtjsBundle\Annotation\Model\Field':
                    $field['type'] = $annotation->type;
                    break;
                case 'Doctrine\ORM\Mapping\Id':
                case 'Doctrine\ODM\MongoDB\Mapping\Annotations\Id':
                    $field['useNull'] = true;
                    $field['persist'] = false;
                    $skipValidator = true;
                    $fieldIsId = true;
                    break;
                case 'Doctrine\ODM\MongoDB\Mapping\Annotations\Timestamp':
                case 'Doctrine\ODM\MongoDB\Mapping\Annotations\Date':
                    $field['type'] = "date";
                    break;
                case 'Doctrine\ODM\MongoDB\Mapping\Annotations\Float':
                    $field['type'] = "float";
                    break;
                case 'Doctrine\ODM\MongoDB\Mapping\Annotations\Boolean':
                    $field['type'] = "boolean";
                    break;
                case 'Doctrine\ODM\MongoDB\Mapping\Annotations\Hash':
                    $field['type'] = "auto";
                    break;
                case 'Doctrine\ODM\MongoDB\Mapping\Annotations\Int':
                case 'Doctrine\ODM\MongoDB\Mapping\Annotations\Increment':
                    $field['type'] = "int";
                    break;
                case 'Doctrine\ODM\MongoDB\Mapping\Annotations\String':
                    $field['type'] = "string";
                    break;
                case 'Doctrine\ODM\MongoDB\Mapping\Annotations\Field':
                    $field['type'] = $this->getColumnType($annotation->type);
                    break;
                case 'Doctrine\ORM\Mapping\Column':
                    $field['type'] = $this->getColumnType($annotation->type);
                    if ($field['type'] === "date") {
                        $field['dateFormat'] = \DateTime::ISO8601;
                    }
                    $validators[] = array('type'=>'presence', 'field'=>$this->convertNaming($property->getName()));
                    break;
                case 'JMS\Serializer\Annotation\SerializedName':
                    $field['name'] = $annotation->name;
                    break;
                case 'JMS\Serializer\Annotation\Type':
                    if (stripos($annotation->name, "DateTime") === 0) {
                        $type = $annotation->name;
                        if ($type === "DateTime") {
                            $field['dateFormat'] = \DateTime::ISO8601;
                        } else {
                            $format = explode(',',
                                substr(
                                    $type,
                                    stripos($type, '<')+2,
                                    -2
                                )
                            );
                            $field['dateFormat'] = $format[0];
                        }
                    }
                    break;
                case 'Doctrine\ORM\Mapping\OneToOne':
                    $association['type'] = substr(get_class($annotation), 21);
                    $association['name'] = $property->getName();
                    $association['model'] = $this->getModelName($annotation->targetEntity);
                    $association['entity'] = $annotation->targetEntity;
                    if (!isset($association['key']) || empty($association['key']))
                        $association['key'] = $this->tryToGetJoinColumnNameOfMappedBy($annotation);
                    break;
                case 'Doctrine\ORM\Mapping\OneToMany':
                    $association['type'] = substr(get_class($annotation), 21);
                    $association['name'] = $property->getName();
                    $association['model'] = $this->getModelName($annotation->targetEntity);
                    $association['entity'] = $annotation->targetEntity;
                    $association['key'] = $this->tryToGetJoinColumnNameOfMappedBy($annotation);
                    break;
                case 'Doctrine\ODM\MongoDB\Mapping\Annotations\EmbedMany':
                case 'Doctrine\ODM\MongoDB\Mapping\Annotations\EmbedOne':
                case 'Doctrine\ODM\MongoDB\Mapping\Annotations\ReferenceMany':
                case 'Doctrine\ODM\MongoDB\Mapping\Annotations\ReferenceOne':
                    if ($annotation->targetDocument) {
                        $association['type'] = substr(get_class($annotation), 41);
                        $association['name'] = $property->getName();
                        $association['model'] = $this->getModelName($annotation->targetDocument);
                        $association['entity'] = $annotation->targetDocument;
                    } else {
                        $field['type'] = "auto";
                    }
                    break;
                case 'Doctrine\ORM\Mapping\ManyToOne':
                    $association['type'] = substr(get_class($annotation), 21);
                    $association['name'] = $property->getName();
                    $association['model'] = $this->getModelName($annotation->targetEntity);
                    $association['entity'] = $annotation->targetEntity;
                    break;
                case 'Doctrine\ORM\Mapping\ManyToMany':
                    $association['type'] = 'ManyToMany';
                    $association['name'] = $property->getName();
                    $association['model'] = $this->getModelName($annotation->targetEntity);
                    $association['entity'] = $annotation->targetEntity;
                    break;
                case 'Doctrine\ORM\Mapping\JoinColumns':
                    if (count($annotation->value) > 1) {
                      throw new \Exception('Multiple foreign key is not supported');
                    }
                    $saveField = true;
                    $field['name'] = $this->convertNaming($annotation->value[0]->name);
                    $field['type'] = $this->getEntityColumnType($association['entity'], $annotation->value[0]->referencedColumnName);
                    $field['useNull'] = true;
                    $association['key'] = $this->convertNaming($annotation->value[0]->name);
                    break;
                case 'Doctrine\ORM\Mapping\JoinColumn':
                    $saveField = true;
                    $field['name'] = $this->convertNaming($annotation->name);
                    $field['type'] = $this->getEntityColumnType($association['entity'], $annotation->referencedColumnName);
                    $field['useNull'] = true;
                    $association['key'] = $this->convertNaming($annotation->name);
                    $field['mapping'] = $property->getName() . '.' . $annotation->referencedColumnName;
                    break;
            }
        }
        if($fieldIsId){
            $structure['idProperty'] = $field['name'];
        }

        /** Add the ability to override field parameter */
        if (isset($this->fieldsParams[$field['type']])) {
          $field = array_merge($field, $this->fieldsParams[$field['type']]);
        }

        if (!empty($association)) {
            if ($association['model'] === null) {
                /** Related model is not available, skip this field. */
                return array();
            }
            $structure['associations'][] = $association;
        }
        if ($saveField || empty($association)) {
            $structure['fields'][$field['name']] = $field;
        }
        if (!empty($validators) && !$skipValidator) {
            $structure['validators'] = array_merge($structure['validators'], $validators);
        }
        return $field;
    }
1013914
private function getFilterProperties(ApiFilter $filterAnnotation, \ReflectionClass $reflectionClass, \ReflectionProperty $reflectionProperty = null): array
    {
        $properties = [];

        if ($filterAnnotation->properties) {
            foreach ($filterAnnotation->properties as $property => $strategy) {
                if (\is_int($property)) {
                    $properties[$strategy] = null;
                } else {
                    $properties[$property] = $strategy;
                }
            }

            return $properties;
        }

        if (null !== $reflectionProperty) {
            $properties[$reflectionProperty->getName()] = $filterAnnotation->strategy ?: null;

            return $properties;
        }

        if ($filterAnnotation->strategy) {
            foreach ($reflectionClass->getProperties() as $reflectionProperty) {
                $properties[$reflectionProperty->getName()] = $filterAnnotation->strategy;
            }
        }

        return $properties;
    }
1167190
private function getEmbeddedAnnotationData(\ReflectionProperty $property)
    {
        $result = $this->reader->getPropertyAnnotation($property, self::EMBEDDED_ANNOTATION);

        if ($result !== null && $result->name === null) {
            $result->name = Caser::snake($property->getName());
        }

        return $result;
    }
470438
private function getReflProperty(string $property): ReflectionProperty
    {
        if (!isset($this->reflProperties[$property])) {
            $this->reflProperties[$property] = new \ReflectionProperty($this->class, $property);
            $this->reflProperties[$property]->setAccessible(true);
        }

        return $this->reflProperties[$property];
    }
591293
public function extract( $structure )
    {
        if ( $structure instanceof StructureAbstract )
        {
            return $structure->toArray();
        }

        if ( $structure instanceof Traversable )
        {
            return ArrayUtils::iteratorToArray( $structure );
        }

        return (array) $structure;
    }
1186695
public function getPropertyClass(\ReflectionProperty $property) : ?string
    {
        $types = $this->getPropertyTypes($property);

        if (count($types) === 1) {
            $type = $types[0];

            if ($type[0] === '\\') {
                return substr($type, 1);
            }
        }

        return null;
    }
71627
public static function getPropertyTypes(\ReflectionProperty $property)
    {
        $hash = $property->class.'-'.$property->getName();

        if (isset(self::$propertyTypes[$hash])) {
            return self::$propertyTypes[$hash];
        }

        $doc = $property->getDocComment();
        preg_match('/@var\s([\w\\\|\[\]]+)/', $doc, $matches);
        $types = [];
        if (isset($matches[1])) {
            $types = explode('|', $matches[1]);
        }

        self::$propertyTypes[$hash] = $types;

        return $types;
    }
184922
public function getProperties($filter = -1)
    {
        $properties = parent::getProperties($filter);
        foreach ($properties as $key => $val) {
            $properties[$key] = new ReflectionProperty($this->getName(), $val->getName());
        }

        return $properties;
    }
690303
public static function buildStructure($array, Structure $structure)
    {
        switch ($structure->getType()) {
            case Structure::TYPE_LIST:
                $result = self::buildList($array, $structure);
                break;
            case Structure::TYPE_ARRAY:
                $result = self::buildArray($array, $structure);
                break;
            default:
                throw new Exception('Unknown structure type ' . $structure->getType());
        }

        return $result;
    }
1038260
public function save( & $structure )
    {
        $id = $this->getSaveProperty( $structure, 'id' );

        if ( empty( $id ) )
        {
            $selector = $this->getSaveProperty( $structure, 'selector', '' );
            $media    = $this->getSaveProperty( $structure, 'media', '' );
            $rootId   = $this->getSaveProperty( $structure, 'rootParagraphId' );
            $sql      = $this->sql();
            $select   = $sql->select()
                            ->columns( array( 'id' ) )
                            ->where( array(
                                'selector'        => $selector,
                                'media'           => $media,
                                'rootParagraphId' => $rootId,
                            ) )
                            ->limit( 1 );

            $result = $sql->prepareStatementForSqlObject( $select )
                          ->execute();

            if ( $result->getAffectedRows() )
            {
                foreach ( $result as $row )
                {
                    $this->setSaveProperty( $structure, 'id', $row['id'] );
                }
            }
        }

        $result = parent::save( $structure );
        $id     = $this->getSaveProperty( $structure, 'id' );

        if ( $result > 0 && ! empty( $id ) )
        {
            switch ( true )
            {
                case $structure instanceof Structure:
                    $properties = $structure->getRawProperties();
                    break;

                case is_array( $structure ):
                    $properties = isset( $structure['properties'] )
                        ? $structure['properties']
                        : array();
                    break;

                case is_object( $structure ):
                    $properties = isset( $structure->properties )
                        ? $structure->properties
                        : array();
                    break;

                default:
                    return $result;
            }

            $sql = $this->sql( $this->getTableInSchema(
                static::$propertyTableName
            ) );

            if ( empty( $properties ) )
            {
                $delete = $sql->delete()
                              ->where( array(
                                  'ruleId' => $id,
                              ) );

                $result += $sql->prepareStatementForSqlObject( $delete )
                               ->execute()
                               ->getAffectedRows();
            }
            else
            {
                $propNames = array();

                foreach ( $properties as $name => $spec )
                {
                    $propNames[] = $propName = empty( $spec['name'] )
                        ? $name : $spec['name'];

                    $result += $this->saveProperty(
                        $id,
                        $propName,
                        $spec['value'],
                        $spec['priority']
                    );
                }

                $delete = $sql->delete()
                              ->where( array(
                                  'ruleId' => $id,
                                  new NotIn( 'name', $propNames ),
                              ) );

                $result += $sql->prepareStatementForSqlObject( $delete )
                               ->execute()
                               ->getAffectedRows();
            }
        }

        return $result;
    }
101242
protected function parse(array $structure, int $offset = null)
    {
        $result = [];
        $current = $offset ?? 0;

        $count_structure = 0;
        foreach ($structure as $registry_group) {
            if (is_array($registry_group)) {
                $buffer = [];
                do {
                    try {
                        $rec = $this->parse($registry_group, $current);
                        $nested = (count($registry_group) > 1)
                            ? [$rec['registries']]
                            : $rec['registries'];
                        $buffer = array_merge($buffer, $nested);
                        $current = $rec['offset'];
                    } catch (ParseException $e) {
                        if (count($buffer) === 0) {
                            throw $e;
                        } else {
                            $first = $registry_group[0];
                            if (is_string($first)) {
                                $first = explode(' ', $first);
                            }
                            $in_first = array_intersect(
                                $first,
                                $e->getRegistries()
                            );
                            if (count($in_first) === 0) {
                                throw $e;
                            }
                            break;
                        }
                    }
                } while ($current < count($this->registries));
                $nested = (count($registry_group) > 1)
                    ? $buffer
                    : [$buffer];
                $result = array_merge($result, $nested);
            } else {
                $types = explode(' ', $registry_group);
                $registry = $this->pregRegistry($current, $types);

                if ($registry !== null) {
                    $result[] = $registry;
                    $current++;
                } elseif (count($result) === 0 || $count_structure > 0) {
                    throw new ParseException(
                        $this->config,
                        $types,
                        $current + 1
                    );
                }
            }
            $count_structure++;
        }

        return [
            'offset' => $current,
            'registries' => $result,
        ];
    }
652343
private function getAccessorMethod(string $class, string $property): ?array
    {
        $ucProperty = ucfirst($property);

        foreach ($this->accessorPrefixes as $prefix) {
            try {
                $reflectionMethod = new \ReflectionMethod($class, $prefix.$ucProperty);
                if ($reflectionMethod->isStatic()) {
                    continue;
                }

                if (0 === $reflectionMethod->getNumberOfRequiredParameters()) {
                    return [$reflectionMethod, $prefix];
                }
            } catch (\ReflectionException $e) {
                // Return null if the property doesn't exist
            }
        }

        return null;
    }
263590
protected function getGeneratedProperties(): array
    {
        $reflectionObject = new \ReflectionObject($this);
        $properties = $reflectionObject->getProperties(\ReflectionProperty::IS_PUBLIC);
        $result = [];
        foreach ($properties as $property) {
            if (!$property->isPublic() || @$property->isDefault()) {
                continue;
            }

            $result[] = $property;
        }

        return $result;
    }
1096028
public static function getPrivateProperty(\ReflectionClass $reflectionClass, $property)
    {
        if (!$reflectionClass->hasProperty($property) && $reflectionClass->getParentClass()) {
            return static::getPrivateProperty($reflectionClass->getParentClass(), $property);
        }

        return $reflectionClass->getProperty($property);
    }
356214
private function getRoutePathPropertyNameByStructureType($structureType)
    {
        $metadata = $this->metadataFactory->getStructureMetadata('article', $structureType);
        if ($metadata->hasTag(self::TAG_NAME)) {
            return $metadata->getPropertyByTagName(self::TAG_NAME);
        }

        return $metadata->getProperty(self::ROUTE_PROPERTY);
    }
311279
protected static function calculateFieldPathsAsArray(array $structure, string $firstLevelFieldName = null): array
    {
        $fieldPaths = [];
        foreach ($structure as $key => $subStructure) {
            $fieldPath = [];
            if ($firstLevelFieldName !== null) {
                $fieldPath[] = $firstLevelFieldName;
            }
            $fieldPath[] = $key;
            if (is_array($subStructure)) {
                foreach (self::calculateFieldPathsAsArray($subStructure) as $subFieldPath) {
                    $fieldPaths[] = array_merge($fieldPath, $subFieldPath);
                }
            } else {
                $fieldPaths[] = $fieldPath;
            }
        }

        return $fieldPaths;
    }
1131775
public function buildPropertiesMetadata(\SimpleXMLElement $node, $className, \ReflectionClass $reflection)
    {
        $properties = [];
        foreach ($node->property as $propertyNode) {
            $properties[] = $this->buildPropertyMetadata($propertyNode, $className, $reflection);
            if (isset($propertyNode->label)) {
                $properties[] = $this->buildLabeledPropertyMetadata($propertyNode, $className, $reflection);
            }
        }

        return $properties;
    }