Prepares bulk data to store in elasticsearch index for model properties eav values

@param HasProperties | PropertiesTrait $model
@param array $props
@param string $index
@param string $type
@param array $languages
@return array
10387
private static function prepareEav($model, $props, $index, $type, $languages)
    {
        $eavTable = $model->eavTable();
        $values = (new Query())
            ->from($eavTable)
            ->where([
                'model_id' => $model->id,
                'property_id' => array_keys($props)
            ])
            ->select([
                'id',
                'property_id',
                'value_integer',
                'value_float',
                'value_string',
                'value_text',
                'language_id'
            ])
            ->all();
        $rows = $data = [];
        foreach ($values as $val) {
            $propKey = isset($props[$val['property_id']]) ? $props[$val['property_id']] : null;
            $row = [
                'eav_value_id' => $val['id'],
                'prop_id' => $val['property_id'],
                'prop_key' => $propKey,
                'value_integer' => $val['value_integer'],
                'value_float' => $val['value_float'],
            ];
            if ($val['language_id'] == 0) {
                $row['utr_text'] = $val['value_text'];
            } else {
                if (false === isset($languages[$val['language_id']])) {
                    continue;
                }
                $row['str_value_' . $languages[$val['language_id']]] = $val['value_string'];
                $row['txt_value_' . $languages[$val['language_id']]] = $val['value_text'];
            }
            $rows[] = $row;
        }
        if (false === empty($rows)) {
            $data['body'][] = ['index' => [
                '_id' => $model->id,
                '_index' => $index,
                '_type' => $type,
            ]];
            $data['body'][] = [
                'model_id' => $model->id,
                Search::EAV_FIELD => $rows,
            ];
        }
        return $data;
    }
161845
public void sendWithBulkProcessor(List<? extends Map<String, ?>> bulkSource,
            String index, String type) {
        sendWithBulkProcessor(bulkSource.stream().map(
                source -> buildIndexRequest(index, type, null).source(source))
                .collect(toList()));
    }
347554
public static function isAttributeProperty(array &$mappings, $propertyName, $type)
    {
        return Serializer::CLASS_IDENTIFIER_KEY !== $propertyName
        && !in_array($propertyName, RecursiveFormatterHelper::getIdProperties($mappings, $type));
    }
1314150
public function setRequiredPropertyTypes(string $property, $types)
    {
        $this->required[$property] = $types;
        $this->requiredTypes[$property] = $types;

        return $this;
    }
37263
public function getProperties(array $props = array())
    {
        if (empty($props)) {
            return $this->properties;
        }

        $properties = [];
        foreach ($props as $key) {
            $properties[$key] = isset($this->properties[$key]) ? $this->properties[$key] : null;
        }

        return $properties;
    }
1352740
protected function fillForModel($index, $model)
    {
        if (false === empty($model->propertiesIds) && false === empty($model->propertiesValues)) {
            //leave only not empty properties
            $workingProps = array_filter($model->propertiesValues, function ($e) {
                if (true === is_array($e)) {
                    foreach ($e as $val) {
                        return (count($val) > 0 && false === empty($val[0]));
                    }
                } else {
                    return false === empty($e);
                }
            });
            //collecting storages
            $storage = (new Query())
                ->from(PropertyStorage::tableName())
                ->select('id')
                ->indexBy('class_name')
                ->column();
            //selecting all applicable properties to work with
            $rawProps = (new Query())->from(Property::tableName())
                ->select(['id', 'key', 'storage_id', 'data_type'])
                ->where([
                    'id' => array_keys($workingProps),
                    'in_search' => 1
                ])
                ->all();
            $props = ArrayHelper::map($rawProps, 'id', 'key', 'storage_id');
            foreach ($storage as $className => $id) {
                if (false === isset($props[$id]) || true === empty($props[$id])) {
                    continue;
                }
                $indexData = self::prepareIndexData($className, $props[$id], $workingProps, $index, $model);
                if (false === empty($indexData)) {
                    $this->client->bulk($indexData);
                }
            }
        }
    }
1100864
public function setType($types)
    {
        if (!is_array($types)) {
            $types = [$types];
        }

        $typesToSet = [];
        foreach ($types as $type) {
            if ($type === 'int') {
                $type = 'integer';
            }
            if ($type === 'hash') {
                $type = 'object';
            }

            // handle non-primitive types
            if (!in_array($type, $this->primitiveTypes)) {
                $setType = 'string';
                if (isset($this->specialTypeMapping[$type])) {
                    $setType = $this->specialTypeMapping[$type];
                }
                $typesToSet[] = $setType;

                if (isset($this->formatOverrides[$type])) {
                    $type = $this->formatOverrides[$type];
                }

                $this->setFormat($type);
            } else {
                $typesToSet[] = $type;
            }
        }

        $this->type = new SchemaType($typesToSet);
    }
703112
protected function __delete($index, $type, $id, array $parameters = []) {
        $result = $this->client->delete([
            'index' => $index,
            'type' => $type,
            'id' => $id] + $parameters);
        return $result;
    }
23134
protected function bindParameter(\PDOStatement $stmt, $params, $types)
    {
        !is_array($params) && $params = array($params);
        !is_array($types) && $types = array($types);

        $isIndex = is_int(key($params));
        $index = 1;

        foreach ($params as $name => $param) {
            // Number index parameters
            if ($isIndex) {
                if (isset($types[$index - 1])) {
                    $stmt->bindValue($index, $param, $types[$index - 1]);
                } else {
                    $stmt->bindValue($index, $param);
                }
                $index++;
            // Named parameters
            } else {
                if (isset($types[$name])) {
                    $stmt->bindValue($name, $param, $types[$name]);
                } else {
                    $stmt->bindValue($name, $param);
                }
            }
        }
    }
675095
public function buildMappingInformation(Index $index): MappingCollection
    {
        $this->lastMappingErrors = new Result();

        $mappings = new MappingCollection(MappingCollection::TYPE_ENTITY);

        /** @var NodeType $nodeType */
        foreach ($this->nodeTypeManager->getNodeTypes() as $nodeTypeName => $nodeType) {
            if ($nodeTypeName === 'unstructured' || $nodeType->isAbstract()) {
                continue;
            }

            $type = $index->findType($this->convertNodeTypeNameToMappingName($nodeTypeName));
            $mapping = new Mapping($type);
            $fullConfiguration = $nodeType->getFullConfiguration();
            if (isset($fullConfiguration['search']['elasticSearchMapping'])) {
                $fullMapping = $fullConfiguration['search']['elasticSearchMapping'];
                $this->migrateConfigurationForElasticVersion5($fullMapping);
                $mapping->setFullMapping($fullMapping);
            }

            // https://www.elastic.co/guide/en/elasticsearch/reference/5.4/dynamic-templates.html
            $mapping->addDynamicTemplate('dimensions', [
                'path_match' => '__dimensionCombinations.*',
                'match_mapping_type' => 'string',
                'mapping' => [
                    'type' => 'text'
                ]
            ]);
            $mapping->setPropertyByPath('__dimensionCombinationHash', [
                'type' => 'keyword'
            ]);

            foreach ($nodeType->getProperties() as $propertyName => $propertyConfiguration) {
                if (isset($propertyConfiguration['search']['elasticSearchMapping'])) {
                    if (is_array($propertyConfiguration['search']['elasticSearchMapping'])) {
                        $propertyMapping = $propertyConfiguration['search']['elasticSearchMapping'];
                        $this->migrateConfigurationForElasticVersion5($propertyMapping);
                        $mapping->setPropertyByPath($propertyName, $propertyMapping);
                    }
                } elseif (isset($propertyConfiguration['type'], $this->defaultConfigurationPerType[$propertyConfiguration['type']]['elasticSearchMapping'])) {
                    if (is_array($this->defaultConfigurationPerType[$propertyConfiguration['type']]['elasticSearchMapping'])) {
                        $mapping->setPropertyByPath($propertyName, $this->defaultConfigurationPerType[$propertyConfiguration['type']]['elasticSearchMapping']);
                    }
                } else {
                    $this->lastMappingErrors->addWarning(new Warning('Node Type "' . $nodeTypeName . '" - property "' . $propertyName . '": No ElasticSearch Mapping found.'));
                }
            }

            $mappings->add($mapping);
        }

        return $mappings;
    }
806982
private function getParameters($type, $index = null)
    {
        // If the type is invalid, return an empty array
        if ( ! in_array($type, ['dataset', 'messageset', 'ruleset'])) return [];

        return array_get($this->{$type}, $index, []);
    }
1230478
protected function getIndex($property, $index = null, $type = null) {
		//verify valid property
		if (!$this->wrappedArg->offsetExists($property))
			throw new \InvalidArgumentException("Unknown property '$property'");
	
		if (is_null($index))
			return $this->castParameter($this->wrappedArg->offsetGet($property), $type);
	
		//check if the value is null
		$value = $this->wrappedArg->offsetGet($property);
		if (is_null($value))
			throw new \InvalidArgumentException("Trying to obtain value from NULL property '$property'");
	
		//check value type
		if (is_array($value)) {
			//search for string index
			if (array_key_exists($index, $value))
				return $this->castParameter($value[$index], $type);
			//try numeric index instead
			elseif (is_numeric($index) && array_key_exists(intval($index), $value))
				return $this->castParameter($value[intval($index)], $type);
	
			throw new \InvalidArgumentException("Index '$index' does not exists in property '$property'");
		}
		//try to convert value to string
		elseif (($value = $this->toString($value)) !== false) {
			//check string length against index
			if ($index < strlen($value))
				return $this->castParameter($value[$index], $type);
	
			throw new \OutOfBoundsException("Index '$index' out of bounds for property '$property'");
		}
			
		throw new \InvalidArgumentException("Cannot obtain index '$index' from a non array/string property '$property'");
	}
846268
public static function bindGroupToModels(&$models, PropertyGroup $propertyGroup)
    {
        foreach ($models as &$model) {
            $model->ensurePropertyGroupIds();
            if (in_array($propertyGroup->id, $model->propertyGroupIds) === true) {
                // maybe it'll be better to throw special exception in such case
                return false;
            }

            $model->getDb()->createCommand()->insert(
                $model->bindedPropertyGroupsTable(),
                [
                    'model_id' => $model->id,
                    'property_group_id' => $propertyGroup->id,
                    'sort_order' => count($model->propertyGroupIds),
                ]
            )->execute();

            $model->propertyGroupIds[] = $propertyGroup->id;

            if ($model->propertiesAttributes !== null) {
                // if there were propertiesIds filled - refresh them
                $model->ensurePropertiesAttributes(true);
            }
            TagDependency::invalidate($model->getTagDependencyCacheComponent(), [$model->objectTag()]);
        }
        return true;
    }
752440
public static function buildFilterQuery($params, $index, $types)
    {
        self::filterInput($params);
        $storageToId = (new Query())
            ->from(PropertyStorage::tableName())
            ->select('class_name')
            ->where(['class_name' => array_keys($types)])
            ->indexBy('id')
            ->column();
        $propData = (new Query())
            ->from(Property::tableName())
            ->select(['id', 'data_type', 'storage_id'])
            ->where([
                'id' => array_keys($params),
                'storage_id' => array_keys($storageToId),
                'in_search' => 1
            ])
            ->indexBy('id')
            ->all();
        $query = ['bool' => ['must' => []]];
        $currentLang = LanguageHelper::getCurrent();
        foreach ($params as $propId => $values) {
            $q = ['bool' => ['should' => []]];
            switch ($storageToId[$propData[$propId]['storage_id']]) {
                case EAV::class :
                    foreach ($values as $val) {
                        $q['bool']['should'][] = [
                            'bool' => ['must' => [['term' => [self::STATIC_VALUES_FILED . '.prop_id' => $propId]],
                                ['term' => [self::STATIC_VALUES_FILED . '.value_' . $currentLang . '.raw' => $val]]]]
                        ];
                    }
                    break;
                case StaticValues::class :
                    foreach ($values as $val) {
                        $q['bool']['should'][] = [
                            'bool' => ['must' => [['term' => [self::STATIC_VALUES_FILED . '.prop_id' => $propId]],
                                ['term' => [self::STATIC_VALUES_FILED . '.static_value_id' => $val]]]]
                        ];
                    }
                    break;
            }
            $query['bool']['must'][] = $q;
        }
        //will search against all types in given index by default
        return $a = [
            'index' => $index,
            'body' => [
                'query' => [
                    'constant_score' => [
                        'filter' => $query
                    ]
                ]
            ]
        ];
    }
127738
private function prepareComponentList (array $types)
    {
        $this->types = [];

        foreach ($types as $type)
        {
            $this->types[$type->getKey()] = $type;
        }
    }
1223198
public function updateTranslations($params, $type)
    {
        if (is_null($translations = array_get($params, 'name'))) {
            return false;
        }
        try {
            DB::transaction(function() use($translations, $type) {
                foreach ($translations as $id => $value) {
                    $where        = [
                        'id'   => $id,
                        'area' => $type
                    ];
                    $model        = $this->makeModel()->newQuery()->where($where)->first();
                    $model->value = $value;
                    $model->save();
                }
            });
            return true;
        } catch (Exception $ex) {
            Log::emergency($ex);
            return false;
        }
    }
512899
protected function forgetIndexType($type, $givenKeys)
    {
        $this->setKeywordsOperation(true);

        $givenKeys = is_array($givenKeys) ? $givenKeys : func_get_args();

        switch ($type) {
            case 'inverse':
                $getKeyCallback = function ($givenKey) {
                    return $this->generateInverseIndexKey($givenKey);
                };
                break;
            case 'keyword':
            default:
                $getKeyCallback = function ($givenKey) {
                    return $this->generateIndexKey($givenKey);
                };
                break;
        }

        $affected = [];
        foreach ($givenKeys as $givenKey) {
            $affected = array_merge($affected, parent::pull(call_user_func($getKeyCallback, $givenKey), []));
        }

        $this->setKeywordsOperation(false);

        return array_unique($affected);
    }