PageRenderTime 46ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/bizproc/lib/script/manager.php

https://gitlab.com/alexprowars/bitrix
PHP | 507 lines | 410 code | 97 blank | 0 comment | 29 complexity | cdfa3fa735026743431c49d5781a6f91 MD5 | raw file
  1. <?php
  2. namespace Bitrix\Bizproc\Script;
  3. use Bitrix\Bizproc\Script\Entity\EO_ScriptQueue;
  4. use Bitrix\Bizproc\Script\Entity\ScriptQueueDocumentTable;
  5. use Bitrix\Bizproc\Script\Entity\ScriptQueueTable;
  6. use Bitrix\Bizproc\Workflow\Template\Packer\RoboPackage;
  7. use Bitrix\Bizproc\Workflow\Template\SourceType;
  8. use Bitrix\Main;
  9. use Bitrix\Bizproc\Workflow\Template\Entity\WorkflowTemplateTable;
  10. use Bitrix\Main\Localization\Loc;
  11. class Manager
  12. {
  13. public static function getListByDocument(array $documentType, $showInactive = false)
  14. {
  15. $filter = [
  16. '=MODULE_ID' => $documentType[0],
  17. '=ENTITY' => $documentType[1],
  18. '=DOCUMENT_TYPE' => $documentType[2],
  19. ];
  20. if (!$showInactive)
  21. {
  22. $filter['=ACTIVE'] = 'Y';
  23. }
  24. $list = Entity\ScriptTable::getList(
  25. [
  26. 'select' => [
  27. 'ID', 'NAME', 'ORIGINATOR_ID', 'ORIGIN_ID',
  28. 'MODULE_ID', 'ENTITY', 'DOCUMENT_TYPE', 'NAME', 'DESCRIPTION',
  29. ],
  30. 'filter' => $filter,
  31. 'order' => [
  32. 'SORT' => 'ASC',
  33. 'NAME' => 'ASC'
  34. ],
  35. ]
  36. )->fetchAll();
  37. return $list;
  38. }
  39. public static function getById($id)
  40. {
  41. $script = Entity\ScriptTable::getList(
  42. [
  43. 'select' => ['*'],
  44. 'filter' => [
  45. '=ID' => $id,
  46. ],
  47. ]
  48. )->fetchObject();
  49. return $script;
  50. }
  51. public static function getQueueById(int $queueId): ?EO_ScriptQueue
  52. {
  53. return Entity\ScriptQueueTable::getById($queueId)->fetchObject();
  54. }
  55. public static function saveScript(int $id, array $documentType, array $fields, $userId = null)
  56. {
  57. if ($id > 0)
  58. {
  59. $result = self::updateScript($id, $fields['script'], $fields['robotsTemplate'], $userId);
  60. }
  61. else
  62. {
  63. $result = self::addScript($documentType, $fields['script'], $fields['robotsTemplate'], $userId);
  64. }
  65. if ($result->isSuccess())
  66. {
  67. self::clearMenuCache();
  68. }
  69. return $result;
  70. }
  71. public static function createScript(array $documentType)
  72. {
  73. $fields = [
  74. 'ID' => 0,
  75. 'MODULE_ID' => $documentType[0],
  76. 'ENTITY' => $documentType[1],
  77. 'DOCUMENT_TYPE' => $documentType[2],
  78. 'NAME' => Loc::getMessage("BIZPROC_SCRIPT_MANAGER_NEW_SCRIPT"),
  79. 'DESCRIPTION' => Loc::getMessage("BIZPROC_SCRIPT_MANAGER_NEW_DESCRIPTION"),
  80. ];
  81. return $fields;
  82. }
  83. private static function updateScript($id, array $scriptFields, array $templateFields, $userId): Main\Result
  84. {
  85. $script = static::getById($id);
  86. if (!$script)
  87. {
  88. $result = new Main\Result();
  89. $result->addError(new Main\Error('Script not found'));
  90. return $result;
  91. }
  92. $wl = array_fill_keys(['NAME', 'DESCRIPTION'], true);
  93. $scriptFields = array_intersect_key($scriptFields, $wl);
  94. $scriptFields['MODIFIED_BY'] = $userId;
  95. $scriptFields['MODIFIED_DATE'] = new Main\Type\DateTime();
  96. $scriptUpdateResult = Entity\ScriptTable::update($script['ID'], $scriptFields);
  97. if (!$scriptUpdateResult->isSuccess())
  98. {
  99. return $scriptUpdateResult;
  100. }
  101. $documentType = [$script['MODULE_ID'], $script['ENTITY'], $script['DOCUMENT_TYPE']];
  102. $template = null;
  103. $tpl = WorkflowTemplateTable::getById($script['WORKFLOW_TEMPLATE_ID'])->fetchObject();
  104. if ($tpl)
  105. {
  106. $template = \Bitrix\Bizproc\Automation\Engine\Template::createByTpl($tpl);
  107. }
  108. if (!$template)
  109. {
  110. $template = new \Bitrix\Bizproc\Automation\Engine\Template($documentType);
  111. }
  112. $template->setName($scriptFields['NAME'] ?? $script->getName());
  113. $robots = isset($templateFields['ROBOTS']) && is_array($templateFields['ROBOTS']) ? $templateFields['ROBOTS'] : [];
  114. $result = $template->save($robots, $userId);
  115. if ($result->isSuccess())
  116. {
  117. self::saveTemplateConfigs($template->getId(), $templateFields);
  118. }
  119. return $result;
  120. }
  121. private static function addScript(array $documentType, array $scriptFields, array $templateFields, $userId): Main\Result
  122. {
  123. $templateFields['NAME'] = $scriptFields['NAME'];
  124. $result = self::addWorkflowTemplate($documentType, $templateFields, $userId);
  125. if (!$result->isSuccess())
  126. {
  127. return $result;
  128. }
  129. return self::addScriptRecord(
  130. $documentType,
  131. [
  132. 'WORKFLOW_TEMPLATE_ID' => $result->getData()['ID'],
  133. 'NAME' => $scriptFields['NAME'],
  134. 'DESCRIPTION' => $scriptFields['DESCRIPTION'],
  135. ],
  136. $userId
  137. );
  138. }
  139. private static function addWorkflowTemplate(array $documentType, array $templateFields, int $userId, $extractParameters = true)
  140. {
  141. $template = new \Bitrix\Bizproc\Automation\Engine\Template($documentType);
  142. $robots = isset($templateFields['ROBOTS']) && is_array($templateFields['ROBOTS']) ? $templateFields['ROBOTS'] : [];
  143. $template->setDocumentStatus('SCRIPT');
  144. $template->setName($templateFields['NAME']);
  145. $template->setExecuteType(\CBPDocumentEventType::Script);
  146. $result = $template->save($robots, $userId);
  147. if (!$result->isSuccess())
  148. {
  149. return $result;
  150. }
  151. self::saveTemplateConfigs($template->getId(), $templateFields, $extractParameters);
  152. $result->setData(['ID' => $template->getId()]);
  153. return $result;
  154. }
  155. private static function addScriptRecord(array $documentType, array $scriptFields, int $userId)
  156. {
  157. $addFields = [
  158. 'MODULE_ID' => $documentType[0],
  159. 'ENTITY' => $documentType[1],
  160. 'DOCUMENT_TYPE' => $documentType[2],
  161. 'WORKFLOW_TEMPLATE_ID' => $scriptFields['WORKFLOW_TEMPLATE_ID'],
  162. 'NAME' => $scriptFields['NAME'],
  163. 'DESCRIPTION' => $scriptFields['DESCRIPTION'],
  164. 'CREATED_BY' => $userId,
  165. 'CREATED_DATE' => new Main\Type\DateTime(),
  166. 'MODIFIED_BY' => $userId,
  167. 'MODIFIED_DATE' => new Main\Type\DateTime(),
  168. ];
  169. if (isset($scriptFields['ORIGINATOR_ID']) && isset($scriptFields['ORIGIN_ID']))
  170. {
  171. $addFields['ORIGINATOR_ID'] = $scriptFields['ORIGINATOR_ID'];
  172. $addFields['ORIGIN_ID'] = $scriptFields['ORIGIN_ID'];
  173. }
  174. return Entity\ScriptTable::add($addFields);
  175. }
  176. private static function saveTemplateConfigs(int $tplId, array $templateFields, $extractParameters = true)
  177. {
  178. $tpl = WorkflowTemplateTable::getById($tplId)->fetchObject();
  179. if (!$tpl)
  180. {
  181. return false;
  182. }
  183. $constants = $templateFields['CONSTANTS'] ?? [];
  184. $parameters = $templateFields['PARAMETERS'] ?? [];
  185. $usages = $tpl->collectUsages();
  186. $usedConstants = $usages->getValuesBySourceType(SourceType::Constant);
  187. $usedParameters = $usages->getValuesBySourceType(SourceType::Parameter);
  188. $constants = array_intersect_key($constants, array_fill_keys($usedConstants, true));
  189. $parameters = array_intersect_key($parameters, array_fill_keys($usedParameters, true));
  190. if ($extractParameters)
  191. {
  192. $constants = self::extractProperties($constants, $tpl->getDocumentComplexType());
  193. $parameters = self::extractProperties($parameters, $tpl->getDocumentComplexType());
  194. }
  195. \CBPWorkflowTemplateLoader::update(
  196. $tplId,
  197. ['CONSTANTS' => $constants, 'PARAMETERS' => $parameters],
  198. true
  199. );
  200. }
  201. private static function extractProperties(array $properties, array $documentType): array
  202. {
  203. $documentService = \CBPRuntime::GetRuntime(true)->getDocumentService();
  204. foreach ($properties as $i => $property)
  205. {
  206. $properties[$i]['Default'] = $documentService->GetFieldInputValue(
  207. $documentType,
  208. $property,
  209. 'field',
  210. ['field' => $property['Default']],
  211. $errors
  212. );
  213. }
  214. return $properties;
  215. }
  216. public static function deleteScript($id): Main\Result
  217. {
  218. $script = static::getById($id);
  219. $result = new Main\Result();
  220. if (!$script)
  221. {
  222. $result->addError(new Main\Error('Script not found'));
  223. return $result;
  224. }
  225. try
  226. {
  227. \CBPWorkflowTemplateLoader::getLoader()->deleteTemplate($script['WORKFLOW_TEMPLATE_ID']);
  228. Entity\ScriptTable::delete($id);
  229. Entity\ScriptQueueTable::deleteByScript($id);
  230. self::clearMenuCache();
  231. }
  232. catch (\Exception $e)
  233. {
  234. $result->addError(new Main\Error($e->getMessage()));
  235. }
  236. return $result;
  237. }
  238. public static function activateScript($id): Main\Result
  239. {
  240. $script = static::getById($id);
  241. $result = new Main\Result();
  242. if (!$script)
  243. {
  244. $result->addError(new Main\Error('Script not found'));
  245. return $result;
  246. }
  247. $script->setActive('Y');
  248. $script->save();
  249. self::clearMenuCache();
  250. return $result;
  251. }
  252. public static function deactivateScript($id): Main\Result
  253. {
  254. $script = static::getById($id);
  255. $result = new Main\Result();
  256. if (!$script)
  257. {
  258. $result->addError(new Main\Error('Script not found'));
  259. return $result;
  260. }
  261. $script->setActive('N');
  262. $script->save();
  263. self::clearMenuCache();
  264. return $result;
  265. }
  266. public static function terminateQueue(int $queueId, int $userId)
  267. {
  268. ScriptQueueTable::markTerminated($queueId, $userId);
  269. }
  270. public static function deleteQueue(int $queueId, int $userId)
  271. {
  272. ScriptQueueTable::delete($queueId);
  273. ScriptQueueDocumentTable::deleteByQueue($queueId);
  274. }
  275. public static function canUserStartScript(int $scriptId, int $userId): bool
  276. {
  277. $user = new \CBPWorkflowTemplateUser($userId);
  278. if ($user->isAdmin())
  279. {
  280. return true;
  281. }
  282. $script = static::getById($scriptId);
  283. if (!$script)
  284. {
  285. return false;
  286. }
  287. $documentType = [$script['MODULE_ID'], $script['ENTITY'], $script['DOCUMENT_TYPE']];
  288. return \CBPDocument::canUserOperateDocumentType(
  289. \CBPCanUserOperateOperation::ViewWorkflow,
  290. $userId,
  291. $documentType
  292. );
  293. }
  294. public static function canUserEditScript(int $scriptId, int $userId): bool
  295. {
  296. $script = static::getById($scriptId);
  297. if (!$script)
  298. {
  299. return false;
  300. }
  301. $documentType = [$script['MODULE_ID'], $script['ENTITY'], $script['DOCUMENT_TYPE']];
  302. return static::canUserCreateScript($documentType, $userId);
  303. }
  304. public static function canUserCreateScript(array $documentType, int $userId): bool
  305. {
  306. $user = new \CBPWorkflowTemplateUser($userId);
  307. if ($user->isAdmin())
  308. {
  309. return true;
  310. }
  311. return \CBPDocument::canUserOperateDocumentType(
  312. \CBPCanUserOperateOperation::CreateWorkflow,
  313. $userId,
  314. $documentType
  315. );
  316. }
  317. public static function exportScript(int $scriptId): ?array
  318. {
  319. $script = static::getById($scriptId);
  320. if (!$script)
  321. {
  322. return null;
  323. }
  324. $exportData = [
  325. 'MODULE_ID' => $script->getModuleId(),
  326. 'ENTITY' => $script->getEntity(),
  327. 'DOCUMENT_TYPE' => $script->getDocumentType(),
  328. 'NAME' => $script->getName(),
  329. 'DESCRIPTION' => $script->getDescription(),
  330. 'ORIGINATOR_ID' => $script->getOriginatorId(),
  331. 'ORIGIN_ID' => $script->getOriginId(),
  332. ];
  333. $script->fillWorkflowTemplate();
  334. $roboPackage = new RoboPackage();
  335. $packageData = $roboPackage->makePackageData($script->getWorkflowTemplate());
  336. $exportData['WORKFLOW_TEMPLATE'] = [
  337. 'PARAMETERS' => $packageData['PARAMETERS'],
  338. 'CONSTANTS' => $packageData['CONSTANTS'],
  339. 'ROBOTS' => $packageData['ROBOTS'],
  340. 'DOCUMENT_FIELDS' => $packageData['DOCUMENT_FIELDS'],
  341. 'REQUIRED_APPLICATIONS' => $packageData['REQUIRED_APPLICATIONS'],
  342. ];
  343. return $exportData;
  344. }
  345. public static function importScript(array $data, int $userId)
  346. {
  347. $documentType = [$data['MODULE_ID'], $data['ENTITY'], $data['DOCUMENT_TYPE']];
  348. $templateFields = $data['WORKFLOW_TEMPLATE'];
  349. $templateFields['DOCUMENT_TYPE'] = $documentType;
  350. $templateFields['NAME'] = $data['NAME'];
  351. $templateFields['DESCRIPTION'] = $data['DESCRIPTION'];
  352. $templateFields['ORIGINATOR_ID'] = $data['ORIGINATOR_ID'];
  353. $templateFields['ORIGIN_ID'] = $data['ORIGIN_ID'];
  354. $result = self::importWorkflowTemplate($templateFields, $userId);
  355. if (!$result->isSuccess())
  356. {
  357. return $result;
  358. }
  359. $result = self::addScriptRecord(
  360. $documentType,
  361. [
  362. 'WORKFLOW_TEMPLATE_ID' => $result->getData()['ID'],
  363. 'NAME' => $data['NAME'],
  364. 'DESCRIPTION' => $data['DESCRIPTION'],
  365. 'ORIGINATOR_ID' => $data['ORIGINATOR_ID'],
  366. 'ORIGIN_ID' => $data['ORIGIN_ID'],
  367. ],
  368. $userId
  369. );
  370. if ($result->isSuccess())
  371. {
  372. self::clearMenuCache();
  373. }
  374. return $result;
  375. }
  376. private static function importWorkflowTemplate(array $data, int $userId)
  377. {
  378. $roboPackage = new RoboPackage();
  379. $result = $roboPackage->unpack($data);
  380. if ($result->isSuccess())
  381. {
  382. $tpl = $result->getTpl();
  383. $tpl->setUserId($userId);
  384. $tpl->setDocumentStatus('SCRIPT');
  385. $tpl->setAutoExecute(\CBPDocumentEventType::Script);
  386. $saveResult = $tpl->save();
  387. if ($saveResult->isSuccess())
  388. {
  389. $result->setData(['ID' => $saveResult->getId()]);
  390. \CBPWorkflowTemplateLoader::importDocumentFields(
  391. $tpl->getDocumentComplexType(),
  392. $result->getDocumentFields()
  393. );
  394. }
  395. else
  396. {
  397. $result->addErrors($saveResult->getErrors());
  398. }
  399. }
  400. return $result;
  401. }
  402. private static function clearMenuCache(): void
  403. {
  404. if (defined('BX_COMP_MANAGED_CACHE'))
  405. {
  406. $cache = Main\Application::getInstance()->getTaggedCache();
  407. $cache->clearByTag('intranet_menu_binding');
  408. }
  409. }
  410. }