Future feature. This method have ability to use combined extended search & filter form
TODO implement

@codeCoverageIgnore

@param string $modelClass
@param array $config
@param array $params
@param bool $intersect
@return array
548102
final private function extendedFilter($modelClass = '', $config = [], $params = [], $intersect = false)
    {
        //перечсечение: внутри свойства ИЛИ между свойствами И
        //объединение: везде ИЛИ
        $index = IndexHelper::classToIndex($modelClass);
        if (true === empty($index)) {
            return [];
        }
        $types = self::prepareTypes($config);
        $storageToId = (new Query())
            ->from(PropertyStorage::tableName())
            ->select('id')
            ->where(['class_name' => array_keys($types)])
            ->indexBy('class_name')
            ->column();
        $eavQuery = [];
        foreach ($types as $storageClass => $type) {
            switch ($storageClass) {
                case StaticValues::class :
                    //TODO include filter query against static values
                    break;
                case EAV::class :
                    //TODO refactor
                    $propData = (new Query())
                        ->from(Property::tableName())
                        ->select('data_type')
                        ->where([
                            'id' => array_keys($params),
                            'storage_id' => $storageToId[EAV::class]
                        ])
                        ->indexBy('id')
                        ->column();
                    $queryCondition = (true === $intersect) ? 'must' : 'should';
                    foreach ($params as $propId => $vals) {
                        if (false === isset($propData[$propId])) {
                            continue;
                        }
                        $vals = is_array($vals) ? $vals : [$vals];
                        //query between different props
                        $searchField = self::dataTypeToIndexField($propData[$propId]);
                        $match = [];
                        $isTranslatable = in_array(
                            $propData[$propId],
                            [Property::DATA_TYPE_STRING, Property::DATA_TYPE_TEXT]
                        );
                        foreach ($vals as $val) {
                            //query between values of one property
                            $fields = [
                                'query' => $val,
                                'operator' => 'and',
                            ];
                            if (true === $isTranslatable) {
                                $fields['type'] = 'phrase';
                            }
                            $match[] = ['match' => [self::EAV_FIELD . '.' . $searchField => $fields]];
                        }
                        $propQuery = ['bool' => ['should' => $match]];
                        $eavQuery['bool'][$queryCondition][] = $propQuery;
                    }
                    break;
            }
        }
        //TODO combine upper queries like im manual below
        /**
         * @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/_search_operations.html#_a_more_complicated_example
         */
        $a = [
            'index' => $index,
            'body' => [
                'query' => $eavQuery
            ]
        ];
        $res = IndexHelper::primaryKeysByCondition($this->client, $a);
        return array_keys($res);
    }
825847
public function createByParams( $params = [], $config = [] ) {

		$params[ 'active' ]	= CoreGlobal::STATUS_ACTIVE;

		return parent::createByParams( $params, $config );
	}
394059
public function getPage( $config = [] ) {

		$modelClass	= static::$modelClass;
		$modelTable	= $this->getModelTable();

		// Sorting ----------

		$sort = new Sort([
			'attributes' => [
				'id' => [
					'asc' => [ "$modelTable.id" => SORT_ASC ],
					'desc' => [ "$modelTable.id" => SORT_DESC ],
					'default' => SORT_DESC,
					'label' => 'Id'
				],
				'title' => [
					'asc' => [ "$modelTable.title" => SORT_ASC ],
					'desc' => [ "$modelTable.title" => SORT_DESC ],
					'default' => SORT_DESC,
					'label' => 'Title'
				],
				'type' => [
					'asc' => [ "$modelTable.type" => SORT_ASC ],
					'desc' => [ "$modelTable.type" => SORT_DESC ],
					'default' => SORT_DESC,
					'label' => 'Type'
				],
				'status' => [
					'asc' => [ "$modelTable.id" => SORT_ASC ],
					'desc' => [ "$modelTable.id" => SORT_DESC ],
					'default' => SORT_DESC,
					'label' => 'Status'
				],
				'total' => [
					'asc' => [ "$modelTable.grandTotal" => SORT_ASC ],
					'desc' => [ "$modelTable.grandTotal" => SORT_DESC ],
					'default' => SORT_DESC,
					'label' => 'Total'
				],
				'cdate' => [
					'asc' => [ "$modelTable.createdAt" => SORT_ASC ],
					'desc' => [ "$modelTable.createdAt" => SORT_DESC ],
					'default' => SORT_DESC,
					'label' => 'Created At'
				],
				'udate' => [
					'asc' => [ "$modelTable.modifiedAt" => SORT_ASC ],
					'desc' => [ "$modelTable.modifiedAt" => SORT_DESC ],
					'default' => SORT_DESC,
					'label' => 'Updated At'
				]
			],
			'defaultOrder' => [ 'cdate' => 'SORT_ASC' ]
		]);

		if( !isset( $config[ 'sort' ] ) ) {

			$config[ 'sort' ] = $sort;
		}

		// Query ------------

		if( !isset( $config[ 'query' ] ) ) {

			$config[ 'hasOne' ] = true;
		}

		// Filters ----------

		// Filter - Status
		$status	= Yii::$app->request->getQueryParam( 'status' );

		if( isset( $status ) ) {

			if( isset( $modelClass::$urlRevStatusMap[ $status ] ) ) {

				$config[ 'conditions' ][ "$modelTable.status" ] = $modelClass::$urlRevStatusMap[ $status ];
			}
		}

		// Searching --------

		$searchCol	= Yii::$app->request->getQueryParam( 'search' );

		if( isset( $searchCol ) ) {

			$search = [ 'title' => "$modelTable.title", 'description' => "$modelTable.description" ];

			$config[ 'search-col' ] = $search[ $searchCol ];
		}

		// Reporting --------

		$config[ 'report-col' ]	= [
			'title' => "$modelTable.title", 'description' => "$modelTable.description", 'content' => "$modelTable.content"
		];

		// Result -----------

		return parent::getPage( $config );
	}
1305322
public function getMatcherConfiguration($matcherClass)
    {
        if ( ! array_key_exists($matcherClass, $this->configuration["matcher_settings"])) {
            return null;
        }

        $configuration = $this->configuration["matcher_settings"][$matcherClass];

        unset($this->configuration["matcher_settings"][$matcherClass]);

        return $configuration;
    }
1308751
private static function addCustomFunctions(Configuration $config, array $options = array())
    {
        if (null !== $strFcts = Collection::get($options, 'orm:entity_managers:default:dql:string_functions')) {
            foreach ($strFcts as $name => $class) {
                if (class_exists($class)) {
                    $config->addCustomStringFunction($name, $class);
                }
            }
        }

        if (null !== $numFcts = Collection::get($options, 'orm:entity_managers:default:dql:numeric_functions')) {
            foreach ($numFcts as $name => $class) {
                if (class_exists($class)) {
                    $config->addCustomNumericFunction($name, $class);
                }
            }
        }

        if (null !== $datetimeFcts = Collection::get($options, 'orm:entity_managers:default:dql:datetime_functions')) {
            foreach ($datetimeFcts as $name => $class) {
                if (class_exists($class)) {
                    $config->addCustomDatetimeFunction($name, $class);
                }
            }
        }

        return $config;
    }
851004
public function createByParams( $params = [], $config = [] ) {

		$status			= isset( $params[ 'status' ] ) ? $params[ 'status' ] : Transaction::STATUS_NEW;
		$desc			= isset( $params[ 'description' ] ) ? $params[ 'description' ] : null;
		$code			= isset( $params[ 'code' ] ) ? $params[ 'code' ] : null;
		$processedAt	= isset( $params[ 'processedAt' ] ) ? $params[ 'processedAt' ] : null;
 		$data			= isset( $params[ 'data' ] ) ? $params[ 'data' ] : null;

		$transaction	= isset( $config[ 'transaction' ] ) ? $config[ 'transaction' ] : new Transaction();
 		$link			= isset( $params[ 'link' ] ) ? $params[ 'link' ] : null;
 		$userId			= isset( $params[ 'userId' ] ) ? $params[ 'userId' ] : null;

		// This condition is applies when we detach authorBehavior from transaction model, so in this case we need to set createdBy manually
		if( isset( $params[ 'createdBy' ] ) ) {

			$transaction->createdBy	= $params[ 'createdBy' ];
		}

		$modelClass	= new static::$modelClass;

		$ignoreSite	= $config[ 'ignoreSite' ] ?? false;

		if( $modelClass::isMultiSite() && !$ignoreSite ) {

			$transaction->siteId	= $config[ 'siteId' ] ?? Yii::$app->core->getSiteId();
		}

		// Mandatory
		$transaction->parentId		= $params[ 'parentId' ];
		$transaction->parentType	= $params[ 'parentType' ];
		$transaction->status		= $status;
		$transaction->type			= $params[ 'type' ];
		$transaction->mode			= $params[ 'mode' ];
		$transaction->amount		= $params[ 'amount' ];
		$transaction->currency		= $params[ 'currency' ];
		$transaction->title			= $params[ 'title' ];

		// Optional
		$transaction->description	= $desc;
		$transaction->code			= $code;
		$transaction->processedAt	= $processedAt;
		$transaction->data			= $data;
		$transaction->link			= $link;
		$transaction->userId		= $userId;

		$transaction->save();

		// Return Transaction
		return $transaction;
	}
714051
private function intersectModelSetParentId(ModelInterface $intersectModel, EnvironmentInterface $environment)
    {
        $dataDefinition       = $environment->getDataDefinition();
        $parentDataDefinition = $environment->getParentDataDefinition();

        if (null === $parentDataDefinition) {
            return;
        }

        $relationships  = $dataDefinition->getModelRelationshipDefinition();
        $childCondition =
            $relationships->getChildCondition($parentDataDefinition->getName(), $dataDefinition->getName());

        $parentField = null;
        foreach ($childCondition->getSetters() as $setter) {
            if (!\array_key_exists('to_field', $setter)) {
                continue;
            }

            $parentField = $setter['to_field'];
            break;
        }

        if (null !== $parentField) {
            $intersectModel->setProperty(
                $parentField,
                ModelId::fromSerialized($environment->getInputProvider()->getParameter('pid'))
                    ->getId()
            );
        }
    }
21282
protected function makeModelDisplayValueFromModelClass($modelClass)
    {
        $stripPrefix = config('cms-models.collector.models-namespace');

        if ($stripPrefix && starts_with($modelClass, $stripPrefix)) {
            $modelClass = trim(substr($modelClass, 0, strlen($stripPrefix)), '\\');
        }

        return ucfirst(str_replace('\\', ' ', $modelClass));
    }
85586
public static function dataModelByClass($modelClassBasename, $params = [], $config = [])
    {
        $thisModule = static::instance();

        $pathList = $thisModule->getBasePathList();
        $nsList = $thisModule->getNamespaceList();
        foreach ($pathList as $i => $basePath) {
            $modelPath = $basePath . DIRECTORY_SEPARATOR . static::$modelsSubdir . DIRECTORY_SEPARATOR . $modelClassBasename . '.php';
            if (is_file($modelPath)) {
                $modelFullName = $nsList[$i] . '\\' . static::$modelsSubdir . '\\' . $modelClassBasename;
                break;
            }
        }
        if (!empty($modelFullName)) {
            $model = Yii::createObject($modelFullName, $params);
            if ($model instanceof DataModel) {
                //$model->module = $this;
                //Yii::configure($model, ['module' => $this]);
                $config['module'] = $this;
                Yii::configure($model, $config);
                $model->prepare();
            }
            return $model;
        }
        return null;
    }
214897
private function fetchPaginatedResourcesWithoutRelationships(
        QueryBuilder $builder,
        string $modelClass
    ): PaginatedDataInterface {
        list($models, $hasMore, $limit, $offset) = $this->fetchResourceCollection($builder, $modelClass);

        $data = $this->getFactory()
            ->createPaginatedData($models)
            ->markAsCollection()
            ->setOffset($offset)
            ->setLimit($limit);

        $hasMore === true ? $data->markHasMoreItems() : $data->markHasNoMoreItems();

        return $data;
    }
1228934
private function resolveAssociations(Entity $config, ClassMetadata $metadata)
    {
        $associations = [];
        foreach ($metadata->getAssociationMappings() as $associationMapping) {
            $fieldName = $associationMapping['fieldName'];
            $fieldClass = array_filter($config->listFields(), function (ListField $field) use ($fieldName) {
                if (!isset($field->options()['field'])) {
                    return;
                }

                return $fieldName === explode('.', $field->options()['field'])[0];
            });

            if (count($fieldClass) > 0) {
                $associations[] = $fieldName;
            }
        }

        return $associations;
    }
141789
protected function determineTargetModelFromSource($modelClass, $source)
    {
        if ( ! is_a($modelClass, Model::class, true)) {
            // @codeCoverageIgnoreStart
            throw new UnexpectedValueException("{$modelClass} is not an Eloquent model");
            // @codeCoverageIgnoreEnd
        }

        $model = new $modelClass;

        if ( ! ($relation = $this->getNestedRelation($model, $source))) {
            // @codeCoverageIgnoreStart
            $relation = $this->resolveModelSource($model, $source);
            // @codeCoverageIgnoreEnd
        }

        if ( ! ($relation instanceof Relation)) {
            // @codeCoverageIgnoreStart
            throw new UnexpectedValueException(
                "Source {$source} on {$modelClass} does not resolve to an Eloquent relation instance"
            );
            // @codeCoverageIgnoreEnd
        }

        /** @var Relation $relation */
        return $relation->getRelated();
    }
289934
public function actionAll( $config = [] ) {

		$modelClass = $this->modelService->getModelClass();

		$dataProvider = $this->modelService->getPage();

		return $this->render( 'all', [
			'dataProvider' => $dataProvider,
			'statusMap' => $modelClass::$statusMap
		]);
	}
811467
public static function hasOne($modelClass, $columnName, $options = []) {
        $options['type'] = self::HAS_ONE;
        $options['modelClass'] = $modelClass;
        $options['compares'] = [["t.__PK__", (false === strpos($columnName, '.')) ? "r.$columnName" : $columnName, "="]];
        return new self($options);
    }
425734
public static function hasMany($modelClass, $columnName, $options = []) {
        $options['type'] = self::HAS_MANY;
        $options['modelClass'] = $modelClass;
        $options['compares'] = [["t.__PK__", (false === strpos($columnName, '.')) ? "r.$columnName" : $columnName, "="]];
        return new self($options);
    }
355876
public function paginateChildren($modelClass, $method, array $params = [])
    {
        // Set request params
        $params = array_filter(array_merge([
            'page' => 1
        ], $params));

        // Make request
        $result = $this->makeRequest($this->getEndpoint(), $method, [$this->getKey(), $params]);

        // Hydrate object
        $result = $this->paginateHydrate($result, $modelClass);

        // Append search params
        $result->appends($params);

        return $result;
    }
393298
protected function getValidationRulesForAttributes(array $modelParams, array $rules = []): array
    {
        $modelRules = empty($rules) ? $this->getValidationRules() : $rules;
        return array_intersect_key($modelRules, $modelParams);
    }