Разрешает и возвращает цепочку связанных полей по указанному пути
@param string $fieldPath путь (Ex: order.owner.name)
@throws InvalidArgumentException
@return array массив вида [[IField $field, string $collectionAlias, ICollection $fieldCollection], ...]
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;
    }
895095
public function getField($fieldName) {
        if(empty($fieldName)) {
            throw new \InvalidArgumentException('Please provide a fieldname');
        }
        
        $values = array();
        foreach($this->fields as $field) {
            if($field['name'] == $fieldName) {
                $values[] = $field['value'];
            }
        }
        
        return $values;
    }
505757
protected function getArrayAndKeyName(string $fieldName, string $key): array
    {
        if (!in_array($key, ['filters', 'sorts'], true)) {
            throw new InvalidArgumentException('Key must be one of [filters, sorts]');
        }
        if (str_contains($fieldName, '.')) {
            $path         = explode('.', $fieldName);
            $name         = array_pop($path);
            $relationPath = implode('.', $path);
            $array        = array_get($this->relations, "$relationPath.$key", []);
        } else {
            $name  = $fieldName;
            $array = ($key === 'filters') ? $this->filters : $this->sorts;
        }
        return [$name, $array];
    }
318967
public function getOptionForValue($value) : IFieldOption
    {
        if ($this->specificFieldOptionLoader) {
            $fieldOption = call_user_func($this->specificFieldOptionLoader, $value);

            if (!$fieldOption) {
                throw InvalidArgumentException::format('Invalid option supplied to %s: %s', __METHOD__, $value);
            }

            return $fieldOption;
        }

        return (new ArrayFieldOptions(call_user_func($this->fieldOptionsLoader)))->getOptionForValue($value);
    }
762159
public function getStrategy($basePath, $settings = [])
    {
        if (isset($settings['combineRecords']) && $settings['combineRecords']) {
            $combineTag = $settings['combineRecordsTag'] ?? null;
            return new CombinedRecordWriterStrategy($basePath, $combineTag);
        }
        return new IndividualRecordWriterStrategy($basePath);
    }
477377
public function defaults($basePath = null)
    {
        $defaults = [];
        foreach ($this->_columns as $key => $value) {
            if ($basePath) {
                $fieldName = strpos($key, $basePath . '.') === 0 ? substr($key, strlen($basePath) + 1) : null;
            } else {
                $fieldName = $key;
            }
            if (!$fieldName || $fieldName === '*' || strpos($fieldName, '.') !== false) {
                continue;
            }
            if (isset($value['default'])) {
                $defaults[$fieldName] = $value['default'];
            }
        }
        return $defaults;
    }
699601
protected function resolveRelatedField($model, $fieldPath)
    {
        $path = explode('.', $fieldPath);
        $field = array_pop($path);
        $class = $model;

        foreach ($path as $part) {
            $metadata = $this->getMetadatas($class);

            if (!$metadata->hasAssociation($part)) {
                throw new \LogicException('Field "'.$part.'" for class "'.$class.'" is not an association.');
            }

            $class = $metadata->getAssociationTargetClass($part);
        }

        return array(
            'field' => $field,
            'class' => $class
        );
    }
241750
protected function addIndicesToFields(DOMXPath $rootPath)
    {
        $fetchedNodes = [];
        $fields = $this->getFields();
        $multipleIndices = [];
        $idMap = array_flip(
            array_map(
                function (MigrationField $field) {
                    return $field->getId();
                },
                $fields
            )
        );

        /** @var MigrationField $field */
        foreach ($fields as $name => $field) {
            $usedId = $field->getId();
            $indexNodes = $rootPath->query(
                './value[@content-struct-name="db.mysql.Index" and @key="indices"]/' .
                'value[@type="object" and @struct-name="db.mysql.Index"]//' .
                'value[@type="object" and @struct-name="db.mysql.IndexColumn"]//' .
                'link[@type="object" and @struct-name="db.Column" and @key="referencedColumn" ' .
                'and text() = "' . $usedId . '"]/' .
                '../' .
                '../' .
                '..'
            );

            if ($indexNodes && $indexNodes->length) {
                $fks = $this->getForeignKeysForField($field, $rootPath);

                /** @var \DOMNode $indexNode */
                foreach ($indexNodes as $indexNode) {
                    if (in_array($nodeId = $indexNode->attributes->getNamedItem('id')->nodeValue, $fetchedNodes)) {
                        continue;
                    } // if

                    $fetchedNodes[] = $nodeId;

                    $indexColumns = $rootPath->query(
                        './/link[@type="object" and @struct-name="db.Column" and @key="referencedColumn"]',
                        $indexNode
                    );

                    $isSingleColumn = $indexColumns && $indexColumns->length <= 1;
                    $genericCall = !$isSingleColumn ? new Base() : null;

                    if ($rootPath->evaluate(
                        'boolean(./value[@type="int" and @key="unique" and number() = 1])',
                        $indexNode
                    )
                    ) {
                        if ($isSingleColumn) {
                            $field->addAdditionalOption('unique');
                        } // if
                        else {
                            $genericMethod = 'unique';
                        } // else
                    } // if

                    $hasIndex = $rootPath->evaluate(
                        'boolean(./value[@type="string" and @key="indexType" and text() = "INDEX"])',
                        $indexNode
                    );

                    if ($hasIndex && (!$fks || !$fks->length)) {
                        if ($isSingleColumn) {
                            $field->addAdditionalOption('index');
                        } // if
                        else {
                            $genericMethod = 'index';
                        } // else
                    } // if

                    if ($rootPath->evaluate(
                        'boolean(./value[@type="string" and @key="indexType" and text() = "PRIMARY"])',
                        $indexNode
                    )
                    ) {
                        if ($isSingleColumn) {
                            $field->addAdditionalOption('primary');
                        } // if
                        else {
                            $genericMethod = 'primary';
                        } // else
                    } // if

                    if ($genericCall && $genericMethod) {
                        $genericParams = [];
                        /** @var DOMNode $column */
                        foreach ($indexColumns as $column) {
                            $genericParams[] = $idMap[$column->nodeValue];
                        } // foreach

                        $this->addGenericCall(call_user_func_array(
                            [$genericCall, $genericMethod],
                            $genericParams ? [$genericParams] : []
                        ));
                    }
                }
            }
        }

        return array_unique($multipleIndices);
    }
686499
private function getOperators($dataClass, $propertyPath)
    {
        $metadata = $this->registry->getManagerForClass($dataClass)->getClassMetadata($dataClass);

        if (false === strpos($propertyPath, '.')) {
            if ($metadata->hasAssociation($propertyPath)) {
                if ($metadata->isCollectionValuedAssociation($propertyPath)) {
                    return [
                        FilterOperator::MEMBER,
                        FilterOperator::NOT_MEMBER,
                    ];
                } else {
                    return [
                        FilterOperator::IN,
                        FilterOperator::NOT_IN,
                    ];
                }
            }
        } else {
            $paths = explode('.', $propertyPath);
            $path = array_shift($paths);

            if ($metadata->hasAssociation($path)) {
                return $this->getOperators(
                    $metadata->getAssociationTargetClass($path),
                    implode('.', $paths)
                );
            }
        }

        throw new InvalidArgumentException("Invalid property path '{$propertyPath}'.");
    }
111377
public function load(string $templatePath): TemplateInterface
    {
        $path = $this->resolveCachedTemplatePath($templatePath);
        $class = $this->generateTemplateCacheClass($path);

        return $this->compileAndSaveTemplate(
            $this->finder->getContents($path),
            $this->resolveCacheTemplatePath($class),
            $class
        );
    }
302849
final function FieldMapper($name)
    {
        $fieldMappers = $this->FieldMappers();
        if (!array_key_exists($name, $fieldMappers))
            throw new \InvalidArgumentException($name . ' is not a field of ' . $this->TableName());
        
        return $fieldMappers[$name];
    }
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';
    }
1095919
public function select(array $fields)
    {
        if (empty($fields)) {
            throw new InvalidArgumentException('The field array must not be' .
                ' empty.');
        }

        foreach ($fields as $field) {
            $validationResult = QueryValidator::validateFieldName($field);
            if ($validationResult->isFailed()) {
                throw new InvalidArgumentException('The field array for' .
                    ' building the SELECT clause contains invalid field name.' .
                    ' Validation fail reason: ' .
                    $validationResult->getFailReason());
            }
        }

        // Flipping an array will create a new associative array. The keys of
        // the new associative array make a set of distinct fields.
        $distinctFields = array_flip($fields);
        $this->selectFields = array_keys($distinctFields);
    }
1339059
private function serializeFormValidationRules(string $formsValPath): array
    {
        $serializer = new FormRulesSerializer(new BlockSerializer());

        foreach ($this->selectClasses($formsValPath, FormRulesInterface::class) as $rulesClass) {
            $serializer->addRulesFromClass($rulesClass);
        }

        return $serializer->getData();
    }
1083008
public function rule($rule, $field)
    {
        $ruleMethod = 'is' . ucfirst($rule);
        if (!isset(static::$rules[$rule]) && !method_exists($this, $ruleMethod)) {
            throw new \InvalidArgumentException(Lang::get('_NOT_FOUND_', 'validate rule [' . $rule . ']'));
        }

        $params = array_slice(func_get_args(), 2);

        $this->dateBindRule[] = [
            'rule' => $rule,
            'field' => (array)$field,
            'params' => (array)$params
        ];
        return $this;
    }
319492
public function validateMountPath($inputPath, array $mounts)
    {
        $normalized = $this->normalizeRelativePath($inputPath);
        if (isset($mounts[$normalized])) {
            return $normalized;
        }

        throw new \InvalidArgumentException(sprintf('Mount not found: <error>%s</error>', $inputPath));
    }
636032
public function resolveGenericTypes() : array
    {
        if (!$this->isCollection()) {
            throw InvalidArgumentException::create("Can't resolve collection type on non collection");
        }

        preg_match(self::COLLECTION_TYPE_REGEX, $this->type, $match);

        return [TypeDescriptor::create(trim($match[1]))];
    }