Your IP : 18.188.213.50


Current Path : /var/www/admin_ftp_12/data/www/httpdocs/bitrix/modules/translate/lib/controller/asset/
Upload File :
Current File : /var/www/admin_ftp_12/data/www/httpdocs/bitrix/modules/translate/lib/controller/asset/collect.php

<?php
namespace Bitrix\Translate\Controller\Asset;

use Bitrix\Main;
use Bitrix\Main\Error;
use Bitrix\Main\Localization\Loc;
use Bitrix\Translate;
use Bitrix\Translate\Index;


/**
 * Harvester of the lang folder disposition.
 */
class Collect
	extends Translate\Controller\Action
	implements Translate\Controller\ITimeLimit, Translate\Controller\IProcessParameters
{
	use Translate\Controller\Stepper;
	use Translate\Controller\ProcessParams;

	/** @var string */
	private $seekPathLangId;

	/** @var string */
	private $languageId;

	/** @var bool */
	private $convertEncoding;

	/** @var string */
	private $encoding;

	/** @var string */
	private $assemblyDate;

	/** @var bool */
	private $packFile;

	/** @var string */
	private $tmpFolderPath;

	/** @var int */
	private $totalFileCount;

	/** @var string */
	public static $documentRoot;
	/** @var boolean */
	public static $useTranslationRepository;
	/** @var string[] */
	public static $enabledLanguages;
	/** @var string[] */
	public static $allowedEncodings;
	/** @var string[] */
	public static $translationRepositoryLanguages;


	/**
	 * \Bitrix\Main\Engine\Action constructor.
	 *
	 * @param string $name Action name.
	 * @param Main\Engine\Controller $controller Parent controller object.
	 * @param array $config Additional configuration.
	 */
	public function __construct($name, Main\Engine\Controller $controller, array $config = [])
	{
		$this->keepField([
			'seekPathLangId', 'convertEncoding', 'encoding', 'assemblyDate',
			'languageId', 'packFile', 'tmpFolderPath', 'totalFileCount'
		]);

		parent::__construct($name, $controller, $config);

		self::$useTranslationRepository = Main\Localization\Translation::useTranslationRepository();
		self::$enabledLanguages = Translate\Config::getEnabledLanguages();
		self::$allowedEncodings = Translate\Config::getAllowedEncodings();
		self::$documentRoot = rtrim(Translate\IO\Path::tidy(Main\Application::getDocumentRoot()), '/');

		if (self::$useTranslationRepository)
		{
			self::$translationRepositoryLanguages = Translate\Config::getTranslationRepositoryLanguages();
		}
	}

	/**
	 * Runs controller action.
	 *
	 * @param string $path Stating path.
	 * @param boolean $runBefore Flag to run onBeforeRun event handler.
	 * @return array
	 */
	public function run($path = '', $runBefore = false)
	{
		if ($runBefore)
		{
			$this->onBeforeRun();
		}

		if (empty($path))
		{
			$path = Grabber::START_PATH;
		}

		$path = '/'. trim($path, '/.\\');

		if ($this->isNewProcess)
		{
			$this->clearProgressParameters();
			$this->totalItems = 0;
			$this->processedItems = 0;
			$this->totalFileCount = 0;

			// language
			$languageId = $this->controller->getRequest()->get('languageId');
			if (empty($languageId))
			{
				$this->addError(new Main\Error(Loc::getMessage('TR_ERROR_SELECT_LANGUAGE')));
			}
			if (!in_array($languageId, self::$enabledLanguages))
			{
				$this->addError(new Main\Error(Loc::getMessage('TR_ERROR_LANGUAGE_ID')));
			}
			else
			{
				$this->languageId = $languageId;
			}

			// convert encoding
			$this->convertEncoding = ($this->controller->getRequest()->get('convertEncoding') === 'Y');

			//  encoding
			$encoding = $this->controller->getRequest()->get('encoding');
			if ($encoding !== null && in_array($encoding, self::$allowedEncodings))
			{
				$this->encoding = $encoding;
			}
			elseif ($this->convertEncoding)
			{
				$this->addError(new Main\Error(Loc::getMessage('TR_ERROR_ENCODING')));
			}

			if ($this->convertEncoding)
			{
				if (self::$useTranslationRepository)
				{
					$encodingIn = Main\Localization\Translation::getSourceEncoding($this->languageId);
					$encodingOut = $this->encoding;
					if ($encodingIn === 'utf-8' && $encodingOut !== 'utf-8')
					{
						$this->addError(new Error(Loc::getMessage('TR_ERROR_LANGUAGE_CHARSET_NON_UTF')));
					}
				}
				elseif (Translate\Config::isUtfMode())
				{
					$encodingIn = 'utf-8';
					$encodingOut = $this->encoding;
					if (Translate\Config::getCultureEncoding($this->languageId) !== 'utf-8')
					{
						$this->addError(new Error(Loc::getMessage('TR_ERROR_LANGUAGE_CHARSET_NON_UTF')));
					}
				}
				else
				{
					$encodingIn = Translate\Config::getCultureEncoding($this->languageId);
					if (!$encodingIn)
					{
						$encodingIn = Main\Localization\Translation::getCurrentEncoding();
					}
					$this->encoding = $encodingOut = 'utf-8';
				}

				$this->convertEncoding = (\mb_strtolower($encodingIn) !== \mb_strtolower($encodingOut));
			}

			// assembly date
			$assemblyDate = $this->controller->getRequest()->get('assemblyDate');
			if ($assemblyDate !== null && \preg_replace("/[\D]+/", "", $assemblyDate) && \mb_strlen($assemblyDate) == 8)
			{
				$this->assemblyDate = $assemblyDate;
			}
			else
			{
				$this->addError(new Main\Error(Loc::getMessage('TR_ERROR_LANGUAGE_DATE')));
			}


			// pack
			$this->packFile = ($this->controller->getRequest()->get('packFile') === 'Y');


			if (!$this->hasErrors())
			{
				$exportFolder = Translate\Config::getExportFolder();
				if (!empty($exportFolder))
				{
					$tempDir = new Translate\IO\Directory($exportFolder.'/'.$this->languageId);
					if ($tempDir->isExists())
					{
						$tempDir->wipe();
					}
					else
					{
						$tempDir->create();
					}
				}
				else
				{
					$tempDir = Translate\IO\Directory::generateTemporalDirectory('translate');
					$tempDir = $tempDir->createSubdirectory($this->languageId);
				}
				$this->tmpFolderPath = $tempDir->getPhysicalPath(). '/';
				if (!$tempDir->isExists())
				{
					$this->addError(
						new Error(Loc::getMessage('TR_ERROR_CREATE_TEMP_FOLDER', ['#PATH#' => $this->tmpFolderPath]))
					);
				}
			}

			if (!$this->hasErrors())
			{
				$fileDateMarkFullPath = $this->tmpFolderPath.
					\str_replace('#LANG_ID#', $this->languageId, Translate\SUPD_LANG_DATE_MARK);

				Translate\IO\Path::checkCreatePath(\dirname($fileDateMarkFullPath));

				$fileDateMark = new Main\IO\File($fileDateMarkFullPath);
				if ($fileDateMark->putContents($assemblyDate) === false)
				{
					$this->addError(
						new Error(Loc::getMessage('TR_ERROR_OPEN_FILE', ['#FILE#' => $fileDateMarkFullPath]))
					);
				}
			}

			$this->totalItems = (int)Index\Internals\PathLangTable::getCount(['=%PATH' => $path.'%']);
			$this->processedItems = 0;

			$this->saveProgressParameters();

			return [
				'STATUS' => ($this->totalItems > 0 ? Translate\Controller\STATUS_PROGRESS : Translate\Controller\STATUS_COMPLETED),
				'PROCESSED_ITEMS' => 0,
				'TOTAL_ITEMS' => $this->totalItems,
			];
		}

		$progressParams = $this->getProgressParameters();

		$this->languageId = $progressParams['languageId'];
		$this->convertEncoding = $progressParams['convertEncoding'];
		$this->encoding = $progressParams['encoding'];
		$this->assemblyDate = $progressParams['assemblyDate'];
		$this->packFile = $progressParams['packFile'];
		$this->tmpFolderPath = $progressParams['tmpFolderPath'];

		if (isset($progressParams['totalItems']) && (int)$progressParams['totalItems'] > 0)
		{
			$this->totalItems = (int)$progressParams['totalItems'];
			$this->processedItems = (int)$progressParams['processedItems'];
			$this->totalFileCount = (int)$progressParams['totalFileCount'];
		}

		if (isset($progressParams['seekPathLangId']))
		{
			$this->seekPathLangId = $progressParams['seekPathLangId'];
		}

		return $this->performStep('runCollecting', ['path' => $path]);
	}


	/**
	 * Copying lang files.
	 *
	 * @param array $params Parameters.
	 * @return array
	 */
	private function runCollecting(array $params = [])
	{
		if ($this->convertEncoding)
		{
			$sourceEncoding = Main\Localization\Translation::getSourceEncoding($this->languageId);
		}

		if (isset($params['path']))
		{
			$path = $params['path'];
		}
		else
		{
			$path = Grabber::START_PATH;
		}

		$pathFilter = [
			'=%PATH' => $path.'%'
		];
		if (!empty($this->seekPathLangId))
		{
			$pathFilter['>ID'] = $this->seekPathLangId;
		}

		$cachePathLangRes = Index\Internals\PathLangTable::getList([
			'filter' => $pathFilter,
			'order' => ['ID' => 'ASC'],
			'select' => ['ID', 'PATH'],
		]);
		$processedItemCount = 0;
		while ($pathLang = $cachePathLangRes->fetch())
		{
			foreach ($this->lookThroughLangFolder($pathLang['PATH']. '/'.$this->languageId) as $filePaths)
			{
				foreach ($filePaths as $langFilePath => $fullPath)
				{
					$targetFolder = new Main\IO\Directory($this->tmpFolderPath. \dirname($langFilePath));
					if (!$targetFolder->isExists())
					{
						$targetFolder->create();
					}

					$source = new Main\IO\File($fullPath);
					$target = new Main\IO\File($targetFolder->getPhysicalPath(). '/'. \basename($langFilePath));

					try
					{
						$content = $source->getContents();
						$content = \str_replace(["\r\n", "\r"], ["\n", "\n"], $content);

						if ($this->convertEncoding)
						{
							$content = Main\Text\Encoding::convertEncoding($content, $sourceEncoding, $this->encoding);
						}

						$target->putContents($content);
						$this->totalFileCount ++;
					}
					catch (Main\IO\IoException $exception)
					{
						$this->addError(new Main\Error($exception->getMessage()));
					}

					// check user abortion
					if (\connection_status() !== \CONNECTION_NORMAL)
					{
						throw new Main\SystemException('Process has been broken course user aborted connection.');
					}
				}
			}

			$processedItemCount ++;

			if ($this->instanceTimer()->hasTimeLimitReached())
			{
				$this->seekPathLangId = (int)$pathLang['ID'];
				break;
			}
		}

		$this->processedItems += $processedItemCount;

		$result = [
			'PROCESSED_ITEMS' => $this->processedItems,
			'TOTAL_ITEMS' => $this->totalItems,
		];

		if ($this->instanceTimer()->hasTimeLimitReached() !== true)
		{
			$this->declareAccomplishment();

			// we have to continue process in next action
			$this->processToken = null;
			$this->seekPathLangId = null;
			$this->saveProgressParameters();

			$messagePlaceholders = [
				'#TOTAL_FILES#' => $this->totalFileCount,
				'#LANG#' => \mb_strtoupper($this->languageId),
				'#PATH#' => '~tmp~',
			];
			$result['SUMMARY'] = Loc::getMessage('TR_LANGUAGE_COLLECTED_FOLDER', $messagePlaceholders);
		}

		return $result;
	}


	/**
	 * Runs through lang folder and collects full path to lang files.
	 *
	 * @param string $langFolderRelPath Relative project path of the language folder.
	 *
	 * @return \Generator|array
	 */
	private function lookThroughLangFolder($langFolderRelPath)
	{
		$files = [];
		$folders = [];

		$langFolderFullPath = Translate\IO\Path::tidy(self::$documentRoot.'/'.$langFolderRelPath);

		$storeFolderRelPath = \str_replace(Grabber::START_PATH, '', $langFolderRelPath);

		if (self::$useTranslationRepository && \in_array($this->languageId, self::$translationRepositoryLanguages))
		{
			$langFolderFullPath = Main\Localization\Translation::convertLangPath($langFolderFullPath, $this->languageId);
		}

		$childrenList = Translate\IO\FileSystemHelper::getFileList($langFolderFullPath);
		if (!empty($childrenList))
		{
			foreach ($childrenList as $fullPath)
			{
				$name = \basename($fullPath);
				if (\in_array($name, Translate\IGNORE_FS_NAMES))
				{
					continue;
				}

				if (Translate\IO\Path::isPhpFile($fullPath, true))
				{
					$files[$storeFolderRelPath.'/'.$name] = $fullPath;
				}
			}
		}

		// dir only
		$childrenList = Translate\IO\FileSystemHelper::getFolderList($langFolderFullPath);
		if (!empty($childrenList))
		{
			$ignoreDev = \implode('|', Translate\IGNORE_MODULE_NAMES);
			foreach ($childrenList as $fullPath)
			{
				$name = \basename($fullPath);
				if (\in_array($name, Translate\IGNORE_FS_NAMES))
				{
					continue;
				}

				$relPath = $langFolderRelPath.'/'.$name;

				if (!\is_dir($fullPath))
				{
					continue;
				}

				if (\in_array($relPath, Translate\IGNORE_BX_NAMES))
				{
					continue;
				}

				// /bitrix/modules/[smth]/dev/
				if (\preg_match("#^bitrix/modules/[^/]+/({$ignoreDev})#", \trim($relPath, '/')))
				{
					continue;
				}

				if (\in_array($name, Translate\IGNORE_LANG_NAMES))
				{
					continue;
				}

				$folders[$langFolderRelPath.'/'.$name] = $langFolderRelPath.'/'.$name;
			}
		}

		if (\count($files) > 0)
		{
			yield $files;
		}

		if (\count($folders) > 0)
		{
			foreach ($folders as $subFolderPath)
			{
				foreach ($this->lookThroughLangFolder($subFolderPath) as $subFiles)// go deeper
				{
					yield $subFiles;
				}
			}
		}
	}


	/**
	 * Returns progress option name
	 *
	 * @return string
	 */
	public function getProgressParameterOptionName()
	{
		$controller = $this->getController();
		return $controller::SETTING_ID;
	}
}