@param string $modelsPath

@return array

@SuppressWarnings(PHPMD.CyclomaticComplexity)

@throws ReflectionException
160536
private function getModelsSchemaInfo(string $modelsPath): array
    {
        // check reverse relationships
        $requireReverseRel = true;

        $registered    = [];
        $modelSchemas  = new ModelSchemaInfo();
        $registerModel = function ($modelClass) use ($modelSchemas, &$registered, $requireReverseRel) {
            /** @var ModelInterface $modelClass */
            $modelSchemas->registerClass(
                $modelClass,
                $modelClass::getTableName(),
                $modelClass::getPrimaryKeyName(),
                $modelClass::getAttributeTypes(),
                $modelClass::getAttributeLengths(),
                $modelClass::getRawAttributes()
            );

            $relationships = $modelClass::getRelationships();

            if (array_key_exists(RelationshipTypes::BELONGS_TO, $relationships) === true) {
                foreach ($relationships[RelationshipTypes::BELONGS_TO] as $relName => list($rClass, $fKey, $rRel)) {
                    /** @var string $rClass */
                    $modelSchemas->registerBelongsToOneRelationship($modelClass, $relName, $fKey, $rClass, $rRel);
                    $registered[(string)$modelClass][$relName] = true;
                    $registered[$rClass][$rRel]                = true;

                    // Sanity check. Every `belongs_to` should be paired with `has_many` on the other side.
                    /** @var ModelInterface $rClass */
                    $rRelationships   = $rClass::getRelationships();
                    $isRelationshipOk = $requireReverseRel === false ||
                        (isset($rRelationships[RelationshipTypes::HAS_MANY][$rRel]) === true &&
                            $rRelationships[RelationshipTypes::HAS_MANY][$rRel] === [$modelClass, $fKey, $relName]);
                    /** @var string $modelClass */

                    assert($isRelationshipOk, "`belongsTo` relationship `$relName` of class $modelClass " .
                        "should be paired with `hasMany` relationship.");
                }
            }

            if (array_key_exists(RelationshipTypes::HAS_MANY, $relationships) === true) {
                foreach ($relationships[RelationshipTypes::HAS_MANY] as $relName => list($rClass, $fKey, $rRel)) {
                    // Sanity check. Every `has_many` should be paired with `belongs_to` on the other side.
                    /** @var ModelInterface $rClass */
                    $rRelationships   = $rClass::getRelationships();
                    $isRelationshipOk = $requireReverseRel === false ||
                        (isset($rRelationships[RelationshipTypes::BELONGS_TO][$rRel]) === true &&
                            $rRelationships[RelationshipTypes::BELONGS_TO][$rRel] === [$modelClass, $fKey, $relName]);
                    /** @var string $modelClass */
                    assert($isRelationshipOk, "`hasMany` relationship `$relName` of class $modelClass " .
                        "should be paired with `belongsTo` relationship.");
                }
            }

            if (array_key_exists(RelationshipTypes::BELONGS_TO_MANY, $relationships) === true) {
                foreach ($relationships[RelationshipTypes::BELONGS_TO_MANY] as $relName => $data) {
                    if (isset($registered[(string)$modelClass][$relName]) === true) {
                        continue;
                    }
                    /** @var string $rClass */
                    list($rClass, $iTable, $fKeyPrimary, $fKeySecondary, $rRel) = $data;
                    $modelSchemas->registerBelongsToManyRelationship(
                        $modelClass,
                        $relName,
                        $iTable,
                        $fKeyPrimary,
                        $fKeySecondary,
                        $rClass,
                        $rRel
                    );
                    $registered[(string)$modelClass][$relName] = true;
                    $registered[$rClass][$rRel]                = true;
                }
            }
        };

        /** @noinspection PhpParamsInspection */
        $modelClasses = iterator_to_array($this->selectClasses($modelsPath, ModelInterface::class));
        array_map($registerModel, $modelClasses);

        $data = $modelSchemas->getData();

        return $data;
    }
128522
public function escapeFieldPath($fieldPath)
    {
        if ($fieldPath instanceof FieldPath) {
            $parts = $fieldPath->path();

            $out = [];
            foreach ($parts as $part) {
                $out[] = $this->escapePathPart($part);
            }

            $fieldPath = implode('.', $out);
        } else {
            if (!preg_match(self::VALID_FIELD_PATH, $fieldPath)) {
                throw new \InvalidArgumentException('Paths cannot be empty and must not contain `*~/[]\`.');
            }
        }

        $this->validateFieldPath($fieldPath);
        return $fieldPath;
    }
698221
private function getLinksByLinkNormalizationMappings(
        NormalizerContextInterface $context,
        array $normalizationLinkMappings,
        string $path,
        $object
    ): array {
        $links = [];
        foreach ($normalizationLinkMappings as $normalizationLinkMapping) {
            if (!$this->isWithinGroup($context, $normalizationLinkMapping)) {
                continue;
            }

            $linkNormalizer = $normalizationLinkMapping->getLinkNormalizer();

            if (null === $link = $linkNormalizer->normalizeLink($path, $object, $context)) {
                continue;
            }

            $links[$normalizationLinkMapping->getName()] = $link;
        }

        return $links;
    }
744856
public function getPrimaryKeyFor($model, $fieldPath)
    {
        $resolved = $this->resolveRelatedField($model, $fieldPath);
        $class = $resolved['class'];
        $field = $resolved['field'];

        $metadata = $this->getMetadatas($class);

        if ($metadata->hasAssociation($field)) {
            $class = $metadata->getAssociationTargetClass($field);
            $classIdentifiers = $this->getMetadatas($class)->getIdentifierFieldNames();

            // Short workaround for https://github.com/symfony2admingenerator/GeneratorBundle/issues/161
            // TODO: throw an exception to correctly handle that situation?
            return 1 == count($classIdentifiers) ? $classIdentifiers[0] : null;
        }

        // if the leaf node is not an association
        return null;
    }
546765
public static function getNamespace($classPath)
    {
        $src = file_get_contents($classPath);

        if (preg_match('/namespace\s+(.+?);/', $src, $m)) {
            return $m[1];
        }

        return null;
    }
995389
protected function loadMigrationFields(DOMXPath $rootPath)
    {
        $fields = $rootPath->query(
            './value[@type="list" and @key="columns"]/value[@type="object" and @struct-name="db.mysql.Column"]'
        );

        if ($fields && $fields->length) {
            /** @var \DOMNode $field */
            foreach ($fields as $field) {
                $fieldName = $rootPath->query('./value[@key="name"]', $field)->item(0)->nodeValue;

                $this->addField($fieldName)->load($field, $rootPath);
            } // foreach
        } // if

        $this->addIndicesToFields($rootPath);

        return $this->addForeignKeys($rootPath);
    }
198665
protected function resolveFieldChain($fieldPath)
    {
        if (isset($this->resolvedFieldChains[$fieldPath])) {
            return $this->resolvedFieldChains[$fieldPath];
        }

        $result = [];
        $pathInfo = explode(self::FIELD_SEPARATOR, $fieldPath);

        $latestCollection = $this->collection;
        $fieldSourceAlias = $this->collection->getSourceAlias();

        for ($i = 0; $i < count($pathInfo); $i++) {
            $fieldName = $pathInfo[$i];

            /**
             * @var IMetadata $metadata
             */
            $metadata = $latestCollection->getMetadata();
            if (!$metadata->getFieldExists($fieldName)) {
                throw new InvalidArgumentException($this->translate(
                    'Cannot resolve field path "{path}". Field "{name}" does not exist in "{metadata}".',
                    ["path" => $fieldPath, "name" => $fieldName, "metadata" => $metadata->getCollectionName()]
                ));
            }

            $field = $metadata->getField($fieldName);
            $result[] = [$field, $fieldSourceAlias, $latestCollection];

            if ($i == 0) {
                $this->usedFields[$field->getName()] = $field;
            }

            if ($field instanceof IRelationField) {
                $latestCollection = $field->getTargetCollection();
                $fieldSourceAlias .= self::ALIAS_SEPARATOR . $fieldName;

                if (!isset($pathInfo[$i + 1])) {
                    $latestCollectionIdField = $latestCollection->getIdentifyField();
                    $result[] = [$latestCollectionIdField, $fieldSourceAlias, $latestCollection];
                }
            } elseif (isset($pathInfo[$i + 1])) {
                throw new InvalidArgumentException($this->translate(
                    'Cannot resolve field path "{path}". Field "{name}" is not relation.',
                    ["path" => $fieldPath, "name" => $field->getName()]
                ));
            }
        }

        return $this->resolvedFieldChains[$fieldPath] = $result;
    }
1016379
public function getIterator($models = [], $requestedClassPath = '')
    {
        $possiblePath = '';
        if ($requestedClassPath) {
            $possiblePath = $this->iteratorFactory->getDefaultNamespaceAbs($requestedClassPath);
            if (!class_exists($possiblePath)) {
                throw new \Exception("Unable to find iterator '$possiblePath'");
            }
        } else {
            try {
                $possiblePath = $this->iteratorFactory->getDefaultNamespaceAbs('Model\\' . $this->getRelativeClassName());
            } catch (\Exception $e) {
            }
        }
        if (class_exists($possiblePath)) {
            $chosenPath = $possiblePath;
        } else {
            $chosenPath = '\\Mwyatt\\Core\\Iterator\\Model';
        }
        rtrim($chosenPath, '\\');
        return new $chosenPath($models);
    }
1197269
protected function buildExtendsModelConfig(
        string $modelName,
        array $fieldsConfig
    ): array {
        $modelExtendsName = Property::getString(
            $this->fieldsModelExtendsConfig,
            $modelName
        );

        if (empty($modelExtendsName)) {
            return [];
        }

        $extendsModelConfig = Property::getArray(
            $this->fieldsModelFieldsConfig,
            $modelExtendsName,
            []
        );

        return array_merge(
            $extendsModelConfig,
            $fieldsConfig
        );
    }
133309
public function getDbType($model, $fieldPath)
    {
        $resolved = $this->resolveRelatedField($model, $fieldPath);
        $class = $resolved['class'];
        $field = $resolved['field'];

        $relation = $this->getRelation($field, $class);

        if ($relation) {
            return \RelationMap::MANY_TO_ONE === $relation->getType() ? 'model' : 'collection';
        }

        $column = $this->getColumn($class, $field);

        return $column ? $column->getType() : 'virtual';
    }
1209713
public static function mapPath($virtualPath = null) {
        if (empty($virtualPath)) {
            return PHPMVC_ROOT_PATH;
        }

        if ($virtualPath[0] == '~' || $virtualPath[0] == '/') {
            $result = PHPMVC_ROOT_PATH;
            $result .= trim(substr($virtualPath, 1, strlen($virtualPath) - 1), '\\/');
        }
        elseif ($virtualPath[0] == '.') {
            $result = realpath(PHPMVC_ROOT_PATH . $virtualPath);
        }
        else {
            $result = PHPMVC_ROOT_PATH . $virtualPath;
        }

        return self::normalizePathSeparators($result);
    }
1078631
public function predictPath($path, $modelType, $language = null)
    {
        if (!file_exists($path)) {
            throw new FileNotFoundException($path);
        }

        return $this->predict(
            [
                'base64' => base64_encode(file_get_contents($path)),
            ],
            $modelType,
            $language
        );
    }
847813
public static function getValueFromPath($objectOrArray, $propertyPath, $throwIfNotFound = false)
    {
        if(null !== $value = self::getValue($objectOrArray, $propertyPath)) {
            return $value;
        }

        $paths = explode('.', $propertyPath);
        $lastPath = array_pop($paths);

        $pathReady = [];
        foreach ($paths as $path) {
            $pathReady[] = $path;

            $objectOrArray = self::getValue($objectOrArray, $path);

            if (null === $objectOrArray || is_scalar($objectOrArray)) {
                if ($throwIfNotFound) {
                    throw new \Exception(sprintf('path not found: %s', implode('.', $pathReady)));
                }

                return null;
            }
        }

        return self::getValue($objectOrArray, $lastPath);
    }
584968
private function getFieldsByFieldNormalizationMappings(
        NormalizerContextInterface $context,
        array $normalizationFieldMappings,
        string $path,
        $object
    ): array {
        $data = [];
        foreach ($normalizationFieldMappings as $normalizationFieldMapping) {
            if (!$this->isWithinGroup($context, $normalizationFieldMapping)) {
                continue;
            }

            $fieldNormalizer = $normalizationFieldMapping->getFieldNormalizer();

            $name = $normalizationFieldMapping->getName();

            $subPath = $this->getSubPathByName($path, $name);

            $this->logger->info('serialize: path {path}', ['path' => $subPath]);

            $data[$name] = $fieldNormalizer->normalizeField($subPath, $object, $context, $this);
        }

        return $data;
    }
1215959
public function getRequireArray($requestPath, array $getData = [])
    {
        $responseData = $this->get($requestPath, $getData);

        return self::requireArray($responseData);
    }
524074
protected function readModelsData(string $modelClass, int $limit = null): array
    {
        return $this->readTableData($this->getModelSchemas()->getTable($modelClass), $limit);
    }
500746
public function mapTree( $modelList )
	{
		$tree = $modelList instanceof Arrayable ? $modelList->toArray() : $modelList;

		$affectedKeys = [];

		$result = $this->mapTreeRecursive( $tree, $this->model->getKey(), $affectedKeys );

		if ( $result && count( $affectedKeys ) > 0 )
			$this->deleteUnaffected( $affectedKeys );

		return $result;
	}