Your IP : 3.14.136.229


Current Path : /home/bitrix/ext_www/crm.klimatlend.ua/bitrix/modules/disk/lib/search/
Upload File :
Current File : /home/bitrix/ext_www/crm.klimatlend.ua/bitrix/modules/disk/lib/search/indexmanager.php

<?php

namespace Bitrix\Disk\Search;

use Bitrix\Disk\BaseObject;
use Bitrix\Disk\Configuration;
use Bitrix\Disk\Driver;
use Bitrix\Disk\File;
use Bitrix\Disk\Folder;
use Bitrix\Disk\Internals\Error\ErrorCollection;
use Bitrix\Disk\Internals\Index\ObjectExtendedIndexTable;
use Bitrix\Disk\Internals\Index\ObjectHeadIndexTable;
use Bitrix\Disk\Internals\ObjectSaveIndexTable;
use Bitrix\Disk\Internals\ObjectTable;
use Bitrix\Disk\Internals\SimpleRightTable;
use Bitrix\Disk\ProxyType\Group;
use Bitrix\Disk\Search\Reindex\HeadIndex;
use Bitrix\Disk\Storage;
use Bitrix\Disk\ProxyType;
use Bitrix\Main\Application;
use Bitrix\Main\Loader;
use Bitrix\Main\ModuleManager;
use Bitrix\Main\Text;
use CSearch;

final class IndexManager
{
	/** @var  ErrorCollection */
	protected $errorCollection;
	/** @var ContentManager */
	protected $contentManager;
	protected $useSearchModule = true;
	protected $allowUseExtendedFullText = true;

	/**
	 * Constructor IndexManager.
	 */
	public function __construct()
	{
		$this->errorCollection = new ErrorCollection;
		$this->contentManager = new ContentManager;

		$this->initDefaultConfiguration();
	}

	public function initDefaultConfiguration()
	{
		$this->allowUseExtendedFullText = Configuration::allowUseExtendedFullText();
	}

	/**
	 * Disables using search module.
	 * @return $this
	 */
	public function disableUsingSearchModule()
	{
		$this->useSearchModule = false;

		return $this;
	}

	public function disableUsingExtendedFullText()
	{
		$this->allowUseExtendedFullText = false;

		return $this;
	}

	protected function saveExtendedFullTextByContent(BaseObject $object, $content = null)
	{
		$textBuilder = $this->getTextBuilder($object);

		if ($object instanceof Folder)
		{
			ObjectExtendedIndexTable::upsert(
				$object->getId(),
				$textBuilder->getSearchValue(),
				ObjectExtendedIndexTable::STATUS_EXTENDED
			);

			return;
		}

		$status = $content? ObjectExtendedIndexTable::STATUS_EXTENDED : ObjectExtendedIndexTable::STATUS_SHORT;
		if ($content)
		{
			//try to update by short version of search index
			ObjectExtendedIndexTable::upsert(
				$object->getId(),
				$textBuilder->getSearchValue(),
				$status
			);
		}

		if (is_callable($content))
		{
			$content = $content();
		}

		ObjectExtendedIndexTable::upsert(
			$object->getId(),
			$textBuilder->addText($content)->getSearchValue(),
			$status
		);
	}

	protected function getTextBuilder(BaseObject $object)
	{
		return FullTextBuilder::create()
			->addText($object->getName())
			->addUser($object->getCreatedBy())
		;
	}

	/**
	 * @param BaseObject $object
	 * @deprecated
	 */
	protected function saveOldFullText(BaseObject $object)
	{
		$textBuilder = $this->getTextBuilder($object);
		if (!ModuleManager::isModuleInstalled('bitrix24') && ($object instanceof File))
		{
			$content = $this->getFileContent($object);
			$maxIndexSize = Configuration::getMaxIndexSize();
			if ($maxIndexSize > 0)
			{
				//yes, we know that substr may kills some last characters
				$content = Text\BinaryString::getSubstring($content, 0, $maxIndexSize);
			}

			$textBuilder->addText($content);
		}

		ObjectSaveIndexTable::update($object->getId(), array(
			'SEARCH_INDEX' => $textBuilder->getSearchValue(),
		));
	}

	protected function saveFullTextByHead(BaseObject $object)
	{
		ObjectHeadIndexTable::upsert(
			$object->getId(),
			$this->getTextBuilder($object)->getSearchValue()
		);
	}

	/**
	 * Runs index by file.
	 *
	 * @param File $file Target file.
	 * @param array $additionalData
	 *
	 * @return void
	 * @throws \Bitrix\Main\ArgumentException
	 * @throws \Bitrix\Main\LoaderException
	 * @throws \Exception
	 */
	public function indexFile(File $file, array $additionalData = array())
	{
		if (!$this->allowIndex($file))
		{
			return;
		}

		$this->saveFullTextByHead($file);
		$this->updateFileContent($file);
		$this->indexFileByModuleSearch($file);
	}

	/**
	 * @param File $file
	 * @deprecated
	 */
	public function indexFileByModuleSearch(File $file)
	{
		if (!$this->useSearchModule)
		{
			return;
		}

		if (!Loader::includeModule('search'))
		{
			return;
		}

		$storage = $file->getStorage();
		$searchData = array(
			'LAST_MODIFIED' => $file->getUpdateTime()?: $file->getCreateTime(),
			'TITLE' => $file->getName(),
			'PARAM1' => $file->getStorageId(),
			'PARAM2' => $file->getParentId(),
			'SITE_ID' => self::resolveSiteId($storage),
			'URL' => $this->getDetailUrl($file),
			'PERMISSIONS' => $this->getSimpleRights($file),
			//CSearch::killTags
			'BODY' => strip_tags($file->getCreateUser()->getFormattedName()) . "\r\n" . $this->getFileContent($file),
		);
		if ($storage->getProxyType() instanceof Group)
		{
			$searchData['PARAMS'] = array(
				'socnet_group' => $storage->getEntityId(),
				'entity' => 'socnet_group',
			);
		}

		$maxIndexSize = Configuration::getMaxIndexSize();
		if ($maxIndexSize > 0)
		{
			//yes, we know that substr may kills some last characters
			$searchData['BODY'] = Text\BinaryString::getSubstring($searchData['BODY'], 0, $maxIndexSize);
		}

		/** @noinspection PhpDynamicAsStaticMethodCallInspection */
		CSearch::index(Driver::INTERNAL_MODULE_ID, $this->getItemId($file), $searchData, true);
	}

	private function allowIndex(BaseObject $object)
	{
		//here we place configuration by Module (Options). Example, we can deactivate index for big files in Disk.
		if (!Configuration::allowIndexFiles())
		{
			return false;
		}

		$storage = $object->getStorage();
		if (!$storage || !$storage->getProxyType()->canIndexBySearch())
		{
			return false;
		}

		return true;
	}

	public function updateFileContent(File $file)
	{
		if (!$this->allowIndex($file))
		{
			return;
		}

		$connection = Application::getConnection();
		if (!HeadIndex::isReady() && $connection->getTableField(ObjectTable::getTableName(), 'SEARCH_INDEX'))
		{
			$this->saveOldFullText($file);
		}

		if ($this->allowUseExtendedFullText)
		{
			$this->saveExtendedFullTextByContent($file);
		}
	}

	public function indexFolderWithExtendedIndex(Folder $folder)
	{
		if (!$this->allowIndex($folder) || !$this->allowUseExtendedFullText)
		{
			return;
		}

		$this->saveExtendedFullTextByContent($folder);
	}

	public function indexFileWithExtendedIndex(File $file)
	{
		if (!$this->allowIndex($file) || !$this->allowUseExtendedFullText)
		{
			return;
		}

		$this->saveExtendedFullTextByContent($file, function() use ($file) {
			return $this->getFileContent($file);
		});
	}

	/**
	 * Runs index by folder.
	 * @param Folder $folder Target folder.
	 * @throws \Bitrix\Main\LoaderException
	 * @return void
	 */
	public function indexFolder(Folder $folder)
	{
		if (!$this->allowIndex($folder))
		{
			return;
		}

		$connection = Application::getConnection();
		if (!HeadIndex::isReady() && $connection->getTableField(ObjectTable::getTableName(), 'SEARCH_INDEX'))
		{
			$this->saveOldFullText($folder);
		}

		$this->saveFullTextByHead($folder);
		if ($this->allowUseExtendedFullText)
		{
			$this->saveExtendedFullTextByContent($folder);
		}
		$this->indexFolderByModuleSearch($folder);
	}

	/**
	 * @param Folder $folder
	 * @deprecated
	 */
	public function indexFolderByModuleSearch(Folder $folder)
	{
		if (!$this->useSearchModule)
		{
			return;
		}

		if (!Loader::includeModule('search'))
		{
			return;
		}

		$storage = $folder->getStorage();
		$searchData = array(
			'LAST_MODIFIED' => $folder->getUpdateTime()?: $folder->getCreateTime(),
			'TITLE' => $folder->getName(),
			'PARAM1' => $folder->getStorageId(),
			'PARAM2' => $folder->getParentId(),
			'SITE_ID' => self::resolveSiteId($storage),
			'URL' => $this->getDetailUrl($folder),
			'PERMISSIONS' => $this->getSimpleRights($folder),
			//CSearch::killTags
			'BODY' => $this->getTextBuilder($folder)->getSearchValue(),
		);
		if ($storage->getProxyType() instanceof Group)
		{
			$searchData['PARAMS'] = array(
				'socnet_group' => $storage->getEntityId(),
				'entity' => 'socnet_group',
			);
		}

		/** @noinspection PhpDynamicAsStaticMethodCallInspection */
		CSearch::index(Driver::INTERNAL_MODULE_ID, $this->getItemId($folder), $searchData, true);
	}

	/**
	 * Changes index after rename.
	 * @param BaseObject $object Target file or folder.
	 * @throws \Bitrix\Main\LoaderException
	 * @return void
	 */
	public function changeName(BaseObject $object)
	{
		if ($object instanceof Folder)
		{
			$this->indexFolder($object);
		}
		elseif ($object instanceof File)
		{
			$this->indexFile($object);
		}
	}

	/**
	 * Delete information from Search by concrete file or folder.
	 * @param BaseObject $object Target object.
	 * @throws \Bitrix\Main\LoaderException
	 */
	public function dropIndex(BaseObject $object)
	{
		ObjectHeadIndexTable::delete($object->getId());
		ObjectExtendedIndexTable::delete($object->getId());

		$this->dropIndexByModuleSearch($object);
	}

	/**
	 * @param BaseObject $object
	 * @deprecated
	 */
	public function dropIndexByModuleSearch(BaseObject $object)
	{
		if (!Loader::includeModule('search'))
		{
			return;
		}
		/** @noinspection PhpDynamicAsStaticMethodCallInspection */
		CSearch::deleteIndex(Driver::INTERNAL_MODULE_ID, $this->getItemId($object));
	}

	/**
	 * Recalculate rights in Search if it needs.
	 * @param BaseObject $object Target object (can be folder or file).
	 * @throws \Bitrix\Main\LoaderException
	 * @return void
	 * @deprecated
	 */
	public function recalculateRights(BaseObject $object)
	{
		if (!$this->useSearchModule)
		{
			return;
		}

		if(!Loader::includeModule('search'))
		{
			return;
		}
		if($object instanceof File)
		{
			/** @noinspection PhpDynamicAsStaticMethodCallInspection */
			CSearch::changePermission(
				Driver::INTERNAL_MODULE_ID,
				$this->getSimpleRights($object),
				$this->getItemId($object)
			);
		}
		elseif($object instanceof Folder)
		{
			/** @noinspection PhpDynamicAsStaticMethodCallInspection */
			CSearch::changePermission(
				Driver::INTERNAL_MODULE_ID,
				$this->getSimpleRights($object),
				false,
				$object->getStorageId(),
				$object->getId()
			);
			/** @noinspection PhpDynamicAsStaticMethodCallInspection */
			CSearch::changePermission(
				Driver::INTERNAL_MODULE_ID,
				$this->getSimpleRights($object),
				$this->getItemId($object)
			);
		}
	}

	/**
	 * Event listener which return url for resource by fields.
	 * @param array $fields Fields from search module.
	 * @return string
	 * @deprecated
	 */
	public static function onSearchGetUrl($fields)
	{
		if(!is_array($fields))
		{
			return '';
		}
		if($fields["MODULE_ID"] !== "disk" || mb_substr($fields["URL"], 0, 1) !== "=")
		{
			return $fields["URL"];
		}

		parse_str(ltrim($fields["URL"], "="), $data);
		if(empty($data['ID']))
		{
			return '';
		}
		$object = BaseObject::loadById($data['ID']);
		if(!$object)
		{
			return '';
		}
		$pathFileDetail = self::getDetailUrl($object);
		\CSearch::update($fields['ID'], array('URL' => $pathFileDetail));

		return $pathFileDetail;
	}

	/**
	 * Returns stored index in module search.
	 * @param BaseObject $object File or Folder.
	 *
	 * @return null|array
	 * @deprecated
	 */
	public function getStoredIndex(BaseObject $object)
	{
		if(!Loader::includeModule('search'))
		{
			return null;
		}

		$itemId = self::getItemId($object);
		$index = \CSearch::getIndex(Driver::INTERNAL_MODULE_ID, $itemId);

		return $index?: null;
	}

	/**
	 * Search re-index handler.
	 * @param array  $nextStepData Array with data about step.
	 * @param null   $searchObject Search object.
	 * @param string $method Method.
	 * @return array|bool
	 * @deprecated
	 */
	public static function onSearchReindex($nextStepData = array(), $searchObject = null, $method = "")
	{
		$result = array();
		$filter = array(
			'!PARENT_ID' => null,
		);

		if(isset($nextStepData['MODULE']) && ($nextStepData['MODULE'] === 'disk') && !empty($nextStepData['ID']))
		{
			$filter['>ID'] = self::getObjectIdFromItemId($nextStepData['ID']);
		}
		else
		{
			$filter['>ID'] = 0;
		}

		static $self = null;
		if($self === null)
		{
			$self = Driver::getInstance()->getIndexManager();
		}

		$query = BaseObject::getList([
			'filter' => $filter,
			'order' => ['ID' => 'ASC'],
			'limit' => 1000,
		]);
		while($fileData = $query->fetch())
		{
			/** @var BaseObject $object */
			$object = BaseObject::buildFromArray($fileData);
			if(!$object->getStorage())
			{
				continue;
			}

			$searchData = array(
				'ID' => self::getItemId($object),
				'LAST_MODIFIED' => $object->getUpdateTime() ?: $object->getCreateTime(),
				'TITLE' => $object->getName(),
				'PARAM1' => $object->getStorageId(),
				'PARAM2' => $object->getParentId(),
				'SITE_ID' => self::resolveSiteId($object->getStorage()),
				'URL' => self::getDetailUrl($object),
				'PERMISSIONS' => $self->getSimpleRights($object),
				//CSearch::killTags
				'BODY' => $self->getObjectContent($object),
			);

			if($searchObject)
			{
				$indexResult = call_user_func(array($searchObject, $method), $searchData);
				if(!$indexResult)
				{
					return $searchData["ID"];
				}
			}
			else
			{
				$result[] = $searchData;
			}
		}

		if($searchObject)
		{
			return false;
		}

		return $result;
	}

	private static function resolveSiteId(Storage $storage)
	{
		$siteId = $storage->getSiteId();
		if($siteId)
		{
			return array($siteId => '');
		}

		if(!Loader::includeModule('socialnetwork'))
		{
			return array(
				self::getDefaultSiteId()?: SITE_ID => ''
			);
		}

		if($storage->getProxyType() instanceof ProxyType\User)
		{
			$user = \Bitrix\Main\UserTable::getList(
				array(
					'select' => array('ID', 'UF_DEPARTMENT'),
					'filter' => array('ID' => $storage->getEntityId())
				)
			)->fetch();

			//user is intranet user
			if(
				!empty($user["UF_DEPARTMENT"])
				&& is_array($user["UF_DEPARTMENT"])
				&& intval($user["UF_DEPARTMENT"][0]) > 0
			)
			{
				$site = \CSocNetLogComponent::getSiteByDepartmentId($user["UF_DEPARTMENT"]);

				return $site["LID"];
			}

			if(Loader::includeModule('extranet'))
			{
				return array(
					self::getExtranetSiteId() => '',
				);
			}

			return array(
				self::getDefaultSiteId()?: SITE_ID => ''
			);
		}
		elseif($storage->getProxyType() instanceof ProxyType\Group)
		{
			$query = \CSocNetGroup::getSite($storage->getEntityId());
			$sites = array();
			while($groupSite = $query->fetch())
			{
				$sites[$groupSite['LID']] = '';
			}

			return $sites;
		}

		return array(
			self::getDefaultSiteId()?: SITE_ID => ''
		);
	}

	private static function getExtranetSiteId()
	{
		static $extranetSiteId = null;

		if($extranetSiteId)
		{
			return $extranetSiteId;
		}

		if(!Loader::includeModule('extranet'))
		{
			return null;
		}

		return \CExtranet::getExtranetSiteID();
	}

	private static function getDefaultSiteId()
	{
		static $defaultSite = null;

		if($defaultSite)
		{
			return $defaultSite['LID'];
		}

		$sites = \CSite::GetList($b = 'SORT', $o = 'asc', array('ACTIVE' => 'Y'));
		while ($site = $sites->getNext())
		{
			if(!$defaultSite && $site['DEF'] == 'Y')
			{
				$defaultSite = $site;
			}
		}

		return $defaultSite['LID'];
	}

	private function getObjectContent(BaseObject $object, array $options = null)
	{
		return $this->contentManager->getObjectContent($object, $options);
	}

	private function getFileContent(File $file, array $options = null)
	{
		return $this->contentManager->getObjectContent($file, $options);
	}

	private function getSimpleRights(BaseObject $object)
	{
		$query = SimpleRightTable::getList(array(
			'select' => array('ACCESS_CODE'),
			'filter' => array(
				'OBJECT_ID' => $object->getId(),
			)
		));
		$permissions = array();
		while($row = $query->fetch())
		{
			$permissions[] = $row['ACCESS_CODE'];
		}

		return $permissions;
	}

	/**
	 * Getting id for module search.
	 * @param BaseObject $object
	 * @return string
	 */
	private static function getItemId(BaseObject $object)
	{
		if($object instanceof File)
		{
			return 'FILE_' . $object->getId();
		}
		return 'FOLDER_' . $object->getId();
	}

	private static function getObjectIdFromItemId($itemId)
	{
		if(mb_substr($itemId, 0, 5) === 'FILE_')
		{
			return mb_substr($itemId, 5);
		}
		return mb_substr($itemId, 7);
	}

	private static function getDetailUrl(BaseObject $object)
	{
		$detailUrl = '';
		$urlManager = Driver::getInstance()->getUrlManager();
		if($object instanceof File)
		{
			$detailUrl = $urlManager->getUrlFocusController('openFileDetail', array('fileId' => $object->getId()));
		}
		elseif($object instanceof Folder)
		{
			$detailUrl = $urlManager->getUrlFocusController('openFolderList', array('folderId' => $object->getId()));
		}

		return $detailUrl;
	}
}