Your IP : 3.141.42.13


Current Path : /home/bitrix/ext_www/crm.klimatlend.ua/bitrix/modules/tasks/lib/util/
Upload File :
Current File : /home/bitrix/ext_www/crm.klimatlend.ua/bitrix/modules/tasks/lib/util/userfield.php

<?
/**
 * Bitrix Framework
 * @package bitrix
 * @subpackage tasks
 * @copyright 2001-2016 Bitrix
 *
 * @access private
 */

namespace Bitrix\Tasks\Util;

use Bitrix\Tasks\Util;

abstract class UserField // todo: extends Dictionary, to iterate over user field scheme
{
	public static function getEntityCode()
	{
		return false;
	}

	/**
	 * Get system fields for this entity
	 */
	public static function getSysScheme()
	{
		return array();
	}

	/**
	 * Get user field map for this entity, with optional restoring missing fields
	 *
	 * @param int $entityId
	 * @param int $userId
	 * @param string $languageId
	 * @return mixed
	 */
	public static function getScheme($entityId = 0, $userId = 0, $languageId = LANGUAGE_ID)
	{
		$userId = intval($userId);
		if(!$userId)
		{
			$userId = User::getId();
		}

		$ufs = static::getUserFields($entityId, $userId, $languageId);

		// restore system fields for this entity
		if(User::isSuper($userId)) // only admin is allowed to create user fields
		{
			$reFetch = false;
			$scheme = static::getSysScheme();
			foreach($scheme as $field)
			{
				if(!array_key_exists($field['FIELD_NAME'], $ufs))
				{
					if(static::add(array_merge(array('ENTITY_ID' => static::getEntityCode()), $field)))
					{
						$reFetch = true;
					}
				}
			}

			if($reFetch)
			{
				$ufs = static::getUserFields($entityId, $userId, $languageId);
			}
		}

		/*
		// todo: restricted completely or restricted by the current project plan? you must now both ways!
		// determine what we can do here
		$canSortAndFilter = Util\UserField\Restriction::canManage(static::getEntityCode());

		foreach($ufs as $code => $desc)
		{
			$ufs[$code]['TASKS_RESTRICTION'] = array(
				'SORT' => $canSortAndFilter,     // whether we can sort by this field or not
				'FILTER' => $canSortAndFilter,   // whether we can filter by this field or not
			);
		}
		*/

		return $ufs;
	}

	public static function getDefaultValue($code, $userId = false)
	{
		$code = trim((string) $code);
		if($code == '')
		{
			return null;
		}

		$scheme = static::getScheme(0, $userId);
		if(!array_key_exists($code, $scheme))
		{
			return null;
		}

		$field = $scheme[$code];
		if(!array_key_exists('SETTINGS', $field) || !is_array($field['SETTINGS']) || !array_key_exists('DEFAULT_VALUE', $field['SETTINGS']))
		{
			return null;
		}

		$typeClass = \Bitrix\Tasks\Util\UserField\Type::getClass($field['USER_TYPE_ID']);

		$single = $typeClass::getDefaultValueSingle($field);
		if($single === null) // no default value is assumed in concept
		{
			return null;
		}

		if($field['MULTIPLE'] == 'Y')
		{
			return array($single);
		}
		else
		{
			return $single;
		}
	}

	public static function getTypes()
	{
		return $GLOBALS['USER_FIELD_MANAGER']->getUserType();
	}

	/**
	 * Checks if a userfield with $code exists for this entity
	 *
	 * @param $code
	 * @return bool
	 */
	public static function checkFieldExists($code)
	{
		$code = trim((string) $code);
		if($code == '')
		{
			return false;
		}

		$scheme = static::getScheme();

		return static::isUFKey($code) && array_key_exists($code, $scheme);
	}

	/**
	 * Checks if argument array contains userfield keys
	 *
	 * @param mixed $fields
	 * @return bool
	 */
	public static function checkContainsUFKeys($fields)
	{
		if(!Type::isIterable($fields))
		{
			return false;
		}

		foreach($fields as $fld => $value)
		{
			if(static::isUFKey($fld))
			{
				return true;
			}
		}

		return false;
	}

	/**
	 * Check if a given string looks like a user field name
	 *
	 * @param $key
	 * @return bool
	 */
	public static function isUFKey($key)
	{
		return mb_substr(trim((string)$key), 0, 3) == 'UF_';
	}

	/**
	 * @param Collection|string|integer|array|null $value
	 * @return bool
	 */
	public static function isValueEmpty($value)
	{
		if(Collection::isA($value))
		{
			return $value->isEmpty();
		}

		if(is_array($value))
		{
			return count($value) == 0;
		}

		return (string) $value == '';
	}

	public static function isFieldExist($name)
	{
		return static::getField($name) !== null;
	}

	public static function getField($id)
	{
		$id = trim((string) $id);
		if($id == '')
		{
			return null;
		}

		$scheme = static::getScheme();

		if(static::isUFKey($id))
		{
			return $scheme[$id];
		}
		elseif(is_numeric($id))
		{
			foreach($scheme as $fData)
			{
				if($fData['ID'] == $id)
				{
					return $fData;
				}
			}
		}

		return null;
	}

	/**
	 * Solves problem of matching entity code to user field controller class
	 *
	 * @param $code
	 * @return string
	 */
	public static function getControllerClassByEntityCode($code)
	{
		static $map = array();

		if(!isset($map[$code]))
		{
			$code = trim((string) $code);
			$code = ToLower(preg_replace('#^TASKS_#', '', $code));
			if($code == '' || !preg_match('#^[a-z0-9_]+$#', $code))
			{
				return '';
			}

			$className = '\\'.__NAMESPACE__.'\\UserField\\'.implode('\\', explode('_', $code));

			if(!class_exists($className))
			{
				return '';
			}

			$map[$code] = $className;
		}

		return $map[$code];
	}

	/**
	 * @param $data
	 * @param \Bitrix\Tasks\Util\UserField $dstUFController
	 * @param int $userId
	 * @param array $parameters
	 * @return Result
	 * @throws \Bitrix\Main\ArgumentException
	 */
	public function cloneValues($data, $dstUFController, $userId = 0, array $parameters = array() /*todo: configure object later */)
	{
		$result = new Result();

		$scheme = static::getScheme();
		$toScheme = $dstUFController->getScheme();

		$newData = $data;
		$values = array();

		// try to map field values...
		foreach($scheme as $field => $desc)
		{
			if(
				array_key_exists($field, $toScheme) && // field exists in the destination entity
				!empty($scheme[$field]['USER_TYPE_ID']) &&
				$toScheme[$field]['USER_TYPE_ID'] == $scheme[$field]['USER_TYPE_ID'] && // types are equal
				!static::isValueEmpty($data[$field]) // the source field is not empty
			)
			{
				$skip = Filter::isA($parameters['FILTER']) && !$parameters['FILTER']->match($desc);

				$typeClass = \Bitrix\Tasks\Util\UserField\Type::getClass($scheme[$field]['USER_TYPE_ID']);

				// even if $skip == true here, we must call cloneValue(), because it may affect other entity fields
				$valueClone = $typeClass::cloneValue(
					$data[$field],
					$newData,
					$scheme[$field],
					$toScheme[$field],
					$userId,
					array('SKIP' => $skip)
				);

				if($skip)
				{
					unset($newData[$field]);
				}
				else
				{
					if(!static::isValueEmpty($valueClone))
					{
						$newData[$field] = $valueClone;
						$values[$field] = $valueClone;
					}
				}
			}
		}

		$result->setData($newData);

		return $result;
	}

	public function cancelCloneValues($data, $userId = 0)
	{
		$result = new Result();

		$scheme = static::getScheme();

		foreach($scheme as $field => $desc)
		{
			if(
				!empty($scheme[$field]['USER_TYPE_ID'])
				&&
				array_key_exists($field, $data)
			)
			{
				$typeClass = \Bitrix\Tasks\Util\UserField\Type::getClass($scheme[$field]['USER_TYPE_ID']);

				$typeClass::cancelCloneValue($data[$field], $scheme[$field], array(), $userId);
			}
		}

		return $result;
	}

	/**
	 * Check values of the specified user fields for the specified entity
	 *
	 * @param int $entityId
	 * @param mixed $data
	 * @param int $userId
	 * @return Result
	 */
	public function checkValues($data, $entityId = 0, $userId = 0)
	{
		$result = new Result();

		if(!empty($data) && static::checkContainsUFKeys($data))
		{
			global $USER_FIELD_MANAGER;

			if(!$USER_FIELD_MANAGER->checkFields(static::getEntityCode(), intval($entityId), $data, $userId ? $userId : false))
			{
				global $APPLICATION;

				$e = $APPLICATION->getException();
				foreach($e->messages as $msg)
				{
					$msgText = $msg;
					$fieldId = '';
					if(is_array($msg))
					{
						$msgText = $msg['text'];
						$fieldId = $msg['id'];
					}

					$result->getErrors()->add('USER_FIELD', $msgText, Error::TYPE_FATAL, array('FIELD_ID' => $fieldId));
				}
			}
		}

		return $result;
	}

	/**
	 * Update values of the specified user fields for the specified entity
	 *
	 * @param int $entityId
	 * @param array $data
	 * @param int $userId
	 * @return Result
	 */
	public function updateValues($data, $entityId = 0, $userId = 0)
	{
		$result = new Result();

		if(!empty($data) && static::checkContainsUFKeys($data))
		{
			global $USER_FIELD_MANAGER;
			$USER_FIELD_MANAGER->update(static::getEntityCode(), intval($entityId), $data, $userId ? $userId : false);
		}

		return $result;
	}

	public function addField(array $fields)
	{
		$result = new Result();

		if(!array_key_exists('FIELD_NAME', $fields))
		{
			// have to auto-assign field name
			$name = static::getFreeFieldName();

			if(!$name)
			{
				$result->getErrors()->add('ACTION_FAILED', 'Unable to generate field name');
			}

			$fields['FIELD_NAME'] = $name;
		}

		if($result->isSuccess())
		{
			$id = static::add(array_merge($fields, array('ENTITY_ID' => static::getEntityCode())));

			if(!$id)
			{
				static::getApplicationErrors($result);
			}
			else
			{
				$result->setData($id);
			}
		}

		return $result;
	}

	public function updateField($id, array $fields)
	{
		$result = new Result();

		$updateResult = static::update($id, $fields);
		if(!$updateResult)
		{
			static::getApplicationErrors($result);
		}

		return $result;
	}

	public function deleteField($id)
	{
		$result = new Result();

		$entity = new \CUserTypeEntity();
		$deleteResult = $entity->delete($id);
		if(!$deleteResult)
		{
			static::getApplicationErrors($result);
		}

		return $result;
	}

	public static function clearCache()
	{
		global $CACHE_MANAGER;

		$CACHE_MANAGER->clearByTag(static::getCacheTagName());
	}

	public static function onAfterUserTypeAdd(array $field)
	{
		static::onUserTypeSchemeChange($field, 0);
	}

	public static function OnAfterUserTypeUpdate(array $field, $id)
	{
		static::onUserTypeSchemeChange($field, $id);
	}

	public static function OnAfterUserTypeDelete(array $field, $id)
	{
		static::onUserTypeSchemeChange($field, $id);
	}

	public static function getFreeFieldName()
	{
		$scheme = static::getScheme();

		for($i = 0; $i < 10; $i++)
		{
			$name = 'UF_AUTO_'.rand(100, 999).rand(100, 999).rand(100, 999).rand(100, 999);
			if(array_key_exists($name, $scheme))
			{
				continue;
			}
			else
			{
				return $name;
			}
//			$item = \Bitrix\Main\UserFieldTable::getList(array('limit' => 1, 'filter' => array(
//				'=FIELD_NAME' => $name,
//				'=ENTITY_ID' => static::getEntityCode()
//			), 'select' => array('ID')))->fetch();
//			if(!intval($item['ID']))
//			{
//				return $name;
//			}
		}

		return false;
	}

	private static function onUserTypeSchemeChange(array $field, $id)
	{
		$entityCode = false;

		if(array_key_exists('ENTITY_ID', $field))
		{
			$entityCode = $field['ENTITY_ID'];
		}
		else
		{
			$item = \CUserTypeEntity::GetByID($id);
			if($item)
			{
				$entityCode = $item['ENTITY_ID'];
			}
		}

		if($entityCode && mb_strpos($entityCode, 'TASKS_') == 0)
		{
			$className = static::getControllerClassByEntityCode($entityCode);
			if($className)
			{
				$className::clearCache();
			}
		}
	}

	private static function add($fields)
	{
		$entity = new \CUserTypeEntity();
		return $entity->add($fields);
	}

	private static function update($id, $fields)
	{
		if(array_key_exists('EDIT_FORM_LABEL', $fields))
		{
			$uf = \CAllUserTypeEntity::GetByID($id);
			if($uf)
			{
				$origLabel = is_array($uf['EDIT_FORM_LABEL']) ? $uf['EDIT_FORM_LABEL'] : array();
				foreach($origLabel as $lid => $text)
				{
					if(!isset($fields['EDIT_FORM_LABEL'][$lid]))
					{
						$fields['EDIT_FORM_LABEL'][$lid] = $text;
					}
				}
			}
		}

		$entity = new \CUserTypeEntity();
		return $entity->update($id, $fields);
	}

	private static function getUserFields($entityId = 0, $userId = 0, $languageId = false)
	{
		return $GLOBALS['USER_FIELD_MANAGER']->getUserFields(static::getEntityCode(), $entityId, $languageId, $userId ? $userId : false);
	}

	private static function getApplicationErrors(Result $result)
	{
		$e = $GLOBALS['APPLICATION']->getException();

		if($e)
		{
			if ($e instanceof \CAdminException)
			{
				if (is_array($e->messages))
				{
					foreach($e->messages as $msg)
					{
						$result->getErrors()->add('ACTION_FAILED', $msg['text'], false, array('ID' => $msg['id']));
					}
				}
			}
			else
			{
				$result->getErrors()->add('ACTION_FAILED', $e->getString(), false, array('EXCEPTION' => $e));
			}
		}
	}

	private static function getCacheTagName()
	{
		return "tasks_uf_".ToLower(static::getEntityCode());
	}

	public static function getClass()
	{
		return get_called_class();
	}
}