Your IP : 13.59.14.52


Current Path : /var/www/axolotl/data/www/yar.axolotls.ru/bitrix/modules/disk/lib/uf/
Upload File :
Current File : /var/www/axolotl/data/www/yar.axolotls.ru/bitrix/modules/disk/lib/uf/userfieldmanager.php

<?php

namespace Bitrix\Disk\Uf;

use Bitrix\Disk\AttachedObject;
use Bitrix\Disk\Configuration;
use Bitrix\Disk\Driver;
use Bitrix\Disk\File;
use Bitrix\Disk\Internals\Error\Error;
use Bitrix\Disk\Internals\Error\ErrorCollection;
use Bitrix\Disk\Internals\Error\IErrorable;
use Bitrix\Disk\BaseObject;
use Bitrix\Main\Event;
use Bitrix\Main\EventResult;
use Bitrix\Main\SystemException;

final class UserFieldManager implements IErrorable
{
	/** @var  ErrorCollection */
	protected $errorCollection;

	protected $additionalConnectorList = null;
	/** @var AttachedObject[]  */
	protected $loadedAttachedObjects = array();

	/**
	 * Constructor of UserFiedManager.
	 */
	public function __construct()
	{
		$this->errorCollection = new ErrorCollection();
	}

	/**
	 * Gets values of user fields for file or folder.
	 * @param BaseObject $object Target object.
	 * @return array
	 */
	public function getFieldsForObject(BaseObject $object)
	{
		/** @var \CAllUserTypeManager */
		global $USER_FIELD_MANAGER;
		return $USER_FIELD_MANAGER->getUserFields($this->getUfEntityName($object), $object->getId(), LANGUAGE_ID);
	}

	/**
	 * Gets data which describes specific connector by entity type.
	 * @param string $entityType Entity type (ex. sonet_comment).
	 * @return array|null Array with two elements: connector class and module.
	 */
	public function getConnectorDataByEntityType($entityType)
	{
		$defaultConnectors = $this->getDefaultConnectors();
		$entityType = strtolower($entityType);

		if(isset($defaultConnectors[$entityType]))
		{
			return $defaultConnectors[$entityType];
		}

		$data = $this->getAdditionalConnector($entityType);

		return $data === null?
			array(StubConnector::className(), Driver::INTERNAL_MODULE_ID) :
			$data
		;
	}

	/**
	 * Returns full list of available connectors for attached objects.
	 *
	 * @return array
	 */
	public function getConnectors()
	{
		return array_merge($this->getDefaultConnectors(), $this->getAdditionalConnectors());
	}

	private function getDefaultConnectors()
	{
		return array(
			'blog_comment' => array(BlogPostCommentConnector::className(), 'blog'),
			'blog_post' => array(BlogPostConnector::className(), 'blog'),
			'calendar_event' => array(CalendarEventConnector::className(), 'calendar'),
			'forum_message' => array(ForumMessageConnector::className(), 'forum'),
			'sonet_log' => array(SonetLogConnector::className(), 'socialnetwork'),
			'sonet_comment' => array(SonetCommentConnector::className(), 'socialnetwork'),
			'iblock_element' => array(IblockElementConnector::className(), 'iblock'),
			'iblock_workflow' => array(IblockWorkflowConnector::className(), 'iblock'),
		);
	}

	/**
	 * Gets input name for hidden input in disk.uf.file by entity type.
	 * This name will use in process saving user type (disk_file).
	 * @param string $entityType Entity type (ex. sonet_comment).
	 * @return string
	 */
	public function getInputNameForAllowEditByEntityType($entityType)
	{
		return $entityType . '_DISK_ATTACHED_OBJECT_ALLOW_EDIT';
	}

	/**
	 * Checks attitude attached object to entity. It is important in right checking in components disk.uf.file, disk.uf.version.
	 * @param AttachedObject $attachedObject Attached object.
	 * @param string $entityType Entity type (ex. sonet_comment).
	 * @param int $entityId Id of entity.
	 * @return bool
	 */
	public function belongsToEntity(AttachedObject $attachedObject, $entityType, $entityId)
	{
		list($connectorClass, $moduleId) = $this->getConnectorDataByEntityType($entityType);

		return
			$attachedObject->getEntityId()   == $entityId &&
			$attachedObject->getModuleId()   == $moduleId &&
			$attachedObject->getEntityType() == $connectorClass
		;
	}

	private function getAdditionalConnectors()
	{
		if($this->additionalConnectorList === null)
		{
			$this->buildAdditionalConnectorList();
		}

		return $this->additionalConnectorList;
	}

	private function getAdditionalConnector($entityType)
	{
		$additionalConnectorList = $this->getAdditionalConnectors();

		return isset($additionalConnectorList[$entityType])? $additionalConnectorList[$entityType] : null;
	}

	private function buildAdditionalConnectorList()
	{
		$this->additionalConnectorList = array();

		$event = new Event(Driver::INTERNAL_MODULE_ID, 'onBuildAdditionalConnectorList');
		$event->send();

		foreach($event->getResults() as $evenResult)
		{
			if($evenResult->getType() != EventResult::SUCCESS)
			{
				continue;
			}

			$result = $evenResult->getParameters();
			if(!is_array($result))
			{
				throw new SystemException('Wrong event result by building AdditionalConnectorList. Must be array.');
			}

			foreach($result as $connector)
			{
				if(empty($connector['ENTITY_TYPE']))
				{
					throw new SystemException('Wrong event result by building AdditionalConnectorList. Could not find ENTITY_TYPE.');
				}

				if(empty($connector['MODULE_ID']))
				{
					throw new SystemException('Wrong event result by building AdditionalConnectorList. Could not find MODULE_ID.');
				}

				if(empty($connector['CLASS']))
				{
					throw new SystemException('Wrong event result by building AdditionalConnectorList. Could not find CLASS.');
				}

				if(is_string($connector['CLASS']) && class_exists($connector['CLASS']))
				{
					$this->additionalConnectorList[strtolower($connector['ENTITY_TYPE'])] = array(
						$connector['CLASS'],
						$connector['MODULE_ID']
					);
				}
				else
				{
					throw new SystemException('Wrong event result by building AdditionalConnectorList. Could not find class by CLASS.');
				}
			}
		}
	}

	/**
	 * Shows component disk.uf.file (edit mode).
	 *
	 * @param array &$params Component parameters.
	 * @param array &$result Component results.
	 * @param null $component Component.
	 * @return void
	 */
	public function showEdit(&$params, &$result, $component = null)
	{
		if (!Configuration::isSuccessfullyConverted())
		{
			return;
		}

		global $APPLICATION;

		$map = [
			'DISABLE_LOCAL_EDIT' => false,
			'DISABLE_CREATING_FILE_BY_CLOUD' => false,
		];

		foreach (array_keys($map) as $key)
		{
			$map[$key] = (isset($params[$key])? $params[$key] : false);
		}

		$APPLICATION->includeComponent(
			'bitrix:disk.uf.file',
			$this->getShowTemplate($params, ['mobile', 'mail']),
			[
				'EDIT' => 'Y',
				'PARAMS' => $params,
				'RESULT' => $result,
				'DISABLE_LOCAL_EDIT' => $map['DISABLE_LOCAL_EDIT'],
				'DISABLE_CREATING_FILE_BY_CLOUD' => $map['DISABLE_CREATING_FILE_BY_CLOUD'],
			],
			$component,
			['HIDE_ICONS' => 'Y']
		);
	}

	/**
	 * Shows component disk.uf.file (show mode).
	 *
	 * @param array &$params Component parameters.
	 * @param array &$result Component results.
	 * @param null $component Component.
	 * @return void
	 */
	public function showView(&$params, &$result, $component = null)
	{
		global $APPLICATION;

		$APPLICATION->includeComponent(
			'bitrix:disk.uf.file',
			$this->getShowTemplate($params, ['mobile', 'mail', 'checklist']),
			[
				'PARAMS' => $params,
				'RESULT' => $result,
				'DISABLE_LOCAL_EDIT' => (isset($params['DISABLE_LOCAL_EDIT'])? $params['DISABLE_LOCAL_EDIT'] : false),
			],
			$component,
			['HIDE_ICONS' => 'Y']
		);
	}

	/**
	 * Shows component disk.uf.version.
	 *
	 * @param array &$params Component parameters.
	 * @param array &$result Component results.
	 * @param null $component Component.
	 * @return void
	 */
	public function showViewVersion(&$params, &$result, $component = null)
	{
		global $APPLICATION;

		$APPLICATION->includeComponent(
			'bitrix:disk.uf.version',
			$this->getShowTemplate($params, ['mobile', 'mail']),
			[
				'PARAMS' => $params,
				'RESULT' => $result,
				'DISABLE_LOCAL_EDIT' => (isset($params['DISABLE_LOCAL_EDIT'])? $params['DISABLE_LOCAL_EDIT'] : false),
			],
			$component,
			['HIDE_ICONS' => 'Y']
		);
	}

	/**
	 * @param array $params
	 * @param array $possibleTemplates
	 * @return string
	 */
	private function getShowTemplate($params, $possibleTemplates)
	{
		$upperParams = array_change_key_case($params, CASE_UPPER);

		if ($upperParams['MOBILE'] == 'Y')
		{
			$template = 'mobile'.(isset($upperParams['GRID']) && $upperParams['GRID'] == 'Y' ? '_grid' : '');
		}
		else
		{
			$template = $upperParams['TEMPLATE'];
			$template = (in_array($template, $possibleTemplates)? $template : '.default');
		}

		return $template;
	}

	/**
	 * @param BaseObject $object
	 * @return string
	 */
	public function getUfEntityName(BaseObject $object)
	{
		if($object instanceof File)
		{
			return 'DISK_FILE_' . $object->getStorageId();
		}
		return 'DISK_FOLDER_' . $object->getStorageId();
	}

	/**
	 * Preload AttachedObjects.
	 * @param array $ids List of attached objects id.
	 * @return void
	 */
	public function loadBatchAttachedObject(array $ids)
	{
		foreach($ids as $i => &$id)
		{
			if(isset($this->loadedAttachedObjects[$id]))
			{
				unset($ids[$i]);
			}
			if(!is_numeric($id))
			{
				unset($ids[$i]);
			}
			$id = (int)$id;
		}
		unset($id);

		if(empty($ids))
		{
			return;
		}

		/** @var \Bitrix\Disk\AttachedObject $attachedObject */
		$modelList = AttachedObject::getModelList([
			'filter' => ['ID' => $ids],
			'with' => ['OBJECT'],
			'extra' => [
				'FILE_CONTENT_TYPE' => 'OBJECT.FILE_CONTENT.CONTENT_TYPE',
				'FILE_SIZE' => 'OBJECT.FILE_CONTENT.FILE_SIZE',
			],
		]);
		foreach($modelList as $attachedObject)
		{
			$this->loadedAttachedObjects[$attachedObject->getId()] = $attachedObject;
		}
		unset($attachedObject);
	}

	/**
	 * Returns list of attached object which are attached to entity.
	 *
	 * @param string $entity Entity name.
	 * @param string|int $entityId Entity id.
	 * @param string $fieldName Field name.
	 *
	 * @return AttachedObject[]
	 */
	public function getAttachedObjectByEntity($entity, $entityId, $fieldName)
	{
		/** @var \CUserTypeManager */
		global $USER_FIELD_MANAGER;

		$values = $USER_FIELD_MANAGER->getUserFieldValue($entity, $fieldName, $entityId);
		if (!$values)
		{
			return array();
		}

		$this->loadBatchAttachedObject($values);

		return array_intersect_key($this->loadedAttachedObjects, array_combine($values, $values));
	}

	/**
	 * Preload AttachedObjects in blog posts.
	 * @param array $blogPostIds List of blog post id.
	 * @return void
	 */
	public function loadBatchAttachedObjectInBlogPost(array $blogPostIds)
	{
		if(empty($blogPostIds))
		{
			return;
		}

		list($connectorClass, $moduleId) = $this->getConnectorDataByEntityType('BLOG_POST');

		$with = ['OBJECT'];
		if(Configuration::isEnabledObjectLock())
		{
			$with[] = 'OBJECT.LOCK';
		}

		$modelList = AttachedObject::getModelList(
			[
				'with' => $with,
				'filter' => [
					'=ENTITY_TYPE' => $connectorClass,
					'ENTITY_ID' => $blogPostIds,
					'=MODULE_ID' => $moduleId,
				],
				'extra' => [
					'FILE_CONTENT_TYPE' => 'OBJECT.FILE_CONTENT.CONTENT_TYPE',
					'FILE_SIZE' => 'OBJECT.FILE_CONTENT.FILE_SIZE',
				],
			]
		);
		foreach($modelList as $attachedObject)
		{
			/** @var \Bitrix\Disk\AttachedObject $attachedObject */
			$this->loadedAttachedObjects[$attachedObject->getId()] = $attachedObject;
		}
		unset($attachedObject);
	}

	/**
	 * Checks by id of attached object status of loading data in memory (optimization).
	 * @param int $id Id of attached object.
	 * @return bool
	 */
	public function isLoadedAttachedObject($id)
	{
		return !empty($this->loadedAttachedObjects[$id]);
	}

	/**
	 * Gets attached object by id (optimization).
	 * @param int $id Id of attached object.
	 * @return AttachedObject|null
	 */
	public function getAttachedObjectById($id)
	{
		if(!isset($this->loadedAttachedObjects[$id]))
		{
			$this->loadedAttachedObjects[$id] = AttachedObject::loadById($id, ['OBJECT']);
		}
		return $this->loadedAttachedObjects[$id];
	}

	/**
	 * Getting array of errors.
	 * @return Error[]
	 */
	public function getErrors()
	{
		return $this->errorCollection->toArray();
	}

	/**
	 * Getting array of errors with the necessary code.
	 * @param string $code Code of error.
	 * @return Error[]
	 */
	public function getErrorsByCode($code)
	{
		return $this->errorCollection->getErrorsByCode($code);
	}

	/**
	 * Getting once error with the necessary code.
	 * @param string $code Code of error.
	 * @return Error[]
	 */
	public function getErrorByCode($code)
	{
		return $this->errorCollection->getErrorByCode($code);
	}

	/**
	 * Clones uf values from entity and creates new files (copies from attach) to save in new entity.
	 * @param array $attachedIds List of attached objects id.
	 * @param int $userId Id of user.
	 * @internal
	 * @return array
	 */
	public function cloneUfValuesFromAttachedObject(array $attachedIds, $userId)
	{
		$this->errorCollection->clear();

		$userId = (int)$userId;
		if($userId <= 0)
		{
			$this->errorCollection->addOne(new Error('Invalid $userId'));
			return null;
		}
		$userStorage = Driver::getInstance()->getStorageByUserId($userId);
		if(!$userStorage)
		{
			$this->errorCollection->addOne(new Error("Could not find storage for user {$userId}"));
			$this->errorCollection->add(Driver::getInstance()->getErrors());
			return null;
		}
		$folder = $userStorage->getFolderForUploadedFiles();
		if(!$folder)
		{
			$this->errorCollection->addOne(new Error("Could not create/find folder for upload"));
			$this->errorCollection->add($userStorage->getErrors());
			return null;
		}

		$newValues = array();
		foreach($attachedIds as $id)
		{
			list($type, $realValue) = FileUserType::detectType($id);
			if(FileUserType::TYPE_ALREADY_ATTACHED != $type)
			{
				continue;
			}
			$attachedObject = AttachedObject::loadById($realValue, array('OBJECT'));
			if(!$attachedObject)
			{
				continue;
			}
			if(!$attachedObject->canRead($userId))
			{
				continue;
			}
			$file = $attachedObject->getFile();
			if(!$file)
			{
				continue;
			}
			$newFile = $file->copyTo($folder, $userId, true);
			if(!$newFile)
			{
				$this->errorCollection->add($file->getErrors());
				continue;
			}
			$newValues[$id] = FileUserType::NEW_FILE_PREFIX . $newFile->getId();
		}

		return $newValues;
	}
}