PageRenderTime 26ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/translate/lib/componentbase.php

https://gitlab.com/alexprowars/bitrix
PHP | 558 lines | 375 code | 66 blank | 117 comment | 48 complexity | 9e8f488a8bac0e7733895ed55cbdf585 MD5 | raw file
  1. <?php
  2. namespace Bitrix\Translate;
  3. use Bitrix\Main;
  4. use Bitrix\Main\Error;
  5. use Bitrix\Main\Localization;
  6. use Bitrix\Main\Localization\Loc;
  7. use Bitrix\Translate;
  8. abstract class ComponentBase
  9. extends \CBitrixComponent
  10. implements Translate\IErrorable
  11. {
  12. use Translate\Error;
  13. use Translate\Warning;
  14. const STATUS_SUCCESS = 'success';
  15. const STATUS_DENIED = 'denied';
  16. const STATUS_ERROR = 'error';
  17. const TEMPLATE_ERROR = 'error';
  18. /** @var string */
  19. protected $path;
  20. /** @var int Session tab counter. */
  21. protected $tabId = 0;
  22. /**
  23. * @return boolean
  24. */
  25. protected function checkModuleAvailability()
  26. {
  27. if (!Main\Loader::includeModule('translate'))
  28. {
  29. if ($this->isAjaxRequest())
  30. {
  31. $this->sendJsonResponse(new Error('Module "translate" is not installed.', self::STATUS_ERROR));
  32. }
  33. else
  34. {
  35. $this->addError(new Error('Module "translate" is not installed.', self::STATUS_ERROR));
  36. $this->includeComponentTemplate(self::TEMPLATE_ERROR);
  37. }
  38. return false;
  39. }
  40. return true;
  41. }
  42. /**
  43. * Checks if user has permission to view language file.
  44. * @param \CUser $user User to check permissions.
  45. * @return boolean
  46. */
  47. protected function hasUserPermissionView($user)
  48. {
  49. return Translate\Permission::canView($user);
  50. }
  51. /**
  52. * Checks if user has permission to edit language file.
  53. * @param \CUser $user User to check permissions.
  54. * @return boolean
  55. */
  56. protected function hasUserPermissionEdit($user)
  57. {
  58. return Translate\Permission::canEdit($user);
  59. }
  60. /**
  61. * Checks if user has permission to edit source language file.
  62. * @param \CUser $user User to check permissions.
  63. * @return boolean
  64. */
  65. protected function hasUserPermissionEditSource($user)
  66. {
  67. return Translate\Permission::canEditSource($user);
  68. }
  69. /**
  70. * Checks if user has permission to view language file.
  71. * @return boolean
  72. */
  73. protected function checkPermissionView()
  74. {
  75. if (!$this->hasUserPermissionView($this->getUser()))
  76. {
  77. if ($this->isAjaxRequest())
  78. {
  79. $this->sendJsonResponse(new Error(Loc::getMessage('TRANSLATE_FILTER_ERROR_ACCESS_DENIED'), self::STATUS_DENIED));
  80. }
  81. else
  82. {
  83. $this->addError(new Error(Loc::getMessage('TRANSLATE_FILTER_ERROR_ACCESS_DENIED'), self::STATUS_DENIED));
  84. $this->includeComponentTemplate(self::TEMPLATE_ERROR);
  85. }
  86. return false;
  87. }
  88. return true;
  89. }
  90. /**
  91. * Checks if user has permission to edit language file.
  92. * @return boolean
  93. */
  94. protected function checkPermissionEdit()
  95. {
  96. if (!$this->hasUserPermissionEdit($this->getUser()))
  97. {
  98. if ($this->isAjaxRequest())
  99. {
  100. $this->sendJsonResponse(new Error(Loc::getMessage('TRANSLATE_FILTER_ERROR_WRITING_RIGHTS'), self::STATUS_DENIED));
  101. }
  102. else
  103. {
  104. $this->addError(new Error(Loc::getMessage('TRANSLATE_FILTER_ERROR_WRITING_RIGHTS'), self::STATUS_DENIED));
  105. $this->includeComponentTemplate(self::TEMPLATE_ERROR);
  106. }
  107. return false;
  108. }
  109. return true;
  110. }
  111. /**
  112. * Checks if user has permission to edit source language file.
  113. * @return boolean
  114. */
  115. protected function checkPermissionEditPhp()
  116. {
  117. if (!$this->hasUserPermissionEditSource($this->getUser()))
  118. {
  119. if ($this->isAjaxRequest())
  120. {
  121. $this->sendJsonResponse(new Error(Loc::getMessage('TRANSLATE_FILTER_ERROR_PHP_EDIT_RIGHTS'), self::STATUS_DENIED));
  122. }
  123. else
  124. {
  125. $this->addError(new Error(Loc::getMessage('TRANSLATE_FILTER_ERROR_PHP_EDIT_RIGHTS'), self::STATUS_DENIED));
  126. $this->includeComponentTemplate(self::TEMPLATE_ERROR);
  127. }
  128. return false;
  129. }
  130. return true;
  131. }
  132. /**
  133. * Checks some mysql config variables.
  134. * @return boolean
  135. */
  136. protected function checkMysqlConfig()
  137. {
  138. $majorVersion = (int)mb_substr(\Bitrix\Main\Application::getConnection()->getVersion()[0], 0, 1);
  139. if ($majorVersion >= 8)
  140. {
  141. $conf = Main\Application::getConnection()->query("SHOW VARIABLES LIKE 'regexp_time_limit'")->fetch();
  142. if ($conf['Variable_name'] == 'regexp_time_limit')
  143. {
  144. if ((int)$conf['Value'] <= 0)
  145. {
  146. $this->addWarning(new Error(Loc::getMessage('TRANSLATE_MYSQL_CONFIG_ERROR_REGEXP_TIME_LIMIT'), self::STATUS_ERROR));
  147. }
  148. }
  149. }
  150. return true;
  151. }
  152. /**
  153. * @return void
  154. */
  155. protected function prepareParams()
  156. {
  157. $params =& $this->getParams();
  158. if (empty($params['CURRENT_LANG']))
  159. {
  160. $params['CURRENT_LANG'] = Loc::getCurrentLang();
  161. }
  162. if (empty($params['LIST_PATH']))
  163. {
  164. $params['LIST_PATH'] = '/bitrix/admin/translate_list.php';
  165. }
  166. if (empty($params['EDIT_PATH']))
  167. {
  168. $params['EDIT_PATH'] = '/bitrix/admin/translate_edit.php';
  169. }
  170. if (empty($params['SHOW_SOURCE_PATH']))
  171. {
  172. $params['SHOW_SOURCE_PATH'] = '/bitrix/admin/translate_show_php.php';
  173. }
  174. if (empty($params['EDIT_SOURCE_PATH']))
  175. {
  176. $params['EDIT_SOURCE_PATH'] = '/bitrix/admin/translate_edit_php.php';
  177. }
  178. $params['SET_TITLE'] = isset($params['SET_TITLE']) ? $params['SET_TITLE'] === 'Y' : true;
  179. $this->arResult['IS_AJAX_REQUEST'] = $this->isAjaxRequest();
  180. $this->arResult['ALLOW_VIEW'] = $this->hasUserPermissionView($this->getUser());
  181. $this->arResult['ALLOW_EDIT'] = $this->hasUserPermissionEdit($this->getUser());
  182. $this->arResult['ALLOW_EDIT_SOURCE'] = $this->hasUserPermissionEditSource($this->getUser());
  183. }
  184. /**
  185. * Moves current language to the first position.
  186. *
  187. * @param string[] $languageList
  188. * @param string $currentLangId
  189. *
  190. * @return string[]
  191. */
  192. protected function rearrangeLanguages($languageList, $currentLangId)
  193. {
  194. $inx = array_search($currentLangId, $languageList, true);
  195. if ($inx !== false)
  196. {
  197. unset($languageList[$inx]);
  198. }
  199. array_unshift($languageList, $currentLangId);
  200. return $languageList;
  201. }
  202. /**
  203. * @return string[]
  204. */
  205. protected function getLanguages()
  206. {
  207. static $languagesList;
  208. if (empty($languagesList))
  209. {
  210. $languagesList = Translate\Config::getEnabledLanguages();
  211. }
  212. return $languagesList;
  213. }
  214. /**
  215. * Returns list of language names from the site settings.
  216. *
  217. * @param string[] $languageIds Languages list to get name.
  218. *
  219. * @return array
  220. */
  221. protected function getLanguagesTitle($languageIds)
  222. {
  223. return Translate\Config::getLanguagesTitle($languageIds);
  224. }
  225. /**
  226. * Return languages compatible by their encoding.
  227. *
  228. * @return string[]
  229. */
  230. protected function getCompatibleLanguages()
  231. {
  232. static $languages = array();
  233. if (empty($languages))
  234. {
  235. $currentEncoding = Localization\Translation::getCurrentEncoding();
  236. $currentLang = Loc::getCurrentLang();
  237. $limitEncoding = !($currentEncoding == 'utf-8' || Localization\Translation::useTranslationRepository());
  238. $isEncodingCompatible = function ($langId) use ($limitEncoding, $currentEncoding, $currentLang)
  239. {
  240. $compatible = true;
  241. if ($limitEncoding)
  242. {
  243. $compatible = (
  244. $langId == $currentLang ||
  245. Translate\Config::getCultureEncoding($langId) == $currentEncoding ||
  246. $langId == 'en'
  247. );
  248. }
  249. return $compatible;
  250. };
  251. $enabledLanguages = $this->getLanguages();
  252. foreach ($enabledLanguages as $langId)
  253. {
  254. if ($limitEncoding && !$isEncodingCompatible($langId))
  255. {
  256. continue;
  257. }
  258. $languages[] = $langId;
  259. }
  260. }
  261. return $languages;
  262. }
  263. /**
  264. * @return string
  265. */
  266. protected function detectTabId()
  267. {
  268. $tabId = $this->request->get('tabId');
  269. if (!empty($tabId) && (int)$tabId > 0)
  270. {
  271. $this->tabId = (int)$tabId;
  272. }
  273. elseif ($this->isAjaxRequest())
  274. {
  275. $this->tabId = Translate\Filter::getTabId(false);
  276. }
  277. else
  278. {
  279. $this->tabId = Translate\Filter::getTabId();
  280. }
  281. return $this->tabId;
  282. }
  283. /**
  284. * @return string
  285. */
  286. protected function detectStartingPath(?string $path = ''): string
  287. {
  288. $home = Translate\Config::getDefaultPath();
  289. $initPaths = Translate\Config::getInitPath();
  290. if (count($initPaths) > 0)
  291. {
  292. $home = $initPaths[0];
  293. if (!empty($path))
  294. {
  295. foreach ($initPaths as $initPath)
  296. {
  297. if (mb_strpos($path, $initPath) === 0)
  298. {
  299. $home = $initPath;
  300. break;
  301. }
  302. }
  303. }
  304. }
  305. return $home;
  306. }
  307. /**
  308. * Returns component calling params by reference.
  309. * @return array
  310. */
  311. public function &getParams()
  312. {
  313. return $this->arParams;
  314. }
  315. /**
  316. * Returns component resulting array by reference.
  317. * @return array
  318. */
  319. public function &getResult()
  320. {
  321. return $this->arResult;
  322. }
  323. /**
  324. * @return \CUser
  325. */
  326. protected function getUser()
  327. {
  328. /** @global \CUser $USER */
  329. global $USER;
  330. return $USER;
  331. }
  332. /**
  333. * @return \CMain
  334. */
  335. protected function getApplication()
  336. {
  337. /** @global \CMain $APPLICATION */
  338. global $APPLICATION;
  339. return $APPLICATION;
  340. }
  341. /**
  342. * Returns whether this is an AJAX (XMLHttpRequest) request.
  343. * @return boolean
  344. */
  345. protected function isAjaxRequest()
  346. {
  347. return
  348. ($this->request->isAjaxRequest() || $this->request->get('AJAX_CALL') !== null) &&
  349. $this->request->getRequestMethod() == 'POST';
  350. }
  351. /**
  352. * Sends Json response to client.
  353. *
  354. * @param array|object|Main\Error $response Response to send.
  355. *
  356. * @throws Main\ArgumentException
  357. * @return void
  358. */
  359. protected function sendJsonResponse($response)
  360. {
  361. $this->getApplication()->restartBuffer();
  362. $answer = Main\Application::getInstance()->getContext()->getResponse();
  363. if ($response instanceof Main\Error)
  364. {
  365. $this->addError($response);
  366. $response = array();
  367. }
  368. $response['result'] = true;
  369. if ($this->hasErrors())
  370. {
  371. $answer->setStatus('500 Internal Server Error');
  372. $response['status'] = self::STATUS_ERROR;
  373. $errors = array();
  374. foreach ($this->getErrors() as $error)
  375. {
  376. /** @var Main\Error $error */
  377. $errors[] = array(
  378. 'message' => $error->getMessage(),
  379. 'code' => $error->getCode(),
  380. );
  381. }
  382. $response['result'] = false;
  383. $response['errors'] = $errors;
  384. }
  385. elseif (!isset($response['status']))
  386. {
  387. $response['status'] = self::STATUS_SUCCESS;
  388. }
  389. $answer->addHeader('Content-Type', 'application/x-javascript; charset=UTF-8');
  390. echo Main\Web\Json::encode($response);
  391. \CMain::finalActions();
  392. die;
  393. }
  394. /**
  395. * Drops saved options.
  396. * @param string $category Group option name.
  397. * @param string $nameMask Option name mask.
  398. * @return void
  399. */
  400. protected function clearSavedOptions($category, $nameMask)
  401. {
  402. $res = \CUserOptions::GetList(false,['CATEGORY' => $category, 'USER_ID' => $this->getUser()->getId(), 'NAME_MASK' => $nameMask]);
  403. while ($opt = $res->fetch())
  404. {
  405. \CUserOptions::DeleteOption($category, $opt['NAME']);
  406. }
  407. }
  408. /**
  409. * Finds way to get back.
  410. *
  411. * @param string $path Path to analise.
  412. *
  413. * @return string
  414. */
  415. protected function detectPathBack($path)
  416. {
  417. static $pathBackCache = array();;
  418. if (!isset($pathBackCache[$path]))
  419. {
  420. $pathBack = dirname($path);
  421. $slash = explode('/', $pathBack);
  422. if (is_array($slash))
  423. {
  424. $slashTmp = $slash;
  425. $langKey = array_search('lang', $slash) + 1;
  426. unset($slashTmp[$langKey]);
  427. if ($langKey == count($slash) - 1)
  428. {
  429. unset($slash[$langKey]);
  430. $pathBack = implode('/', $slash);
  431. }
  432. }
  433. $pathBackCache[$path] = $pathBack;
  434. }
  435. return $pathBackCache[$path];
  436. }
  437. /**
  438. * Get data for chain links.
  439. *
  440. * @param string $path Path to analise.
  441. *
  442. * @return array
  443. */
  444. protected function generateChainLinks($path)
  445. {
  446. static $chainCache = array();
  447. if (!isset($chainCache[$path]))
  448. {
  449. $params =& $this->getParams();
  450. $chain = array();
  451. $slash = explode('/', dirname($path));
  452. if (is_array($slash))
  453. {
  454. $langKey = array_search('lang', $slash) + 1;
  455. $slash[$langKey] = $params['CURRENT_LANG'];
  456. if ($langKey == count($slash) - 1)
  457. {
  458. unset($slash[$langKey]);
  459. }
  460. $i = 0;
  461. $pathList = array();
  462. foreach ($slash as $dir)
  463. {
  464. $i++;
  465. if ($i == 1)
  466. {
  467. $chain[] = array(
  468. 'link' => $params['LIST_PATH'].
  469. '?lang='.$params['CURRENT_LANG'].
  470. '&tabId='.$this->tabId.
  471. '&path=/',
  472. 'title' => '..'
  473. );
  474. }
  475. else
  476. {
  477. $pathList[] = htmlspecialcharsbx($dir);
  478. $chain[] = array(
  479. 'link' => $params['LIST_PATH'].
  480. '?lang='.$params['CURRENT_LANG'].
  481. '&tabId='.$this->tabId.
  482. '&path=/'.implode('/', $pathList).'/',
  483. 'title' => htmlspecialcharsbx($dir)
  484. );
  485. }
  486. }
  487. }
  488. $chainCache[$path] = $chain;
  489. }
  490. return $chainCache[$path];
  491. }
  492. }