• Модуль: crm
  • Путь к файлу: ~/bitrix/modules/crm/lib/synchronization/userfieldsynchronizer.php
  • Класс: Bitrix\Crm\Synchronization\UserFieldSynchronizer
  • Вызов: UserFieldSynchronizer::synchronize
static function synchronize($srcEntityTypeID, $dstEntityTypeID, $languageID = '', $filter = array(), array $options = array())
{
	/** @var \CMain $APPLICATION */
	global $APPLICATION;

	$synchronizedFieldNameMap = array();
	$entity = new \CUserTypeEntity();

	$isRecycling = (isset($options['IS_RECYCLING']) && $options['IS_RECYCLING'] === true);

	if(isset($options['ENABLE_TRIM']) && $options['ENABLE_TRIM'] === true)
	{
		$fieldsToDelete = self::getSynchronizationFields(
			$dstEntityTypeID,
			$srcEntityTypeID,
			$languageID,
			true,
			$isRecycling
		);
		foreach($fieldsToDelete as $field)
		{
			if(self::isUserFieldTypeSupported($field['USER_TYPE_ID']))
			{
				$entity->Delete($field['ID']);
			}
		}
	}

	$entityID = \CCrmOwnerType::ResolveUserFieldEntityID($dstEntityTypeID);
	$fieldsToCreateDraft = self::getSynchronizationFields(
		$srcEntityTypeID,
		$dstEntityTypeID,
		$languageID,
		true,
		$isRecycling
	);
	$labelMap = [];
	foreach ($fieldsToCreateDraft as $index => $field)
	{
		$label = self::getFieldComplianceCode($field);
		if($label !== '' && !isset($labelMap[$label]))
		{
			$labelMap[$label] = $index;
		}
	}
	$fieldsToCreate = [];
	foreach ($labelMap as $index)
	{
		$fieldsToCreate[] = $fieldsToCreateDraft[$index];
	}
	unset($fieldsToCreateDraft);

	if(isset($filter['FIELD_NAME']))
	{
		$filter['FIELD_NAME'] = is_array($filter['FIELD_NAME']) ? $filter['FIELD_NAME'] : array($filter['FIELD_NAME']);
		foreach(self::$existedFieldNameMap as $existedSrcFieldName => $existedDstFieldName)
		{
			if(!in_array($existedSrcFieldName, $filter['FIELD_NAME']))
			{
				unset(self::$existedFieldNameMap[$existedSrcFieldName]);
			}
		}
	}

	foreach($fieldsToCreate as $field)
	{
		$srcField = $entity->GetByID($field['ID']);
		if(!is_array($srcField))
		{
			continue;
		}

		$typeID = $srcField['USER_TYPE_ID'];
		if(!self::isUserFieldTypeSupported($typeID))
		{
			continue;
		}

		if(isset($filter['FIELD_NAME']))
		{
			if(!in_array($srcField['FIELD_NAME'], $filter['FIELD_NAME']))
			{
				continue;
			}
		}

		do
		{
			$fieldName = 'UF_CRM_'.mb_strtoupper(uniqid());
			$dbResult = $entity->GetList(
				array(),
				array('ENTITY_ID' => $entityID, 'FIELD_NAME' => $fieldName)
			);
		}
		while(is_array($dbResult->Fetch()));

		$dstField = array(
			'FIELD_NAME' => $fieldName,
			'ENTITY_ID' => $entityID,
			'USER_TYPE_ID' => $typeID,
			'SORT' => $srcField['SORT'] ?? 100,
			'MULTIPLE' => $srcField['MULTIPLE'] ?? 'N',
			'MANDATORY' => $srcField['MANDATORY'] ?? 'N',
			'SHOW_FILTER' => $srcField['SHOW_FILTER'] ?? 'N',
			'SHOW_IN_LIST' => $srcField['SHOW_IN_LIST'] ?? 'N'
		);

		if(isset($srcField['SETTINGS']))
		{
			$dstField['SETTINGS'] = $srcField['SETTINGS'];
		}

		if(isset($srcField['EDIT_FORM_LABEL']))
		{
			$dstField['EDIT_FORM_LABEL'] = $srcField['EDIT_FORM_LABEL'];
		}

		if(isset($srcField['LIST_COLUMN_LABEL']))
		{
			$dstField['LIST_COLUMN_LABEL'] = $srcField['LIST_COLUMN_LABEL'];
		}

		if(isset($srcField['LIST_FILTER_LABEL']))
		{
			$dstField['LIST_FILTER_LABEL'] = $srcField['LIST_FILTER_LABEL'];
		}

		$ID = $entity->Add($dstField);
		if($ID === false)
		{
			$ex = $APPLICATION->GetException();
			if(!($ex instanceof \CApplicationException))
			{
				$ex = null;
			}

			throw new UserFieldSynchronizationException(
				$dstField,
				$ex,
				UserFieldSynchronizationException::CREATE_FAILED,
				__FILE__,
				__LINE__
			);
		}

		//region UserField visible access settings
		$visibilityConfig = self::getInstance()
			->prepareEntityFieldvisibilityConfigs($srcEntityTypeID);
		if (isset($visibilityConfig[$srcField['FIELD_NAME']]))
		{
			$accessCodesKeys = array_keys($visibilityConfig[$srcField['FIELD_NAME']]['accessCodes'] ?? []);
			$accessCodes = array_map(
				static function($accessCode){
					return ['ID' => $accessCode];
				}, $accessCodesKeys
			);
			VisibilityManager::saveEntityConfiguration(
				$accessCodes,
				$dstField['FIELD_NAME'],
				$dstEntityTypeID,
				PermissionDictionary::USER_FIELD_VIEW
				);
		}
		// endregion

		if($typeID === 'enumeration')
		{
			if (is_callable(array($field['USER_TYPE']['CLASS_NAME'], 'GetList')))
			{
				$enumList = array();
				$enumQty = 0;
				$enumResult = call_user_func_array(array($field['USER_TYPE']['CLASS_NAME'], 'GetList'), array($field));
				while($enum = $enumResult->Fetch())
				{
					unset($enum['ID']);
					$enumList["n{$enumQty}"] = $enum;
					$enumQty++;
				}

				$enumEntity = new \CUserFieldEnum();
				$enumEntity->SetEnumValues($ID, $enumList);
			}
		}

		$synchronizedFieldNameMap[$srcField['FIELD_NAME']] = $fieldName;
	}

	//remove this branch if proper bugfix exists and this workaround is no longer needed
	if (!empty($fieldsToCreate) || !empty($fieldsToDelete))
	{
		$dstFactory = Container::getInstance()->getFactory((int)$dstEntityTypeID);
		if ($dstFactory)
		{
			$dstDataClass = $dstFactory->getDataClass();

			//rebuild entity so that new user fields are added to map and old fields are removed
			Main\ORM\Entity::destroy($dstDataClass::getEntity());

			if ($dstFactory instanceof Factory\Dynamic)
			{
				//if we do not recompile entity for dynamic type, some fields will be absent
				Model\Dynamic\TypeTable::compileEntity($dstFactory->getType());
			}
		}
	}

	$historyItem = self::getHistoryItem($srcEntityTypeID, $dstEntityTypeID);
	if($historyItem === null)
	{
		$historyItem = array();
	}

	$historyItem['sync'] = new DateTime();
	$historyItem['check'] = new DateTime();
	$historyItem['required'] = false;
	self::setHistoryItem($srcEntityTypeID, $dstEntityTypeID, $historyItem);

	return array_merge(self::$existedFieldNameMap, $synchronizedFieldNameMap);
}