@param \SimpleXMLElement $propertyNode
@param string            $className
@param \ReflectionClass  $reflection

@return LabeledPropertyMetadata
320521
private function buildLabeledPropertyMetadata(
        \SimpleXMLElement $propertyNode,
        $className,
        \ReflectionClass $reflection
    ) {
        if (!isset($propertyNode->label['name'])) {
            throw new MappingException(
                sprintf('Class "%s" OGM XML property label configuration is missing "name" attribute', $className)
            );
        }

        $name = (string) $propertyNode['name'];
        $label = new Label();
        $label->name = (string) $propertyNode->label['name'];

        return new LabeledPropertyMetadata(
            $name,
            $reflection->getProperty($name),
            $label
        );
    }
741026
protected function getPropertyLabel($propertyName, NodeInterface $changedNode)
    {
        $properties = $changedNode->getNodeType()->getProperties();
        if (!isset($properties[$propertyName]) ||
            !isset($properties[$propertyName]['ui']['label'])
        ) {
            return $propertyName;
        }
        return $properties[$propertyName]['ui']['label'];
    }
431228
public static function propertyAnnotations($class, $propertyName)
    {
        $class = is_object($class) ? get_class($class) : $class;
        if (!class_exists('ReflectionProperty')) {
            throw new \RuntimeException("Property type of " . $class . "::{$propertyName} cannot be resolved");
        }

        if ($annotations =& self::$propertiesType[$class][$propertyName]) {
            return $annotations;
        }

        if (!($refl =& self::$propertiesRefl[$class][$propertyName])) {
            $getter = self::getter($class, $propertyName);
            $refl = new \ReflectionMethod($class, $getter);
            self::$propertiesRefl[$class][$propertyName] = $refl;
        }

        // todo: smarter regexp
        if (!preg_match_all(
            '~\@([^\s@\(]+)[\t ]*(?:\(?([^\n@]+)\)?)?~i',
            $refl->getDocComment(),
            $annots,
            PREG_PATTERN_ORDER)
        ) {
            return null;
        }
        foreach ($annots[1] as $i => $annot) {
            $annotations[strtolower($annot)] = empty($annots[2][$i]) ? TRUE : rtrim($annots[2][$i], " \t\n\r)");
        }

        return $annotations;
    }
1207740
public function buildEntityIdMetadata(\SimpleXMLElement $node, $className, \ReflectionClass $reflection)
    {
        if (!isset($node->id) || !isset($node->id['name'])) {
            throw new MappingException(
                sprintf('Class "%s" OGM XML configuration has invalid or missing "id" element', $className)
            );
        }

        return new EntityIdMetadata(
            (string) $node->id['name'],
            $reflection->getProperty((string) $node->id['name']),
            new IdAnnotationMetadata()
        );
    }
577425
public static function getHub($classMetadata, $propertyName)
    {
        if ($propertyName instanceof ReflectionProperty) {
            $propertyName = $propertyName->getName();
        }
        $path = self::PATH_HUB;

        return $classMetadata->$path[$propertyName];
    }
710112
public static function parse($model, $propertyName, $annotation)
    {
        if(!$model->$propertyName)
        {
            return;
        }
        $className = BeanFactory::getObjectClass($model);
        $autoInsert = AnnotationManager::getPropertyAnnotations($className, $propertyName, AutoInsert::class)[0] ?? null;
        $autoSave = AnnotationManager::getPropertyAnnotations($className, $propertyName, AutoSave::class)[0] ?? null;

        if($autoInsert)
        {
            if(!$autoInsert->status)
            {
                return;
            }
        }
        else if(!$autoSave || !$autoSave->status)
        {
            return;
        }

        if($annotation instanceof \Imi\Model\Annotation\Relation\OneToOne)
        {
            static::parseByOneToOne($model, $propertyName, $annotation);
        }
        else if($annotation instanceof \Imi\Model\Annotation\Relation\OneToMany)
        {
            static::parseByOneToMany($model, $propertyName, $annotation);
        }
        else if($annotation instanceof \Imi\Model\Annotation\Relation\ManyToMany)
        {
            static::parseByManyToMany($model, $propertyName, $annotation);
        }
        else if($annotation instanceof \Imi\Model\Annotation\Relation\PolymorphicOneToOne)
        {
            static::parseByPolymorphicOneToOne($model, $propertyName, $annotation);
        }
        else if($annotation instanceof \Imi\Model\Annotation\Relation\PolymorphicOneToMany)
        {
            static::parseByPolymorphicOneToMany($model, $propertyName, $annotation);
        }
        else if($annotation instanceof \Imi\Model\Annotation\Relation\PolymorphicManyToMany)
        {
            static::parseByPolymorphicManyToMany($model, $propertyName, $annotation);
        }
    }
505841
public function buildRelationshipsMetadata(\SimpleXMLElement $node, $className, \ReflectionClass $reflection)
    {
        $relationships = [];
        foreach ($node->relationship as $relationshipNode) {
            $relationships[] = $this->buildRelationshipMetadata($relationshipNode, $className, $reflection);
        }

        return $relationships;
    }
220
public static function parseClassProperty($fullClassName, $propertyName)
    {
        $class      = self::parseClass($fullClassName);
        $classNodes = $class->stmts;

        foreach ($classNodes as $classLevelNode) {
            if ($classLevelNode instanceof Property) {
                foreach ($classLevelNode->props as $classProperty) {
                    if ($classProperty->name->toString() == $propertyName) {
                        return [$classLevelNode, $classProperty];
                    }
                }
            }
        }

        throw new \InvalidArgumentException("Property $propertyName was not found in the $fullClassName");
    }
454681
private function convertClassAnnotationsToClassMetadata(
        ReflectionClass $reflectionClass,
        array $classAnnotations,
        Mapping\ClassMetadata $metadata,
        Mapping\ClassMetadataBuildingContext $metadataBuildingContext
    ) : Mapping\ClassMetadata {
        switch (true) {
            case isset($classAnnotations[Annotation\Entity::class]):
                $binder = new Binder\EntityClassMetadataBinder(
                    $reflectionClass,
                    $classAnnotations,
                    $metadata,
                    $metadataBuildingContext
                );

                break;

            case isset($classAnnotations[Annotation\MappedSuperclass::class]):
                $binder = new Binder\MappedSuperClassMetadataBinder(
                    $reflectionClass,
                    $classAnnotations,
                    $metadata,
                    $metadataBuildingContext
                );
                break;

            case isset($classAnnotations[Annotation\Embeddable::class]):
                $binder = new Binder\EmbeddableClassMetadataBinder(
                    $reflectionClass,
                    $classAnnotations,
                    $metadata,
                    $metadataBuildingContext
                );
                break;

            default:
                throw Mapping\MappingException::classIsNotAValidEntityOrMappedSuperClass($reflectionClass->getName());
        }

        return $binder->bind();
    }
1358244
private function convertReflectionPropertyToOneToManyAssociationMetadata(
        ReflectionProperty $reflectionProperty,
        array $propertyAnnotations,
        Mapping\ClassMetadata $metadata,
        Mapping\ClassMetadataBuildingContext $metadataBuildingContext
    ) : Mapping\OneToManyAssociationMetadata {
        $className      = $metadata->getClassName();
        $fieldName      = $reflectionProperty->getName();
        $oneToManyAnnot = $propertyAnnotations[Annotation\OneToMany::class];
        $assocMetadata  = new Mapping\OneToManyAssociationMetadata($fieldName);
        $targetEntity   = $oneToManyAnnot->targetEntity;

        $assocMetadata->setTargetEntity($targetEntity);
        $assocMetadata->setCascade($this->getCascade($className, $fieldName, $oneToManyAnnot->cascade));
        $assocMetadata->setOrphanRemoval($oneToManyAnnot->orphanRemoval);
        $assocMetadata->setFetchMode($this->getFetchMode($className, $oneToManyAnnot->fetch));

        if (! empty($oneToManyAnnot->mappedBy)) {
            $assocMetadata->setMappedBy($oneToManyAnnot->mappedBy);
        }

        if (! empty($oneToManyAnnot->indexBy)) {
            $assocMetadata->setIndexedBy($oneToManyAnnot->indexBy);
        }

        // Check for OrderBy
        if (isset($propertyAnnotations[Annotation\OrderBy::class])) {
            $orderByAnnot = $propertyAnnotations[Annotation\OrderBy::class];

            $assocMetadata->setOrderBy($orderByAnnot->value);
        }

        // Check for Id
        if (isset($propertyAnnotations[Annotation\Id::class])) {
            throw Mapping\MappingException::illegalToManyIdentifierAssociation($className, $fieldName);
        }

        $this->attachAssociationPropertyCache($propertyAnnotations, $reflectionProperty, $assocMetadata, $metadata);

        return $assocMetadata;
    }
537255
private function convertReflectionPropertyToManyToManyAssociationMetadata(
        ReflectionProperty $reflectionProperty,
        array $propertyAnnotations,
        Mapping\ClassMetadata $metadata,
        Mapping\ClassMetadataBuildingContext $metadataBuildingContext
    ) : Mapping\ManyToManyAssociationMetadata {
        $className       = $metadata->getClassName();
        $fieldName       = $reflectionProperty->getName();
        $manyToManyAnnot = $propertyAnnotations[Annotation\ManyToMany::class];
        $assocMetadata   = new Mapping\ManyToManyAssociationMetadata($fieldName);
        $targetEntity    = $manyToManyAnnot->targetEntity;

        $assocMetadata->setTargetEntity($targetEntity);
        $assocMetadata->setCascade($this->getCascade($className, $fieldName, $manyToManyAnnot->cascade));
        $assocMetadata->setOrphanRemoval($manyToManyAnnot->orphanRemoval);
        $assocMetadata->setFetchMode($this->getFetchMode($className, $manyToManyAnnot->fetch));

        if (! empty($manyToManyAnnot->mappedBy)) {
            $assocMetadata->setMappedBy($manyToManyAnnot->mappedBy);
        }

        if (! empty($manyToManyAnnot->inversedBy)) {
            $assocMetadata->setInversedBy($manyToManyAnnot->inversedBy);
        }

        if (! empty($manyToManyAnnot->indexBy)) {
            $assocMetadata->setIndexedBy($manyToManyAnnot->indexBy);
        }

        // Check for JoinTable
        if (isset($propertyAnnotations[Annotation\JoinTable::class])) {
            $joinTableAnnot    = $propertyAnnotations[Annotation\JoinTable::class];
            $joinTableMetadata = $this->convertJoinTableAnnotationToJoinTableMetadata($joinTableAnnot);

            $assocMetadata->setJoinTable($joinTableMetadata);
        }

        // Check for OrderBy
        if (isset($propertyAnnotations[Annotation\OrderBy::class])) {
            $orderByAnnot = $propertyAnnotations[Annotation\OrderBy::class];

            $assocMetadata->setOrderBy($orderByAnnot->value);
        }

        // Check for Id
        if (isset($propertyAnnotations[Annotation\Id::class])) {
            throw Mapping\MappingException::illegalToManyIdentifierAssociation($className, $fieldName);
        }

        $this->attachAssociationPropertyCache($propertyAnnotations, $reflectionProperty, $assocMetadata, $metadata);

        return $assocMetadata;
    }
412678
protected function buildProperty(ReflectionProperty $reflectionProperty) : Node\Stmt\Property
    {
        $propertyBuilder = new Property($reflectionProperty->getName());

        if ($reflectionProperty->isPublic()) {
            $propertyBuilder->makePublic();
        }

        if ($reflectionProperty->isProtected()) {
            $propertyBuilder->makeProtected();
        }

        if ($reflectionProperty->isPrivate()) {
            $propertyBuilder->makePrivate();
        }

        if ($reflectionProperty->isStatic()) {
            $propertyBuilder->makeStatic();
        }

        if ($reflectionProperty->isDefault()) {
            $allDefaultProperties = $reflectionProperty->getDeclaringClass()->getDefaultProperties();

            $propertyBuilder->setDefault($allDefaultProperties[$reflectionProperty->getName()]);
        }

        return $propertyBuilder->getNode();
    }
472415
public static function getMaskReflection($classMetadata, $propertyName)
    {
        if ($propertyName instanceof ReflectionProperty) {
            $propertyName = $propertyName->getName();
        }

        $path_hub_mask = self::PATH_HUB_MASK;
        $hubName = $classMetadata->$path_hub_mask[$propertyName];

        $path = self::PATH_MASK_BY_HUB;

        return $classMetadata->$path[$hubName][$propertyName][self::REFLECTION];
    }
188236
protected static function getReflectionClassWithProperty($class, $propertyName)
    {
        Assert::string($class, 'First argument to Reflection::getReflectionClassWithProperty must be string. Variable of type "%s" was given.');
        Assert::classExists($class, 'Could not find class "%s"');

        $refl = new \ReflectionClass($class);
        if ($refl->hasProperty($propertyName)) {
            return $refl;
        }

        if (false === $parent = get_parent_class($class)) {
            // No more parents
            return;
        }

        return self::getReflectionClassWithProperty($parent, $propertyName);
    }
1092571
private function buildNodeMetadata(\SimpleXMLElement $node, $className)
    {
        if (!isset($node['label'])) {
            throw new MappingException(
                sprintf('Class "%s" OGM XML node configuration is missing "label" attribute', $className)
            );
        }

        return new NodeAnnotationMetadata(
            (string) $node['label'],
            isset($node['repository-class']) ? (string) $node['repository-class'] : null
        );
    }
837702
public function getPropertyMetadata($propertyName)
    {
        if (!isset($this->propertyMetadata[$propertyName])) {
            throw MappingException::mappingNotFound($this->name, $propertyName);
        }

        return $this->propertyMetadata[$propertyName];
    }
312015
private function getPropertyInfo(string $propertyName, string $className, int $specVersion = 2): stdClass
    {
        foreach ($this->getProperties($className, $specVersion) as $classPropertyName => $property) {
            if ($classPropertyName === $propertyName) {
                return $property;
            }
        }

        throw new \InvalidArgumentException(sprintf('The property "%s" for the class "%s" doesn\'t exist.', $propertyName, $className));
    }