PageRenderTime 36ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/translate/lib/controller/import/csv.php

https://gitlab.com/alexprowars/bitrix
PHP | 437 lines | 310 code | 62 blank | 65 comment | 36 complexity | 7c2d41ca641f1ea1d40b36bda2048c1d MD5 | raw file
  1. <?php
  2. namespace Bitrix\Translate\Controller\Import;
  3. use Bitrix\Main;
  4. use Bitrix\Main\Error;
  5. use Bitrix\Main\Localization\Loc;
  6. use Bitrix\Translate;
  7. class Csv
  8. extends Translate\Controller\Controller
  9. implements Translate\Controller\IProcessParameters
  10. {
  11. use Translate\Controller\ProcessParams;
  12. const SETTING_ID = 'TRANSLATE_IMPORT';
  13. const ACTION_IMPORT = 'import';
  14. const ACTION_PURGE = 'purge';
  15. const ACTION_CANCEL = 'cancel';
  16. const ACTION_UPLOAD = 'upload';
  17. const ACTION_INDEX = 'index';
  18. const ACTION_FINALIZE = 'finalize';
  19. const METHOD_ADD_UPDATE = 'ADD_UPDATE';
  20. const METHOD_UPDATE_ONLY = 'UPDATE_ONLY';
  21. const METHOD_ADD_ONLY = 'ADD_ONLY';
  22. /** @var int Session tab counter. */
  23. private $tabId = 0;
  24. /** @var string */
  25. private $encodingIn;
  26. /** @var string */
  27. private $updateMethod;
  28. /** @var string[] */
  29. private $languages;
  30. /** @var string */
  31. private $csvFilePath;
  32. /** @var boolean */
  33. private $reindex;
  34. /**
  35. * Configures actions.
  36. *
  37. * @return array
  38. */
  39. public function configureActions()
  40. {
  41. $configureActions = parent::configureActions();
  42. $permission = new Translate\Controller\CheckPermission(Translate\Permission::WRITE);
  43. $configureActions[self::ACTION_UPLOAD] = array(
  44. '+prefilters' => array(
  45. new Main\Engine\ActionFilter\HttpMethod([Main\Engine\ActionFilter\HttpMethod::METHOD_POST]),
  46. $permission
  47. ),
  48. );
  49. $configureActions[self::ACTION_IMPORT] = array(
  50. '+prefilters' => array(
  51. $permission
  52. ),
  53. );
  54. $configureActions[self::ACTION_PURGE] = array(
  55. '+prefilters' => array(
  56. $permission
  57. ),
  58. );
  59. $configureActions[self::ACTION_CANCEL] = array(
  60. '+prefilters' => array(
  61. $permission
  62. ),
  63. );
  64. $configureActions[self::ACTION_FINALIZE] = array(
  65. '+prefilters' => array(
  66. $permission
  67. ),
  68. );
  69. $configureActions[self::ACTION_INDEX] = array(
  70. '+prefilters' => array(
  71. new Translate\Controller\CheckPermission(Translate\Permission::READ)
  72. ),
  73. );
  74. return $configureActions;
  75. }
  76. /**
  77. * Initializes controller.
  78. *
  79. * @return void
  80. */
  81. protected function init()
  82. {
  83. parent::init();
  84. $tabId = $this->request->get('tabId');
  85. if (empty($tabId) || (int)$tabId <= 0)
  86. {
  87. throw new Main\ArgumentException("Missing 'tabId' parameter");
  88. }
  89. $this->tabId = (int)$tabId;
  90. $this->keepField(['encodingIn', 'updateMethod', 'csvFilePath', 'languages']);
  91. $params = $this->getProgressParameters();
  92. // languages
  93. $this->languages = Translate\Config::getEnabledLanguages();
  94. // encoding
  95. $enc = $this->request->get('encodingIn');
  96. if ($enc !== null && in_array(mb_strtolower($enc), Translate\Config::getAllowedEncodings()))
  97. {
  98. $this->encodingIn = mb_strtolower($enc);
  99. }
  100. elseif (isset($params['encodingIn']) && in_array($params['encodingIn'], Translate\Config::getAllowedEncodings()))
  101. {
  102. $this->encodingIn = $params['encodingIn'];
  103. }
  104. // update method
  105. $updateMethod = $this->request->get('updateMethod');
  106. if ($updateMethod !== null)
  107. {
  108. if (in_array($updateMethod, [self::METHOD_ADD_ONLY, self::METHOD_UPDATE_ONLY, self::METHOD_ADD_UPDATE]))
  109. {
  110. $this->updateMethod = $updateMethod;
  111. }
  112. }
  113. if (empty($this->updateMethod) && isset($params['updateMethod']))
  114. {
  115. $this->updateMethod = $params['updateMethod'];
  116. }
  117. if (empty($this->updateMethod))
  118. {
  119. $this->updateMethod = self::METHOD_ADD_ONLY;
  120. }
  121. // update index
  122. $reindex = $this->request->get('reindex');
  123. $this->reindex = ($reindex === 'Y');
  124. // file to import
  125. if (isset($params['csvFilePath']))
  126. {
  127. $this->csvFilePath = $params['csvFilePath'];
  128. }
  129. $this->saveProgressParameters();
  130. }
  131. /**
  132. * Runs controller import action.
  133. *
  134. * @return array
  135. */
  136. public function importAction()
  137. {
  138. $action = new Translate\Controller\Import\ImportCsv(
  139. self::ACTION_IMPORT,
  140. $this,
  141. [
  142. 'tabId' => $this->tabId,
  143. 'encodingIn' => $this->encodingIn,
  144. 'updateMethod' => $this->updateMethod,
  145. 'csvFilePath' => $this->csvFilePath,
  146. ]
  147. );
  148. $result = $action->run(true);
  149. if (count($action->getErrors()) > 0)
  150. {
  151. $this->addErrors($action->getErrors());
  152. }
  153. if ($action instanceof Translate\Controller\ITimeLimit)
  154. {
  155. if ($action->hasProcessCompleted() && $result['TOTAL_ITEMS'] == 0)
  156. {
  157. $result['SUMMARY'] = Loc::getMessage('TR_IMPORT_VOID');
  158. }
  159. else
  160. {
  161. $messagePlaceholders = array(
  162. '#TOTAL_PHRASES#' => $result['TOTAL_ITEMS'],
  163. '#PROCESSED_PHRASES#' => $result['PROCESSED_ITEMS'],
  164. );
  165. if ($action->hasProcessCompleted())
  166. {
  167. $result['SUMMARY'] =
  168. Loc::getMessage('TR_IMPORT_COMPLETED')."\n".
  169. Loc::getMessage('TR_IMPORT_ACTION_STATS', $messagePlaceholders);
  170. }
  171. else
  172. {
  173. $result['SUMMARY'] = Loc::getMessage('TR_IMPORT_ACTION_STATS', $messagePlaceholders);
  174. }
  175. }
  176. }
  177. else
  178. {
  179. if ($result['TOTAL_ITEMS'] == 0)
  180. {
  181. $result['SUMMARY'] = Loc::getMessage('TR_IMPORT_VOID');
  182. }
  183. else
  184. {
  185. $messagePlaceholders = array(
  186. '#TOTAL_PHRASES#' => $result['TOTAL_ITEMS'],
  187. '#PROCESSED_PHRASES#' => $result['PROCESSED_ITEMS'],
  188. );
  189. $result['SUMMARY'] =
  190. Loc::getMessage('TR_IMPORT_COMPLETED')."\n".
  191. Loc::getMessage('TR_IMPORT_ACTION_STATS', $messagePlaceholders);
  192. }
  193. }
  194. return $result;
  195. }
  196. /**
  197. * Runs controller index action.
  198. *
  199. * @return array
  200. */
  201. public function indexAction()
  202. {
  203. if ($this->reindex !== true)
  204. {
  205. return [
  206. 'STATUS' => Translate\Controller\STATUS_COMPLETED,
  207. 'SUMMARY' => Loc::getMessage('TR_IMPORT_COMPLETED')
  208. ];
  209. }
  210. $action = new Translate\Controller\Import\IndexCsv(
  211. self::ACTION_INDEX,
  212. $this,
  213. [
  214. 'tabId' => $this->tabId,
  215. 'csvFilePath' => $this->csvFilePath,
  216. ]
  217. );
  218. $result = $action->run(true);
  219. if (count($action->getErrors()) > 0)
  220. {
  221. $this->addErrors($action->getErrors());
  222. }
  223. if ($action instanceof Translate\Controller\ITimeLimit)
  224. {
  225. if ($action->hasProcessCompleted())
  226. {
  227. $result['SUMMARY'] = Loc::getMessage('TR_IMPORT_COMPLETED');
  228. }
  229. else
  230. {
  231. $messagePlaceholders = array(
  232. '#TOTAL_FILES#' => $result['TOTAL_ITEMS'],
  233. '#PROCESSED_FILES#' => $result['PROCESSED_ITEMS'],
  234. );
  235. $result['SUMMARY'] = Loc::getMessage('TR_INDEX_ACTION_STATS', $messagePlaceholders);
  236. }
  237. }
  238. else
  239. {
  240. $result['SUMMARY'] = Loc::getMessage('TR_IMPORT_COMPLETED');
  241. }
  242. return $result;
  243. }
  244. /**
  245. * Handles uploaded file.
  246. *
  247. * @return array
  248. */
  249. public function uploadAction()
  250. {
  251. $result = array();
  252. $success = false;
  253. if (
  254. isset($_FILES['csvFile'], $_FILES['csvFile']['tmp_name']) &&
  255. ($_FILES['csvFile']['error'] == 0) &&
  256. file_exists($_FILES['csvFile']['tmp_name'])
  257. )
  258. {
  259. if (
  260. (filesize($_FILES['csvFile']['tmp_name']) > 0) &&
  261. (mb_substr($_FILES['csvFile']['name'], -4) === '.csv')
  262. )
  263. {
  264. if ($this->moveUploadedFile($_FILES['csvFile'], '.csv'))
  265. {
  266. $this->saveProgressParameters();
  267. $success = true;
  268. }
  269. }
  270. else
  271. {
  272. $this->addError(new Main\Error(Loc::getMessage('TR_IMPORT_EMPTY_FILE_ERROR')));
  273. }
  274. }
  275. else
  276. {
  277. $this->addError(new Main\Error(Loc::getMessage('TR_IMPORT_EMPTY_FILE_ERROR')));
  278. }
  279. if ($success)
  280. {
  281. $result['SUMMARY'] = Loc::getMessage('TR_IMPORT_UPLOAD_OK');
  282. }
  283. $result['STATUS'] = Translate\Controller\STATUS_COMPLETED;
  284. return $result;
  285. }
  286. /**
  287. * Moves uploaded csv file into bxtmp folder.
  288. *
  289. * @param array $postedFile Uploaded file data from $_FILES.
  290. * @param string $suffix Append file name with suffix.
  291. * @param int $timeToLive Time to live in hours.
  292. *
  293. * @return boolean
  294. */
  295. private function moveUploadedFile($postedFile, $suffix = '.csv', $timeToLive = 3)
  296. {
  297. if (
  298. isset($postedFile['tmp_name']) &&
  299. file_exists($postedFile['tmp_name'])
  300. )
  301. {
  302. /** @var Translate\IO\CsvFile $csvFile */
  303. $tmpFile = Translate\IO\CsvFile::generateTemporalFile('translate', $suffix, $timeToLive);
  304. if (@copy($postedFile['tmp_name'], $tmpFile->getPhysicalPath()))
  305. {
  306. $this->csvFilePath = $tmpFile->getPhysicalPath();
  307. return true;
  308. }
  309. }
  310. $this->addError(new Main\Error(Loc::getMessage('TR_IMPORT_EMPTY_FILE_ERROR')));
  311. return false;
  312. }
  313. /**
  314. * Deletes genereted file.
  315. *
  316. * @param int $tabId Id of session storage.
  317. *
  318. * @return array
  319. */
  320. public function cancelAction($tabId)
  321. {
  322. $result = $this->purgeAction($tabId);
  323. $result['SUMMARY'] = Loc::getMessage('TR_IMPORT_ACTION_CANCEL');
  324. return $result;
  325. }
  326. /**
  327. * Deletes genereted file.
  328. *
  329. * @param int $tabId Id of session storage.
  330. *
  331. * @return array
  332. */
  333. public function purgeAction($tabId)
  334. {
  335. if (empty($tabId) || (int)$tabId <= 0)
  336. {
  337. throw new Main\ArgumentException("Missing 'tabId' parameter");
  338. }
  339. $settings = $this->getProgressParameters();
  340. if (!empty($settings['csvFilePath']))
  341. {
  342. $path = new Main\IO\File($settings['csvFilePath']);
  343. if ($path->isExists())
  344. {
  345. $path->delete();
  346. }
  347. }
  348. $this->clearProgressParameters();
  349. return array(
  350. 'SUMMARY' => Loc::getMessage('TR_IMPORT_FILE_DROPPED'),
  351. 'STATUS' => Translate\Controller\STATUS_COMPLETED
  352. );
  353. }
  354. /**
  355. * Deletes genereted file.
  356. *
  357. * @return array
  358. */
  359. public function finalizeAction()
  360. {
  361. $settings = $this->getProgressParameters();
  362. if (!empty($settings['csvFilePath']))
  363. {
  364. $path = new Main\IO\File($settings['csvFilePath']);
  365. if ($path->isExists())
  366. {
  367. $path->delete();
  368. }
  369. }
  370. $this->clearProgressParameters();
  371. return array(
  372. 'STATUS' => Translate\Controller\STATUS_COMPLETED
  373. );
  374. }
  375. }