Parses attribute configuration
@param \Omocha\AnnotationBag $propertyAnnotations
506740
protected function parseConfig(AnnotationBag $propertyAnnotations) {
		$this->config = [];
		
		//mapping type expression
		if (isset($this->type))
			$this->config['map.type'] = $this->type;
		
		//result map
		if ($propertyAnnotations->has('ResultMap'))
			$this->config['map.result'] = $propertyAnnotations->get('ResultMap')->getValue();
		
		//cache
		if ($propertyAnnotations->has('Cache')) {
			$this->config['cache.ttl'] = intval($propertyAnnotations->get('Cache')->getArgument());
			$this->config['cache.key'] = $propertyAnnotations->get('Cache')->getValue();
		}
		
		//custom options
		$options = $propertyAnnotations->find('Option', Filter::HAS_ARGUMENT);
		
		foreach ($options as $option)
			$this->config[$option->getArgument()] = $option->getValue();
		
		//cacheable
		if ($propertyAnnotations->has('Cacheable')) {
			//check type before assuming is cacheable
			$this->cacheable = !empty($this->type) && !preg_match('/^[arr|array|obj|object]:/', $this->type);
		}
		
		//get evaluation condition
		if ($propertyAnnotations->has('If')) {
			$this->program = new DynamicSQLProgram($propertyAnnotations->get('If')->getValue());
			$this->condition = function ($row, $config) {
				return (bool) $this->program->execute($this->buildEnvironment($config), $row);
			};
		}
		elseif ($propertyAnnotations->has('IfNot')) {
			$this->program = new DynamicSQLProgram($propertyAnnotations->get('IfNot')->getValue());
			$this->condition = function ($row, $config) {
				return !(bool) $this->program->execute($this->buildEnvironment($config), $row);
			};
		}
		elseif ($propertyAnnotations->has('IfNotNull')) {
			$attribute = $propertyAnnotations->get('IfNotNull')->getArgument();
			$this->condition = function($row, $_) use ($attribute) {
				$argument = ArgumentWrapper::wrap($row);
				return !($argument->offsetExists($attribute) && $argument->offsetGet($attribute) === null);
			};
		}
	}
333444
public function parser(
        string $className,
        $objectAnnotation = null,
        string $propertyName = '',
        string $methodName = '',
        $propertyValue = null
    ) {
        $collector = ControllerCollector::getCollector();

        if (!isset($collector[$className])) {
            return;
        }

        // Collect requestMapping
        ControllerCollector::collect($className, $objectAnnotation, $propertyName, $methodName, $propertyValue);
    }
1268321
public function execute(RequestAnnotation $annotation, PropertyParserBuilder $propertyParser)
    {
        $propertyParser->addValidator(
            ValidatorBuilder::builder()
            ->withClass($annotation->getAssociatedClass())
            ->withSpecification($annotation->getValue())
            ->build()
        );
    }
428127
public static function put(Annotations $annotations)
    {
        self::$annotations[$annotations->target()]  = serialize($annotations);
        self::$unserialized[$annotations->target()] = $annotations;
        self::$cacheChanged = true;
    }
90950
protected function isAssociation(AnnotationBag $propertyAnnotations) {
		return $propertyAnnotations->has('OneToOne') ||
			$propertyAnnotations->has('OneToMany') ||
			$propertyAnnotations->has('ManyToOne') ||
			$propertyAnnotations->has('ManyToMany');
	}
179697
private function convertReflectionPropertyToManyToOneAssociationMetadata(
        ReflectionProperty $reflectionProperty,
        array $propertyAnnotations,
        Mapping\ClassMetadata $metadata
    ) {
        $className      = $metadata->getClassName();
        $fieldName      = $reflectionProperty->getName();
        $manyToOneAnnot = $propertyAnnotations[Annotation\ManyToOne::class];
        $assocMetadata  = new Mapping\ManyToOneAssociationMetadata($fieldName);
        $targetEntity   = $manyToOneAnnot->targetEntity;

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

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

        // Check for Id
        if (isset($propertyAnnotations[Annotation\Id::class])) {
            $assocMetadata->setPrimaryKey(true);
        }

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

        // Check for JoinColumn/JoinColumns annotations
        switch (true) {
            case isset($propertyAnnotations[Annotation\JoinColumn::class]):
                $joinColumnAnnot = $propertyAnnotations[Annotation\JoinColumn::class];

                $assocMetadata->addJoinColumn(
                    $this->convertJoinColumnAnnotationToJoinColumnMetadata($joinColumnAnnot)
                );

                break;

            case isset($propertyAnnotations[Annotation\JoinColumns::class]):
                $joinColumnsAnnot = $propertyAnnotations[Annotation\JoinColumns::class];

                foreach ($joinColumnsAnnot->value as $joinColumnAnnot) {
                    $assocMetadata->addJoinColumn(
                        $this->convertJoinColumnAnnotationToJoinColumnMetadata($joinColumnAnnot)
                    );
                }

                break;
        }

        return $assocMetadata;
    }
228782
private function convertReflectionPropertyToOneToOneAssociationMetadata(
        ReflectionProperty $reflectionProperty,
        array $propertyAnnotations,
        Mapping\ClassMetadata $classMetadata
    ) {
        $className     = $classMetadata->getClassName();
        $fieldName     = $reflectionProperty->getName();
        $oneToOneAnnot = $propertyAnnotations[Annotation\OneToOne::class];

        if ($oneToOneAnnot->targetEntity === null) {
            throw Mapping\MappingException::missingTargetEntity($fieldName);
        }

        $assocMetadata = new Mapping\OneToOneAssociationMetadata($fieldName);
        $targetEntity  = $oneToOneAnnot->targetEntity;

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

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

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

        // Check for Id
        if (isset($propertyAnnotations[Annotation\Id::class])) {
            $assocMetadata->setPrimaryKey(true);
        }

        // Check for Cache
        if (isset($propertyAnnotations[Annotation\Cache::class])) {
            $cacheAnnot    = $propertyAnnotations[Annotation\Cache::class];
            $cacheMetadata = $this->convertCacheAnnotationToCacheMetadata($cacheAnnot, $classMetadata, $fieldName);

            $assocMetadata->setCache($cacheMetadata);
        }

        // Check for JoinColumn/JoinColumns annotations
        switch (true) {
            case isset($propertyAnnotations[Annotation\JoinColumn::class]):
                $joinColumnAnnot = $propertyAnnotations[Annotation\JoinColumn::class];
                $joinColumn      = $this->convertJoinColumnAnnotationToJoinColumnMetadata(
                    $reflectionProperty,
                    $joinColumnAnnot,
                    $classMetadata
                );

                $assocMetadata->addJoinColumn($joinColumn);

                break;

            case isset($propertyAnnotations[Annotation\JoinColumns::class]):
                $joinColumnsAnnot = $propertyAnnotations[Annotation\JoinColumns::class];

                foreach ($joinColumnsAnnot->value as $joinColumnAnnot) {
                    $joinColumn = $this->convertJoinColumnAnnotationToJoinColumnMetadata(
                        $reflectionProperty,
                        $joinColumnAnnot,
                        $classMetadata
                    );

                    $assocMetadata->addJoinColumn($joinColumn);
                }

                break;
        }

        return $assocMetadata;
    }
266008
public function parser(string $className, $objectAnnotation = null, string $propertyName = "", string $methodName = "", $propertyValue = null)
    {
        $injectValue = $objectAnnotation->getName();
        if (!empty($injectValue)) {
            return [$injectValue, true];
        }

        // phpdoc解析
        $phpReader = new PhpDocReader();
        $property = new \ReflectionProperty($className, $propertyName);
        $propertyClass = $phpReader->getPropertyClass($property);

        $isRef = true;
        $injectProperty = $propertyClass;
        return [$injectProperty, $isRef];
    }
164649
private function convertReflectionPropertyToManyToManyAssociationMetadata(
        ReflectionProperty $reflectionProperty,
        array $propertyAnnotations,
        Mapping\ClassMetadata $classMetadata
    ) {
        $className       = $classMetadata->getClassName();
        $fieldName       = $reflectionProperty->getName();
        $manyToManyAnnot = $propertyAnnotations[Annotation\ManyToMany::class];

        if ($manyToManyAnnot->targetEntity === null) {
            throw Mapping\MappingException::missingTargetEntity($fieldName);
        }

        $assocMetadata = new Mapping\ManyToManyAssociationMetadata($fieldName);
        $targetEntity  = $manyToManyAnnot->targetEntity;

        $assocMetadata->setSourceEntity($className);
        $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(
                $reflectionProperty,
                $joinTableAnnot,
                $classMetadata
            );

            $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])) {
            $assocMetadata->setPrimaryKey(true);
        }

        // Check for Cache
        if (isset($propertyAnnotations[Annotation\Cache::class])) {
            $cacheAnnot    = $propertyAnnotations[Annotation\Cache::class];
            $cacheMetadata = $this->convertCacheAnnotationToCacheMetadata($cacheAnnot, $classMetadata, $fieldName);

            $assocMetadata->setCache($cacheMetadata);
        }

        return $assocMetadata;
    }
648014
public function parseClassAnnotations(string $className, array $annotations)
    {
        if (!$this->isParseClass($annotations)) {
            return null;
        }

        $beanData = null;
        foreach ($annotations as $annotation) {
            $annotationClass = get_class($annotation);
            if (!in_array($annotationClass, $this->getClassAnnotations())) {
                continue;
            }

            // annotation parser
            $annotationParser = $this->getAnnotationParser($annotation);
            if ($annotationParser == null) {
                continue;
            }
            $annotationData = $annotationParser->parser($className, $annotation);
            if ($annotationData != null) {
                $beanData = $annotationData;
            }
        }

        return $beanData;
    }
657870
protected function getAnnotation($entity, $property, $annotation) {
        $classRef = new \ReflectionClass($entity);
        $propertyRef = $classRef->getProperty($property);
        if ($propertyRef) return $this->annoReader->getPropertyAnnotation($propertyRef, $annotation);
        else return null;
    }
731895
public static function getPropertyAnnotation($object, $propertyName, $annotationClass)
    {
        return AnnotationManager::getPropertyAnnotations(BeanFactory::getObjectClass($object), $propertyName, $annotationClass)[0] ?? null;
    }
813250
public static function initByOneToMany($model, $propertyName, $annotation)
    {
        $className = BeanFactory::getObjectClass($model);

        if(class_exists($annotation->model))
        {
            $modelClass = $annotation->model;
        }
        else
        {
            $modelClass = Imi::getClassNamespace($className) . '\\' . $annotation->model;
        }

        $struct = new OneToMany($className, $propertyName, $annotation);
        $leftField = $struct->getLeftField();
        $rightField = $struct->getRightField();

        $model->$propertyName = new ArrayList($modelClass);
        if(null !== $model->$leftField)
        {
            $list = $modelClass::query()->where($rightField, '=', $model->$leftField)->select()->getArray();
            if(null !== $list)
            {
                $model->$propertyName->append(...$list);
            }
        }

    }
418493
public static function initByPolymorphicToOne($model, $propertyName, $annotation)
    {
        foreach($annotation as $annotationItem)
        {
            if($model->{$annotationItem->type} == $annotationItem->typeValue)
            {
                $leftField = $annotationItem->modelField;
                $rightField = $annotationItem->field;
                if(class_exists($annotationItem->model))
                {
                    $modelClass = $annotationItem->model;
                }
                else
                {
                    $modelClass = Imi::getClassNamespace($className) . '\\' . $annotationItem->model;
                }
                if(null === $model->$rightField)
                {
                    $leftModel = $modelClass::newInstance();
                }
                else
                {
                    $leftModel = $modelClass::query()->where($leftField, '=', $model->$rightField)->select()->get();
                    if(null === $leftModel)
                    {
                        $leftModel = $modelClass::newInstance();
                    }
                }
                $model->$propertyName = $leftModel;
                break;
            }
        }
    }
871847
private function convertReflectionPropertyToFieldMetadata(
        ReflectionProperty $reflectionProperty,
        array $propertyAnnotations,
        Mapping\ClassMetadata $classMetadata
    ) {
        $className    = $classMetadata->getClassName();
        $fieldName    = $reflectionProperty->getName();
        $columnAnnot  = $propertyAnnotations[Annotation\Column::class];
        $isVersioned  = isset($propertyAnnotations[Annotation\Version::class]);
        $isPrimaryKey = isset($propertyAnnotations[Annotation\Id::class]);

        if ($columnAnnot->type === null) {
            throw Mapping\MappingException::propertyTypeIsRequired($className, $fieldName);
        }

        if ($isVersioned && $isPrimaryKey) {
            throw Mapping\MappingException::cannotVersionIdField($className, $fieldName);
        }

        $columnName = empty($columnAnnot->name)
            ? $this->namingStrategy->propertyToColumnName($fieldName, $className)
            : $columnAnnot->name;

        $fieldMetadata = $isVersioned
            ? new Mapping\VersionFieldMetadata($fieldName)
            : new Mapping\FieldMetadata($fieldName);

        $fieldMetadata->setType(Type::getType($columnAnnot->type));
        $fieldMetadata->setColumnName($columnName);
        $fieldMetadata->setScale($columnAnnot->scale);
        $fieldMetadata->setPrecision($columnAnnot->precision);
        $fieldMetadata->setNullable($columnAnnot->nullable);
        $fieldMetadata->setUnique($columnAnnot->unique);

        // Check for Id
        if ($isPrimaryKey) {
            if ($fieldMetadata->getType()->canRequireSQLConversion()) {
                throw Mapping\MappingException::sqlConversionNotAllowedForPrimaryKeyProperties($className, $fieldMetadata);
            }

            $fieldMetadata->setPrimaryKey(true);
        }

        if (! empty($columnAnnot->columnDefinition)) {
            $fieldMetadata->setColumnDefinition($columnAnnot->columnDefinition);
        }

        if (! empty($columnAnnot->length)) {
            $fieldMetadata->setLength($columnAnnot->length);
        }

        // Assign default options
        $customOptions  = $columnAnnot->options ?? [];
        $defaultOptions = [];

        if ($isVersioned) {
            switch ($fieldMetadata->getTypeName()) {
                case 'integer':
                case 'bigint':
                case 'smallint':
                    $defaultOptions['default'] = 1;
                    break;

                case 'datetime':
                    $defaultOptions['default'] = 'CURRENT_TIMESTAMP';
                    break;

                default:
                    if (! isset($customOptions['default'])) {
                        throw Mapping\MappingException::unsupportedOptimisticLockingType($fieldMetadata->getType());
                    }
            }
        }

        $fieldMetadata->setOptions(array_merge($defaultOptions, $customOptions));

        return $fieldMetadata;
    }
1107401
private function parseFields(array $fields)
    {
        $propertyStub = $this->generateProperty();
        $setterStub   = $this->generateSetter();
        $getterStub   = $this->generateGetter();
        foreach ($fields as $fieldInfo) {
            $this->parseProperty($propertyStub, $fieldInfo);
            $this->parseSetter($setterStub, $fieldInfo);
            $this->parseGetter($getterStub, $fieldInfo);
        }
    }
16116
public static function initByPolymorphicOneToOne($model, $propertyName, $annotation)
    {
        $className = BeanFactory::getObjectClass($model);

        if(class_exists($annotation->model))
        {
            $modelClass = $annotation->model;
        }
        else
        {
            $modelClass = Imi::getClassNamespace($className) . '\\' . $annotation->model;
        }

        $struct = new PolymorphicOneToOne($className, $propertyName, $annotation);
        $leftField = $struct->getLeftField();
        $rightField = $struct->getRightField();

        if(null === $model->$leftField)
        {
            $rightModel = $modelClass::newInstance();
        }
        else
        {
            $rightModel = $modelClass::query()->where($annotation->type, '=', $annotation->typeValue)->where($rightField, '=', $model->$leftField)->select()->get();
            if(null === $rightModel)
            {
                $rightModel = $modelClass::newInstance();
            }
        }

        $model->$propertyName = $rightModel;
    }