Your IP : 3.144.101.193


Current Path : /var/www/www-root/data/www/info.monolith-realty.ru/bitrix/modules/landing/lib/
Upload File :
Current File : /var/www/www-root/data/www/info.monolith-realty.ru/bitrix/modules/landing/lib/file.php

<?php
namespace Bitrix\Landing;

use \Bitrix\Landing\Internals\FileTable;

class File
{
	/**
	 * Entity type site.
	 */
	public const ENTITY_TYPE_SITE  = 'S';

	/**
	 * Entity type landing.
	 */
	public const ENTITY_TYPE_LANDING = 'L';

	/**
	 * Entity type block.
	 */
	public const ENTITY_TYPE_BLOCK = 'B';

	/**
	 * Entity type asset.
	 */
	public const ENTITY_TYPE_ASSET = 'A';

	/**
	 * Transliterates the Cyrillic characters in a file name to Latin characters and returns the new file name.
	 * @param string $fileName File name.
	 * @return string
	 */
	public static function transliterateFileName(string $fileName): string
	{
		$parts = pathinfo($fileName);
		$basename = $parts['filename'];
		$transliterateBaseName =  \CUtil::translit(
			$basename,
			'ru',
			[
				'replace_space' => '_',
				'replace_other' => '_'
			]
		);

		return $transliterateBaseName . '.' . $parts['extension'];
	}

	/**
	 * Returns sanitized file name.
	 * @param string $fileName File name.
	 * @return string
	 */
	public static function sanitizeFileName(string $fileName): string
	{
		return preg_replace(
			'/[\(\)\s]+/s',
			'_',
			$fileName
		);
	}

	/**
	 * Add new record.
	 * @param int $fileId File id.
	 * @param int $entityId Entity id.
	 * @param string $entityType Entity type.
	 * @param bool $temp This is temporary file.
	 * @return void
	 */
	protected static function add(int $fileId, int $entityId, string $entityType, bool $temp = false): void
	{
		$res = FileTable::getList(array(
			'select' => array(
				'ID'
			),
			'filter' => array(
				'FILE_ID' => $fileId,
				'ENTITY_ID' => $entityId,
				'=ENTITY_TYPE' => $entityType
			)
		));
		if (!$res->fetch())
		{
			$res = FileTable::add(array(
				'FILE_ID' => $fileId,
				'ENTITY_ID' => $entityId,
				'ENTITY_TYPE' => $entityType,
				'TEMP' => $temp ? 'Y' : 'N'
			));
			$res->isSuccess();
		}
	}

	/**
	 * Get all files id from entity.
	 * @param int $entityId Entity id.
	 * @param int $entityType Entity type.
	 * @return array
	 */
	protected static function getFiles($entityId, $entityType)
	{
		$files = [];
		$res = FileTable::getList(array(
			'select' => array(
				'FILE_ID'
			),
			'filter' => array(
				'ENTITY_ID' => $entityId,
				'=ENTITY_TYPE' => $entityType
			)
		));
		while ($row = $res->fetch())
		{
			$files[] = $row['FILE_ID'];
		}
		return $files;
	}

	/**
	 * Mark records for delete.
	 * @param int|array $fileId File id.
	 * @param int $entityId Entity id.
	 * @param int $entityType Entity type.
	 * @return void
	 */
	protected static function delete($fileId, $entityId, $entityType)
	{
		//@tmp log
		Debug::log(
			$entityId . '@' . $entityType,
			'fileId: ' . print_r($fileId, true) . '@' . print_r(\Bitrix\Main\Diag\Helper::getBackTrace(15), true),
			'LANDING_FILE_MARK_DELETE'
		);

		$filter = array(
			'ENTITY_ID' => $entityId,
			'=ENTITY_TYPE' => $entityType
		);
		if ($fileId)
		{
			$filter['FILE_ID'] = $fileId;
		}
		$res = FileTable::getList(array(
			'select' => array(
				'ID', 'FILE_ID'
			),
			'filter' => $filter
		));
		while ($row = $res->fetch())
		{
			$resUpdate = FileTable::update(
				$row['ID'],
				array(
					'FILE_ID' => -1 * abs($row['FILE_ID'])
				)
			);
			$resUpdate->isSuccess();
		}
	}

	/**
	 * Final delete all marked files.
	 * @param int $limit Records limit for one iteration.
	 * @return void
	 */
	public static function deleteFinal($limit = null)
	{
		$deletedFiles = [];

		$res = FileTable::getList([
		  	'select' => [
		 		'ID', 'FILE_ID'
		    ],
	  		'filter' => [
				'<FILE_ID' => 0
		    ],
			'limit' => $limit,
			'order' => [
				'ID' => 'asc'
			]
		]);
		while ($row = $res->fetch())
		{
			$row['FILE_ID'] *= -1;
			FileTable::delete($row['ID']);
			$deletedFiles[$row['FILE_ID']] = $row['FILE_ID'];
		}
		if (!empty($deletedFiles))
		{
			// don't delete still used
			$res = FileTable::getList([
				'select' => [
					'FILE_ID'
				],
				'filter' => [
					'FILE_ID' => $deletedFiles
				]
			]);
			while ($row = $res->fetch())
			{
				unset($deletedFiles[$row['FILE_ID']]);
			}
			foreach ($deletedFiles as $fid)
			{
				$fileData = self::getFileArray($fid);
				if ($fileData)
				{
					//@tmp log
					Debug::log(
						$fileData['SRC'],
						'fileId: ' . $fid,
						'LANDING_FILE_DELETE'
					);
					\CFile::delete($fid);
				}
			}
		}
	}

	/**
	 * Add new record for Site.
	 * @param int $id Site id.
	 * @param int $fileId File id.
	 * @param bool $temp This is temporary file.
	 * @return void
	 */
	public static function addToSite(int $id, int $fileId, bool $temp = false): void
	{
		if ($fileId > 0 && $id > 0)
		{
			self::add($fileId, $id, self::ENTITY_TYPE_SITE, $temp);
		}
	}

	/**
	 * Gets files id from site.
	 * @param int $siteId Site id.
	 * @return array
	 */
	public static function getFilesFromSite($siteId)
	{
		return self::getFiles(
			$siteId,
			self::ENTITY_TYPE_SITE
		);
	}

	/**
	 * Delete record from Site.
	 * @param int $id Site id.
	 * @param int|array $fileId File id (by default delete all files from landing).
	 * @return void
	 */
	public static function deleteFromSite($id, $fileId = array())
	{
		self::delete($fileId, $id, self::ENTITY_TYPE_SITE);
	}

	/**
	 * Add new record for Landing.
	 * @param int $lid Landing id.
	 * @param int $fileId File id.
	 * @return void
	 */
	public static function addToLanding($lid, $fileId)
	{
		if ($fileId > 0 && $lid > 0)
		{
			self::add($fileId, $lid, self::ENTITY_TYPE_LANDING);
		}
	}

	/**
	 * Gets files id from landing.
	 * @param int $landingId Landing id.
	 * @return array
	 */
	public static function getFilesFromLanding($landingId)
	{
		return self::getFiles(
			$landingId,
			self::ENTITY_TYPE_LANDING
		);
	}

	/**
	 * Delete record from Landing.
	 * @param int $lid Landing id.
	 * @param int|array $fileId File id (by default delete all files from landing).
	 * @return void
	 */
	public static function deleteFromLanding($lid, $fileId = array())
	{
		self::delete($fileId, $lid, self::ENTITY_TYPE_LANDING);
	}

	/**
	 * Add new record(s) for Block.
	 * @param int $blockId Block id.
	 * @param int|array $fileId File id (or file ids).
	 * @param bool $temp This is temporary file.
	 * @return void
	 */
	public static function addToBlock(int $blockId, $fileId, bool $temp = false): void
	{
		if ($blockId > 0)
		{
			if (!is_array($fileId))
			{
				$fileId = array($fileId);
			}
			foreach ($fileId as $fid)
			{
				if ($fid > 0)
				{
					self::add($fid, $blockId, self::ENTITY_TYPE_BLOCK, $temp);
				}
			}
		}
	}

	/**
	 * Add new record(s) for Block (old records will be deleted).
	 * @param int $blockId Block id.
	 * @param int|array $fileId File id (or file ids).
	 * @return void
	 */
	public static function replaceInBlock($blockId, $fileId)
	{
		if ($blockId > 0)
		{
			if (!is_array($fileId))
			{
				$fileId = array($fileId);
			}
			$res = FileTable::getList(array(
				'select' => array(
					'FILE_ID'
				),
				'filter' => array(
					'ENTITY_ID' => $blockId,
					'=ENTITY_TYPE' => self::ENTITY_TYPE_BLOCK
				)
			));
			while ($row = $res->fetch())
			{
				if (!in_array($row['FILE_ID'], $fileId))
				{
					self::delete($row['FILE_ID'], $blockId, self::ENTITY_TYPE_BLOCK);
				}
			}
			self::addToBlock($blockId, $fileId);
		}
	}

	/**
	 * Delete record from Block.
	 * @param int $blockId Block id.
	 * @param int|array $fileId File id (by default delete all files from block).
	 * @return void
	 */
	public static function deleteFromBlock($blockId, $fileId = array())
	{
		self::delete($fileId, $blockId, self::ENTITY_TYPE_BLOCK);
	}

	/**
	 * Parse some content for search data-fileid for the block.
	 * @param int $blockId Block id for content.
	 * @param string $content Content.
	 * @return array
	 */
	public static function getFilesFromBlockContent($blockId, $content)
	{
		$fileIds = array();
		// parse from content
		if (preg_match_all('/data-fileid[2x]{0,2}="([\d]+)"/i', $content, $matches))
		{
			foreach ($matches[1] as $fid)
			{
				$fileIds[] = $fid;
			}
		}
		// check if files ids set in blockId
		if (!empty($fileIds))
		{
			$res = FileTable::getList(array(
				'select' => array(
					'FILE_ID'
				),
				'filter' => array(
					'FILE_ID' => $fileIds,
					'ENTITY_ID' => $blockId,
					'=ENTITY_TYPE' => self::ENTITY_TYPE_BLOCK
				)
			));
			$fileIds = array();
			while ($row = $res->fetch())
			{
				$fileIds[] = $row['FILE_ID'];
			}
		}
		return $fileIds;
	}

	/**
	 * Gets files id from block.
	 * @param int $blockId Block id.
	 * @return array
	 */
	public static function getFilesFromBlock($blockId)
	{
		return self::getFiles(
			$blockId,
			self::ENTITY_TYPE_BLOCK
		);
	}

	/**
	 * Add new record for Asset.
	 * @param int $assetId Id of landing to which attached asset.
	 * @param int $fileId File id.
	 * @return void
	 */
	public static function addToAsset($assetId, $fileId): void
	{
		if ($fileId > 0 && $assetId > 0)
		{
			self::add($fileId, $assetId, self::ENTITY_TYPE_ASSET);
			self::markAssetRebuilded($assetId);
			// todo: res from add and check error
		}
	}

	/**
	 * Gets asset files for current landing.
	 * @param int $assetId Id of landing to which attached asset.
	 * @return array
	 */
	public static function getFilesFromAsset($assetId): array
	{
		return self::getFiles(
			$assetId,
			self::ENTITY_TYPE_ASSET
		);
	}

	/**
	 * Delete asset files for current landing.
	 * Not remove from disk immediately, just marked for agent
	 * @param int $assetId Id of landing to which attached asset.
	 * @param int|int[] $fileId File id (by default delete all files from Asset).
	 * @return void
	 */
	public static function deleteFromAsset(int $assetId, $fileId = []): void
	{
		self::delete($fileId, $assetId, self::ENTITY_TYPE_ASSET);
	}

	/**
	 * Mark file as "need rebuild", but not delete them. File will be exist until not created new file.
	 * @param int|int[] $assetId Id of landing to which attached asset. If not set - will marked all.
	 * @return bool
	 */
	public static function markAssetToRebuild($assetId = []): bool
	{
		$filter = [
			'=ENTITY_TYPE' => self::ENTITY_TYPE_ASSET
		];
		if ($assetId)
		{
			$filter['ENTITY_ID'] = $assetId;
		}

		$res = FileTable::getList([
			'select' => ['ID', 'ENTITY_ID'],
			'filter' => $filter
		]);
		$files = $res->fetchAll();
		$result = true;
		foreach ($files as $file)
		{
			$resUpdate = FileTable::update(
				$file['ID'],
				[
					'ENTITY_ID' => -1 * abs($file['ENTITY_ID'])
				]
			);
			$result = $result && $resUpdate->isSuccess();
		}

		return count($files) > 0 ? $result : false;
	}

	/**
	 * When file rebuilded - delete old files (marked as "need rebuild") for current asset ID (current landing)
	 * @param int|int[] $assetId Id of landing to which attached asset.
	 * @return void
	 */
	public static function markAssetRebuilded($assetId): void
	{
		if(!is_array($assetId))
		{
			$assetId = [$assetId];
		}

		foreach ($assetId as $key => $id)
		{
			self::deleteFromAsset(-1 * abs($id));
		}
	}

	/**
	 * Copy files from one entity to another.
	 * @param int $from Entity id.
	 * @param int $to Entity id.
	 * @param string $entityType Entity type.
	 * @return void
	 */
	protected static function copyEntityFiles($from, $to, $entityType)
	{
		$res = FileTable::getList(array(
			'select' => array(
				'FILE_ID'
			),
			'filter' => array(
				'ENTITY_ID' => $from,
				'=ENTITY_TYPE' => $entityType
			)
		));
		while ($row = $res->fetch())
		{
			FileTable::add(array(
				'FILE_ID' => $row['FILE_ID'],
				'ENTITY_ID' => $to,
				'ENTITY_TYPE' => $entityType
			));
		}
	}

	/**
	 * Copy files from one site to another.
	 * @param int $from Site id.
	 * @param int $to Site id.
	 * @return void
	 */
	public static function copySiteFiles($from, $to)
	{
		self::copyEntityFiles($from, $to, self::ENTITY_TYPE_SITE);
	}

	/**
	 * Copy files from one landing to another.
	 * @param int $from Landing id.
	 * @param int $to Landing id.
	 * @return void
	 */
	public static function copyLandingFiles($from, $to)
	{
		self::copyEntityFiles($from, $to, self::ENTITY_TYPE_LANDING);
	}

	/**
	 * Copy files from one block to another.
	 * @param int $from Block id.
	 * @param int $to Block id.
	 * @return void
	 */
	public static function copyBlockFiles($from, $to)
	{
		self::copyEntityFiles($from, $to, self::ENTITY_TYPE_BLOCK);
	}

	/**
	 * Gets core file array.
	 * @param int $fileId File id.
	 * @return mixed
	 */
	public static function getFileArray($fileId)
	{
		$file = \CFile::getFileArray(
			$fileId
		);
		if (
			isset($file['MODULE_ID']) &&
			$file['MODULE_ID'] == 'landing'
		)
		{
			return $file;
		}
		return false;
	}

	/**
	 * Gets core file path.
	 * @param int $fileId File id.
	 * @return string|null
	 */
	public static function getFilePath($fileId): ?string
	{
		$file = self::getFileArray($fileId);
		if (isset($file['SRC']))
		{
			return $file['SRC'];
		}
		return null;
	}

	/**
	 * Delete all file Id from File table.
	 * @param int $fileId File id to delete.
	 * @return void
	 */
	public static function releaseFile(int $fileId): void
	{
		$res = FileTable::getList(array(
			'select' => [
				'ID'
			],
			'filter' => [
				'FILE_ID' => $fileId
			]
		));
		while ($row = $res->fetch())
		{
			FileTable::delete($row['ID']);
		}
	}

	/**
	 * Physical delete file.
	 * @param int $fileId File id.
	 * @return void
	 */
	public static function deletePhysical(int $fileId): void
	{
		if (self::getFileArray($fileId))
		{
			self::releaseFile($fileId);
			\CFile::delete($fileId);
		}
	}
}