初始化多对多关系

@param \Imi\Model\Model $model
@param string $propertyName
@param \Imi\Model\Annotation\Relation\ManyToMany $annotation
@return void
961221
public static function initByManyToMany($model, $propertyName, $annotation)
    {
        $className = BeanFactory::getObjectClass($model);

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

        $struct = new ManyToMany($className, $propertyName, $annotation);
        $leftField = $struct->getLeftField();
        $rightField = $struct->getRightField();
        $middleTable = ModelManager::getTable($struct->getMiddleModel());
        $rightTable = ModelManager::getTable($struct->getRightModel());

        static::parseManyToManyQueryFields($struct->getMiddleModel(), $struct->getRightModel(), $middleFields, $rightFields);
        $fields = static::mergeManyToManyFields($middleTable, $middleFields, $rightTable, $rightFields);
        
        $model->$propertyName = new ArrayList($struct->getMiddleModel());
        $model->{$annotation->rightMany} = new ArrayList($struct->getRightModel());
        
        if(null !== $model->$leftField)
        {
            $list = Db::query(ModelManager::getDbPoolName($className))
                        ->table($rightTable)
                        ->field(...$fields)
                        ->join($middleTable, $middleTable . '.' . $struct->getMiddleRightField(), '=', $rightTable . '.' . $rightField)
                        ->where($middleTable . '.' . $struct->getMiddleLeftField(), '=', $model->$leftField)
                        ->select()
                        ->getArray();
            if(null !== $list)
            {
                // 关联数据
                static::appendMany($model->$propertyName, $list, $middleFields, $struct->getMiddleModel());

                // 右侧表数据
                static::appendMany($model->{$annotation->rightMany}, $list, $rightFields, $struct->getRightModel());

            }
        }
    }
3337
protected function isPropertyAnnotated($propertyName)
    {
        $target = $this->getClass();
        $isAnnotated = false;

        while ($target) {

            if ($target->hasProperty($propertyName)) {
                $comment = $target->getProperty($propertyName)->getDocComment();
                if (empty($comment) === false) {
                    $isAnnotated = mb_strpos($comment, self::ANNOTATION_PROPERTY, 0, 'UTF-8') !== false;

                    if ($isAnnotated === true) {
                        break;
                    }

                }
            }

            $target = $target->getParentClass();
        }

        return $isAnnotated;
    }
1029319
public static function collect(string $className, $objectAnnotation = null, string $propertyName = "", string $methodName = "", $propertyValue = null)
    {
        if ($objectAnnotation instanceof Process) {

            $num       = $objectAnnotation->getNum();
            $name      = $objectAnnotation->getName();
            $boot      = $objectAnnotation->isBoot();
            $inout     = $objectAnnotation->isInout();
            $pipe      = $objectAnnotation->isPipe();
            $coroutine = $objectAnnotation->isCoroutine();
            $name      = empty($name) ? $className : $name;

            self::$processes[$name] = [
                'name'  => $name,
                'num'   => $num,
                'boot'  => $boot,
                'pipe'  => $pipe,
                'inout' => $inout,
                'co'    => $coroutine,
                'class' => $className,
            ];

            return;
        }
    }
814716
public static function initModel($model)
    {
        foreach(AnnotationManager::getPropertiesAnnotations(BeanFactory::getObjectClass($model), RelationBase::class) as $propertyName => $annotations)
        {
            if(null !== $model[$propertyName])
            {
                continue;
            }
            $annotation = $annotations[0];
            Query::init($model, $propertyName, $annotation);
        }
    }
387714
public static function collect(
        string $className,
        $objectAnnotation = null,
        string $propertyName = '',
        string $methodName = '',
        $propertyValue = null
    ) {
        if ($objectAnnotation instanceof Strings) {
            self::collectString($objectAnnotation, $className, $methodName);
        } elseif ($objectAnnotation instanceof Floats) {
            self::collectFloats($objectAnnotation, $className, $methodName);
        } elseif ($objectAnnotation instanceof Number) {
            self::collectNumber($objectAnnotation, $className, $methodName);
        } elseif ($objectAnnotation instanceof Integer) {
            self::collectInteger($objectAnnotation, $className, $methodName);
        } elseif ($objectAnnotation instanceof Enum) {
            self::collectEnum($objectAnnotation, $className, $methodName);
        }
    }
684005
public function setModelRelationship(&$model, Field $field)
    {
        //if this is a belongsToMany, we want to sort our initial values
        $relatedItems   = $this->getModelRelatedItems($model, $field);
        $name           = $field->getOption('field_name');
        $multipleValues = $field->getOption('multiple_values');
        $nameField      = $field->getOption('name_field');
        $autocomplete   = $field->getOption('autocomplete');
        $options        = $field->getOption('options');

        //get all existing values for this relationship
        if ($relatedItems) {
            //the array that holds all the ids of the currently-related items
            $relationsArray = array();

            //the id-indexed array that holds all of the select option data for a relation.
            //this holds the currently-related items and all of the available options
            $autocompleteArray = array();

            //iterate over the items
            foreach ($relatedItems as $item) {
                $keyName = $item->getKeyName();

                //if this is a mutliple-value type (i.e. HasMany, BelongsToMany), make sure this is an array
                if ($multipleValues) {
                    $relationsArray[] = $item->{$keyName};
                } else {
                    $model->setAttribute($name, $item->{$keyName});
                }

                //if this is an autocomplete field, we'll need to provide an array of arrays with 'id' and 'text' indexes
                if ($autocomplete) {
                    $autocompleteArray[$item->{$keyName}] = array('id' => $item->{$keyName}, 'text' => $item->{$nameField});
                }
            }

            //if this is a BTM, set the relations array to the property that matches the relationship name
            if ($multipleValues) {
                $model->{$name} = $relationsArray;
            }

            //set the options attribute
            $model->setAttribute($name.'_options', $options);

            //unset the relationships so we only get back what we need
            $model->relationships = array();

            //set the autocomplete array
            if ($autocomplete) {
                $model->setAttribute($name.'_autocomplete', $autocompleteArray);
            }
        }
        //if there are no values, then just set an empty array
        else {
            $model->{$name} = array();
        }
    }
50624
public static function queryModelRelations($model, ...$names)
    {
        $relations = AnnotationManager::getPropertiesAnnotations(BeanFactory::getObjectClass($model), RelationBase::class);
        foreach($names as $name)
        {
            if(isset($relations[$name]))
            {
                Query::init($model, $name, $relations[$name][0], true);
            }
        }
    }
317264
private function processBidirectional($annotation, PropertyInformation $information): void
    {
        // Parse the mappedBy and inversedBy columns, there is no nice interface
        // on them so we have to check for existence of the property.
        if (property_exists($annotation, 'inversedBy') && $annotation->inversedBy) {
            $information->setReferencedProperty($annotation->inversedBy);
        } elseif (property_exists($annotation, 'mappedBy') && $annotation->mappedBy) {
            $information->setReferencedProperty($annotation->mappedBy);
        }

        if ($annotation instanceof ManyToOne || $annotation instanceof ManyToMany) {
            $information->setReferencingCollection(true);
        }

        // Set default value for nullable.
        if ($information->isNullable() === null) {
            $information->setNullable((new JoinColumn())->nullable);
        }

        // Set field name for index on this collection.
        if (!property_exists($annotation, 'indexBy') || !$annotation->indexBy) {
            return;
        }

        $information->setIndex($annotation->indexBy);
    }
142083
public void init(Email annotation, PropertyMetadata propertyMetadata)
    {
        m_propertyMetadata = propertyMetadata;
        m_pattern = java.util.regex.Pattern.compile("^" + ATOM + "+(\\." + ATOM + "+)*@"
                + DOMAIN
                + "|"
                + IP_DOMAIN
                + ")$",
        java.util.regex.Pattern.CASE_INSENSITIVE
);
        m_message = annotation.message();
    }
912179
public function isPropertyAnnotatedWith($className, $propertyName, $annotationClassName)
    {
        $className = $this->prepareClassReflectionForUsage($className);
        return isset($this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_ANNOTATIONS][$annotationClassName]);
    }
728040
protected function parseArguments(AnnotationBag $propertyAnnotations) {
		$this->args = [];
		
		//parse additional arguments
		$parameters = $propertyAnnotations->find('Param');
		
		foreach ($parameters as $param) {
			if ($param->hasArgument()) {
				$arg = $param->getArgument();
				
				if (strtolower($arg) == 'self')
					$this->useDefaultArgument = true;
				else
					$this->args[] = Attr::__callstatic($arg);
			}
			else
				$this->args[] = $param->getValue();
		}
		
		//use default argument if no arguments are specified
		if (empty($this->args))
			$this->useDefaultArgument = true;
	}
938315
protected function properties(Model $model)
    {
        // Process property annotations
        $annotations = '';

        foreach ($model->getProperties() as $name => $hint) {
            $annotations .= $this->class->annotation('property', "$hint \$$name");
        }

        if ($model->hasRelations()) {
            // Add separation between model properties and model relations
            $annotations .= "\n * ";
        }

        foreach ($model->getRelations() as $name => $relation) {
            // TODO: Handle collisions, perhaps rename the relation.
            if ($model->hasProperty($name)) {
                continue;
            }
            $annotations .= $this->class->annotation('property', $relation->hint()." \$$name");
        }

        return $annotations;
    }
1055834
public function validateProperty(string $propertyName): void
    {
        $errors = $this->validator->validateProperty($this->dataObject, $propertyName);
        $this->throwExceptionIfErrors($errors);
    }
1213827
public static function parseByPolymorphicOneToMany($model, $propertyName, $annotation)
    {
        $className = BeanFactory::getObjectClass($model);

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

        $rightModel::deleteBatch(function(IQuery $query) use($model, $leftField, $rightField, $annotation){
            $query->where($annotation->type, '=', $annotation->typeValue)->where($rightField, '=', $model->$leftField);
        });
    }
830758
public static function collect(string $className, $objectAnnotation = null, string $propertyName = '', string $methodName = '', $propertyValue = null)
    {
        // collect service
        if ($objectAnnotation instanceof Service) {

            $rc = new \ReflectionClass($className);
            $interfaces = $rc->getInterfaceNames();
            $methods = $rc->getMethods(\ReflectionMethod::IS_PUBLIC);
            $version = $objectAnnotation->getVersion();

            foreach ($interfaces as $interfaceClass){
                foreach ($methods as $method){
                    $methodName = $method->getName();
                    self::$serviceMapping[$interfaceClass][$version][$methodName] = [$className, $methodName];
                }
            }

            return;
        }
    }
532958
public static function setPropertyValue($object,$propertyName,$value)
    {
        $setter = "set" . ucfirst($propertyName);
        if (method_exists($object, $setter)) {
            $object->$setter($value);
        }
    }
323259
public function afterInitialize(Event $event, ModelsManager $manager, $model)
    {
        //Reflector
        /** @var \Phalcon\Annotations\Reflection $reflector */
        $reflector = $this->annotations->get($model);
        /**
         * Read the annotations in the class' docblock
         */
        $annotations = $reflector->getClassAnnotations();
        if ($annotations) {
            /**
             * Traverse the annotations
             */
            foreach ($annotations as $annotation) {
                switch ($annotation->getName()) {
                    /**
                     * Initializes the model's source
                     */
                    case 'Source':
                        $arguments = $annotation->getArguments();
                        $model->setConnectionService($arguments[0]);
                        $manager->setModelSource($model, $arguments[1]);
                        break;
                    /**
                     * Initializes Has-Many relations
                     */
                    case 'HasMany':
                        $arguments = $annotation->getArguments();
                        if (!isset($arguments[3])) {
                            $arguments[3] = null;
                        }
                        $manager->addHasMany($model, $arguments[0], $arguments[1], $arguments[2], $arguments[3]);
                        break;
                    /**
                     * Initializes Has-Many-To-Many relations
                     */
                    case 'HasManyToMany':
                        $arguments = $annotation->getArguments();
                        if (!isset($arguments[6])) {
                            $arguments[6] = null;
                        }
                        $manager->addHasManyToMany($model, $arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6]);
                        break;
                    /**
                     * Initializes Has-One relations
                     */
                    case 'HasOne':
                        $arguments = $annotation->getArguments();
                        if (!isset($arguments[3])) {
                            $arguments[3] = null;
                        }
                        $manager->addHasOne($model, $arguments[0], $arguments[1], $arguments[2], $arguments[3]);
                        break;
                    /**
                     * Initializes Has-Many relations
                     */
                    case 'BelongsTo':
                        $arguments = $annotation->getArguments();
                        if (!isset($arguments[3])) {
                            $arguments[3] = null;
                        }
                        $manager->addBelongsTo($model, $arguments[0], $arguments[1], $arguments[2], $arguments[3]);
                        break;
                }
            }
        }
    }