/modules/bizproc/lib/automation/engine/conditiongroup.php

https://gitlab.com/alexprowars/bitrix · PHP · 441 lines · 330 code · 56 blank · 55 comment · 37 complexity · 57b49f7d9cf07132bbfbacc79538f580 MD5 · raw file

  1. <?php
  2. namespace Bitrix\Bizproc\Automation\Engine;
  3. use Bitrix\Bizproc\Automation\Target\BaseTarget;
  4. use Bitrix\Main\Localization\Loc;
  5. use Bitrix\Bizproc\Automation\Helper;
  6. use Bitrix\Main\NotSupportedException;
  7. Loc::loadMessages(__FILE__);
  8. class ConditionGroup
  9. {
  10. const TYPE_FIELD = 'field';
  11. const TYPE_MIXED = 'mixed';
  12. const JOINER_AND = 'AND';// 0
  13. const JOINER_OR = 'OR';// 1
  14. private $type;
  15. private $items = [];
  16. public function __construct(array $params = null)
  17. {
  18. $this->setType(static::TYPE_FIELD);
  19. if ($params)
  20. {
  21. if (isset($params['type']))
  22. {
  23. $this->setType($params['type']);
  24. }
  25. if (isset($params['items']) && is_array($params['items']))
  26. {
  27. foreach ($params['items'] as [$item, $joiner])
  28. {
  29. if (!empty($item['field']))
  30. {
  31. $condition = new Condition($item);
  32. $this->addItem($condition, $joiner);
  33. }
  34. }
  35. }
  36. }
  37. }
  38. /**
  39. * @param BaseTarget $target Automation target.
  40. * @return bool
  41. */
  42. public function evaluate(BaseTarget $target)
  43. {
  44. $documentType = $target->getDocumentType();
  45. $documentId = $documentType;
  46. $documentId[2] = $target->getDocumentId();
  47. return $this->evaluateByDocument($documentType, $documentId);
  48. }
  49. /**
  50. * @param array $documentType
  51. * @param array $documentId
  52. * @param array|null $document
  53. * @return bool
  54. */
  55. public function evaluateByDocument(array $documentType, array $documentId, array $document = null): bool
  56. {
  57. if (empty($this->items))
  58. {
  59. return true;
  60. }
  61. if ($this->getType() === static::TYPE_MIXED)
  62. {
  63. throw new NotSupportedException('Mixed conditions can`t be evaluated by document only');
  64. }
  65. $documentService = \CBPRuntime::getRuntime(true)->getDocumentService();
  66. if ($document === null)
  67. {
  68. $document = $documentService->getDocument($documentId, $documentType);
  69. }
  70. $documentFields = $documentService->getDocumentFields($documentType);
  71. $result = [0 => true];
  72. $i = 0;
  73. $joiner = static::JOINER_AND;
  74. foreach ($this->items as $item)
  75. {
  76. /** @var Condition $condition */
  77. $condition = $item[0];
  78. $conditionField = $condition->getField();
  79. $conditionResult = true;
  80. $fld = $document[$conditionField] ?? null;
  81. $fieldType = null;
  82. if (isset($documentFields[$conditionField]))
  83. {
  84. $fieldType = $documentService->getFieldTypeObject($documentType, $documentFields[$conditionField]);
  85. }
  86. if (!$fieldType)
  87. {
  88. $fieldType = $documentService->getFieldTypeObject($documentType, ['Type' => 'string']);
  89. }
  90. if (!$condition->checkValue($fld, $fieldType, $documentId))
  91. {
  92. $conditionResult = false;
  93. }
  94. if ($joiner == static::JOINER_OR)
  95. {
  96. ++$i;
  97. $result[$i] = $conditionResult;
  98. }
  99. elseif (!$conditionResult)
  100. {
  101. $result[$i] = false;
  102. }
  103. $joiner = ($item[1] === static::JOINER_OR) ? static::JOINER_OR : static::JOINER_AND;
  104. }
  105. return (count(array_filter($result)) > 0);
  106. }
  107. /**
  108. * @param string $type Type of condition.
  109. * @return ConditionGroup This instance.
  110. */
  111. public function setType($type)
  112. {
  113. if ($type === static::TYPE_FIELD || $type === static::TYPE_MIXED)
  114. {
  115. $this->type = $type;
  116. }
  117. return $this;
  118. }
  119. /**
  120. * @return mixed
  121. */
  122. public function getType()
  123. {
  124. return $this->type;
  125. }
  126. /**
  127. * @param Condition $condition Condition instance.
  128. * @param string $joiner Condition joiner.
  129. * @return $this This instance.
  130. */
  131. public function addItem(Condition $condition, $joiner = self::JOINER_AND)
  132. {
  133. $this->items[] = [$condition, $joiner];
  134. return $this;
  135. }
  136. /**
  137. * @return array Condition items.
  138. */
  139. public function getItems()
  140. {
  141. return $this->items;
  142. }
  143. /**
  144. * @return array Array presentation of condition group.
  145. */
  146. public function toArray()
  147. {
  148. $itemsArray = [];
  149. /** @var Condition $condition */
  150. foreach ($this->getItems() as [$condition, $joiner])
  151. {
  152. $itemsArray[] = [$condition->toArray(), $joiner];
  153. }
  154. return ['type' => $this->getType(), 'items' => $itemsArray];
  155. }
  156. /**
  157. * @param array $childActivity Child activity array.
  158. * @param array $documentType
  159. * @param Template $template
  160. * @return array New activity array.
  161. */
  162. public function createBizprocActivity(array $childActivity, array $documentType, Template $template)
  163. {
  164. $mixedCondition = [];
  165. $bizprocJoiner = 0;
  166. $documentService = \CBPRuntime::GetRuntime(true)->getDocumentService();
  167. /** @var Condition $condition */
  168. foreach ($this->getItems() as [$condition, $joiner])
  169. {
  170. $object = $condition->getObject();
  171. $field = $condition->getField();
  172. $value = $condition->getValue();
  173. $property = $template->getProperty($object, $field);
  174. if ($property && !in_array($condition->getOperator(), ['empty', '!empty']))
  175. {
  176. $valueInternal = $documentService->GetFieldInputValue(
  177. $documentType,
  178. $property,
  179. 'field',
  180. ['field' => $value],
  181. $errors
  182. );
  183. if (!$errors)
  184. {
  185. $value = $valueInternal;
  186. }
  187. }
  188. $mixedCondition[] = [
  189. 'object' => $object,
  190. 'field' => $field,
  191. 'operator' => $condition->getOperator(),
  192. 'value' => self::unConvertExpressions($value, $documentType),
  193. 'joiner' => $bizprocJoiner,
  194. ];
  195. $bizprocJoiner = ($joiner === static::JOINER_OR) ? 1 : 0;
  196. }
  197. $title = Loc::getMessage('BIZPROC_AUTOMATION_CONDITION_TITLE');
  198. $activity = [
  199. 'Type' => 'IfElseActivity',
  200. 'Name' => Robot::generateName(),
  201. 'Properties' => ['Title' => $title],
  202. 'Children' => [
  203. [
  204. 'Type' => 'IfElseBranchActivity',
  205. 'Name' => Robot::generateName(),
  206. 'Properties' => [
  207. 'Title' => $title,
  208. 'mixedcondition' => $mixedCondition
  209. ],
  210. 'Children' => [$childActivity]
  211. ],
  212. [
  213. 'Type' => 'IfElseBranchActivity',
  214. 'Name' => Robot::generateName(),
  215. 'Properties' => [
  216. 'Title' => $title,
  217. 'truecondition' => '1',
  218. ],
  219. 'Children' => []
  220. ]
  221. ]
  222. ];
  223. return $activity;
  224. }
  225. /**
  226. * @param array &$activity Target activity array.
  227. * @param array $documentType
  228. * @param Template $template
  229. * @return false|ConditionGroup Instance of false.
  230. */
  231. public static function convertBizprocActivity(array &$activity, array $documentType, Template $template)
  232. {
  233. $conditionGroup = false;
  234. if (
  235. count($activity['Children']) === 2
  236. && $activity['Children'][0]['Type'] === 'IfElseBranchActivity'
  237. && $activity['Children'][1]['Type'] === 'IfElseBranchActivity'
  238. && (
  239. !empty($activity['Children'][0]['Properties']['fieldcondition'])
  240. ||
  241. !empty($activity['Children'][0]['Properties']['mixedcondition'])
  242. )
  243. && !empty($activity['Children'][1]['Properties']['truecondition'])
  244. && count($activity['Children'][0]['Children']) === 1
  245. )
  246. {
  247. $conditionGroup = new static();
  248. $conditionGroup->setType(static::TYPE_MIXED);
  249. $isMixed = isset($activity['Children'][0]['Properties']['mixedcondition']);
  250. $bizprocConditions = $activity['Children'][0]['Properties'][$isMixed?'mixedcondition':'fieldcondition'];
  251. foreach ($bizprocConditions as $index => $condition)
  252. {
  253. if (!$isMixed)
  254. {
  255. $condition = self::convertDocumentCondition($condition);
  256. }
  257. $property = $template->getProperty($condition['object'], $condition['field']);
  258. if ($property && $property['Type'] === 'user')
  259. {
  260. $condition['value'] = \CBPHelper::UsersArrayToString(
  261. $condition['value'],
  262. null,
  263. $documentType
  264. );
  265. }
  266. $conditionItem = new Condition(array(
  267. 'object' => $condition['object'],
  268. 'field' => $condition['field'],
  269. 'operator' => $condition['operator'],
  270. 'value' => self::convertExpressions($condition['value'], $documentType),
  271. ));
  272. $nextCondition = isset($bizprocConditions[$index + 1]) ? $bizprocConditions[$index + 1] : null;
  273. $joiner = ($nextCondition && (!empty($nextCondition[3]) || !empty($nextCondition['joiner'])))
  274. ? static::JOINER_OR : static::JOINER_AND;
  275. $conditionGroup->addItem($conditionItem, $joiner);
  276. }
  277. $activity = $activity['Children'][0]['Children'][0];
  278. }
  279. return $conditionGroup;
  280. }
  281. private static function convertDocumentCondition(array $condition): array
  282. {
  283. return [
  284. 'object' => 'Document',
  285. 'field' => $condition[0],
  286. 'operator' => $condition[1],
  287. 'value' => $condition[2],
  288. 'joiner' => $condition[3],
  289. ];
  290. }
  291. /**
  292. * Convert values to internal format.
  293. * @param array $documentType
  294. * @return $this
  295. */
  296. public function internalizeValues(array $documentType): self
  297. {
  298. $documentService = \CBPRuntime::GetRuntime(true)->getDocumentService();
  299. $documentFields = $documentService->GetDocumentFields($documentType);
  300. /** @var Condition $condition */
  301. foreach ($this->getItems() as [$condition, $joiner])
  302. {
  303. $field = $condition->getField();
  304. $value = $condition->getValue();
  305. $property = isset($documentFields[$field]) ? $documentFields[$field] : null;
  306. if ($property && !in_array($condition->getOperator(), ['empty', '!empty']))
  307. {
  308. $value = self::unConvertExpressions($value, $documentType);
  309. $valueInternal = $documentService->GetFieldInputValue(
  310. $documentType,
  311. $property,
  312. 'field',
  313. ['field' => $value],
  314. $errors
  315. );
  316. if (!$errors)
  317. {
  318. $condition->setValue($valueInternal);
  319. }
  320. }
  321. }
  322. return $this;
  323. }
  324. /**
  325. * Convert value to external format.
  326. * @param array $documentType
  327. * @return $this
  328. */
  329. public function externalizeValues(array $documentType): self
  330. {
  331. $documentService = \CBPRuntime::GetRuntime(true)->getDocumentService();
  332. $documentFields = $documentService->GetDocumentFields($documentType);
  333. /** @var Condition $condition */
  334. foreach ($this->getItems() as [$condition, $joiner])
  335. {
  336. $field = $condition->getField();
  337. $value = $condition->getValue();
  338. $property = isset($documentFields[$field]) ? $documentFields[$field] : null;
  339. if ($property && !in_array($condition->getOperator(), ['empty', '!empty']))
  340. {
  341. $value = self::convertExpressions($value, $documentType);
  342. if ($property['Type'] === 'user')
  343. {
  344. $value = \CBPHelper::UsersArrayToString(
  345. $value,
  346. null,
  347. $documentType
  348. );
  349. }
  350. $condition->setValue($value);
  351. }
  352. }
  353. return $this;
  354. }
  355. private static function convertExpressions($value, array $documentType)
  356. {
  357. if (is_array($value))
  358. {
  359. foreach ($value as $k => $v)
  360. {
  361. $value[$k] = self::convertExpressions($v, $documentType);
  362. }
  363. }
  364. else
  365. {
  366. $value = Helper::convertExpressions($value, $documentType);
  367. }
  368. return $value;
  369. }
  370. private static function unConvertExpressions($value, array $documentType)
  371. {
  372. if (is_array($value))
  373. {
  374. foreach ($value as $k => $v)
  375. {
  376. $value[$k] = self::unConvertExpressions($v, $documentType);
  377. }
  378. }
  379. else
  380. {
  381. $value = Helper::unConvertExpressions($value, $documentType);
  382. }
  383. return $value;
  384. }
  385. }