1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
runtime.php
См. документацию.
1<?php
2
3namespace Bitrix\Bizproc\Automation\Engine;
4
5use Bitrix\Main;
6use Bitrix\Bizproc;
7use Bitrix\Bizproc\Workflow\Entity\WorkflowInstanceTable;
8use Bitrix\Bizproc\Workflow\Entity\WorkflowStateTable;
9use Bitrix\Bizproc\Automation\Target\BaseTarget;
10use Bitrix\Main\Config\Option;
11use Bitrix\Main\InvalidOperationException;
12use Bitrix\Main\Localization\Loc;
13use Bitrix\Bizproc\Runtime\Starter\Context;
14
15Loc::loadMessages(__FILE__);
16
17class Runtime
18{
19 use Bizproc\Debugger\Mixins\WriterDebugTrack;
20
21 protected $target;
22 protected static $startedTemplates = [];
23 private static array $clearMap = [];
24
25 public function setTarget(BaseTarget $target)
26 {
27 $this->target = $target;
28 return $this;
29 }
30
35 public function getTarget()
36 {
37 if ($this->target === null)
38 {
39 throw new InvalidOperationException('Target must be set by setTarget method.');
40 }
41
42 return $this->target;
43 }
44
45 protected function getWorkflowInstanceIds()
46 {
47 $documentType = $this->getTarget()->getDocumentType();
48 $documentId = $this->getTarget()->getDocumentId();
49 $ids = WorkflowInstanceTable::getList([
50 'select' => ['ID'],
51 'filter' => [
52 '=MODULE_ID' => $documentType[0],
53 '=ENTITY' => $documentType[1],
54 '=DOCUMENT_ID' => $documentId,
56 '=TEMPLATE.DOCUMENT_TYPE' => $documentType[2],
57 ],
58 ])->fetchAll();
59 $workflowInstanceIds = array_column($ids, 'ID');
60
61 $runtime = \CBPRuntime::getRuntime();
62 $workflows = $runtime->getWorkflows();
63 $workflowsRuntimeIds = [];
64 foreach ($workflows as $id => $workflow)
65 {
66 $eventType = $workflow->getRootActivity()->getDocumentEventType();
67 if (
68 ($eventType === \CBPDocumentEventType::Automation || $eventType === \CBPDocumentEventType::Debug)
69 && \CBPHelper::isEqualDocument($workflow->getDocumentType(), $documentType)
70 && \CBPHelper::isEqualDocument($workflow->getDocumentId(), $this->getTarget()->getComplexDocumentId())
71 )
72 {
73 $workflowsRuntimeIds[] = $id;
74 }
75 }
76
77 return array_merge($workflowInstanceIds, $workflowsRuntimeIds);
78 }
79
80 public function getCurrentWorkflowId(): ?string
81 {
82 $documentType = $this->getTarget()->getDocumentType();
83
84 $template = new Template(
85 $documentType,
86 $this->getTarget()->getDocumentStatus()
87 );
88
89 if ($template->getId() > 0)
90 {
91 $filter = [
92 '=DOCUMENT_ID' => $this->getTarget()->getDocumentId(),
93 '=TEMPLATE.ID' => $template->getId(),
94 ];
95
96 if ($this->isDebug())
97 {
99 $filter['@ID'] = $session->getWorkflowContexts()->getWorkflowIdList();
100 }
101
102 $row = WorkflowStateTable::getList([
103 'select' => ['ID'],
104 'filter' => $filter,
105 'order' => ['STARTED' => 'DESC'],
106 'limit' => 1,
107 ])->fetch();
108
109 return $row ? $row['ID'] : null;
110 }
111
112 return null;
113 }
114
115 protected function runTemplates($documentStatus, string $preGeneratedWorkflowId = null)
116 {
117 $isDebug = $this->isDebug();
118 $template = new Template($this->getTarget()->getDocumentType(), $documentStatus);
119 $workflowId = null;
120
121 if ($template->getId() > 0)
122 {
123 $errors = [];
124 $trigger = $this->getTarget()->getAppliedTrigger();
125 $this->getTarget()->setAppliedTrigger([]);
126
127 if (
128 !$template->isExternalModified()
129 && !$isDebug
130 && !$trigger
131 && !$template->getRobots()
132 )
133 {
134 return false;
135 }
136
137 $documentType = $this->getTarget()->getDocumentType();
138 $documentId = $this->getTarget()->getDocumentId();
139 $documentComplexId = [$documentType[0], $documentType[1], $documentId];
140 $useForcedTracking = $this->canUseForcedTracking() && !$template->isExternalModified();
141
142 $startParameters = [
143 \CBPDocument::PARAM_TAGRET_USER => null, //Started by System
144 \CBPDocument::PARAM_USE_FORCED_TRACKING => $isDebug || $useForcedTracking,
145 \CBPDocument::PARAM_IGNORE_SIMULTANEOUS_PROCESSES_LIMIT => true,
146 \CBPDocument::PARAM_DOCUMENT_TYPE => $documentType,
147 \CBPDocument::PARAM_DOCUMENT_EVENT_TYPE =>
149 \CBPDocument::PARAM_PRE_GENERATED_WORKFLOW_ID => $preGeneratedWorkflowId ?? null,
150 ];
151
152 if (isset($trigger['RETURN']) && is_array($trigger['RETURN']))
153 {
154 $startParameters += $trigger['RETURN'];
155 }
156
157 foreach ($template->getParameters() as $parameterId => $parameter)
158 {
159 if (!isset($startParameters[$parameterId]) && isset($parameter['Default']))
160 {
161 $startParameters[$parameterId] = $parameter['Default'];
162 }
163 }
164
165 $this->setStarted($documentType[2], $documentId, $documentStatus);
166
167 $args = [$template->getId(), $documentComplexId, $startParameters, $errors];
168
169 if ($isDebug && $preGeneratedWorkflowId)
170 {
172 $session->addWorkflowContext($preGeneratedWorkflowId, $template);
173 }
174
175 $workflowId = $isDebug
176 ? \CBPDocument::startDebugWorkflow(...$args)
177 : \CBPDocument::startWorkflow(...$args)
178 ;
179
180 if (!$errors && $workflowId)
181 {
182 if ($trigger)
183 {
184 $this->writeTriggerTracking($workflowId, $trigger);
185 }
186
187 if ($useForcedTracking && !$isDebug)
188 {
189 $this->clearOldTrack($documentComplexId, $template->getId(), $workflowId);
190 }
191 }
192 }
193
194 return $workflowId;
195 }
196
197 protected function writeTriggerTracking($workflowId, $trigger)
198 {
199 $trackingService = \CBPRuntime::getRuntime(true)->getTrackingService();
200
201 $trackingService->write(
202 $workflowId,
204 'APPLIED_TRIGGER',
207 '',
208 $trigger['ID']
209 );
210 }
211
212 protected function stopTemplates()
213 {
214 $errors = [];
215 $instanceIds = $this->getWorkflowInstanceIds();
216 $documentType = $this->getTarget()->getDocumentType();
217 $documentId = [$documentType[0], $documentType[1], $this->getTarget()->getDocumentId()];
218 foreach ($instanceIds as $instanceId)
219 {
220 \CBPDocument::terminateWorkflow(
221 $instanceId,
222 $documentId,
223 $errors,
224 Loc::getMessage('BIZPROC_AUTOMATION_TEMPLATE_TERMINATED')
225 );
226 }
227 }
228
235 public function onDocumentAdd(?Context $context = null)
236 {
237 $preGeneratedWorkflowId = \CBPRuntime::generateWorkflowId();
238 $isManualAdd = $context && $context->isManualOperation();
239
240 if (!$isManualAdd && $this->isDebug(true))
241 {
243
244 if ($debugSession->isBeforeDebuggerStartState())
245 {
246 $debugSession->addDocument($this->getTarget()->getDocumentId());
247
248 return;
249 }
250
251 $debugSession->addWorkflowContext($preGeneratedWorkflowId, []);
252
253 $status = $this->getTarget()->getDocumentStatus();
254 $this->writeSessionLegendTrack($preGeneratedWorkflowId);
255 $this->writeStatusTracking($preGeneratedWorkflowId, $status);
256 $this->writeCategoryTracking($preGeneratedWorkflowId);
257 }
258
259 $this->runDocumentStatus($preGeneratedWorkflowId);
260 }
261
268 public function onDocumentStatusChanged()
269 {
270 $preGeneratedWorkflowId = \CBPRuntime::generateWorkflowId();
271 if ($this->isDebug())
272 {
274
275 if ($debugSession->isBeforeDebuggerStartState())
276 {
277 return;
278 }
279
280 $debugSession->addWorkflowContext($preGeneratedWorkflowId, []);
281
282 $status = $this->getTarget()->getDocumentStatus();
283 $documentType = $this->getTarget()->getDocumentType()[2];
284 $documentId = $this->getTarget()->getDocumentId();
285 if (!$this->isStarted($documentType, $documentId, $status))
286 {
287 $this->onDocumentStatusChangedDebug($preGeneratedWorkflowId, $status);
288 }
289 }
290
291 $this->runDocumentStatus($preGeneratedWorkflowId);
292 }
293
294 public function runDocumentStatus(string $preGeneratedWorkflowId = null): ?string
295 {
296 $status = $this->getTarget()->getDocumentStatus();
297 $documentType = $this->getTarget()->getDocumentType()[2];
298 $documentId = $this->getTarget()->getDocumentId();
299
300 if ($status && !$this->isStarted($documentType, $documentId, $status))
301 {
302 $this->stopTemplates();
303
304 return $this->runTemplates($status, $preGeneratedWorkflowId);
305 }
306
307 return null;
308 }
309
310 protected function isDebug(bool $isOnDocumentAdd = false): bool
311 {
313 if (!$debugSession)
314 {
315 return false;
316 }
317
318 $documentType = $this->getTarget()->getDocumentType();
319 if (!$debugSession->isStartedInDocumentType($documentType))
320 {
321 return false;
322 }
323
324 $documentId = $this->getTarget()->getComplexDocumentId();
325 if (!$isOnDocumentAdd || $debugSession->isExperimentalMode() || $debugSession->isFixed())
326 {
327 return $debugSession->isSessionDocument($documentId);
328 }
329
330 $documentCategoryId = $this->getTarget()->getDocumentCategory();
331
332 return $documentCategoryId === $debugSession->getDocumentCategoryId();
333 }
334
335 protected function onDocumentStatusChangedDebug(?string $workflowId, string $status)
336 {
337 if ($workflowId)
338 {
339 $trigger = $this->getTarget()->getAppliedTrigger();
340 if ($trigger)
341 {
342 $trigger['APPLIED_RULE_LOG'] = $this->getTarget()->getAppliedTriggerConditionResults();
343 $this->writeAppliedTriggerTrack($workflowId, $trigger);
344 }
345
346 $this->writeStatusTracking($workflowId, $status);
347 }
348
349 Bizproc\Debugger\Listener::getInstance()->onDocumentStatusChanged($status);
350 }
351
357 public function onDocumentMove()
358 {
359 $this->stopTemplates();
360 }
361
362 public function onFieldsChanged(array $changes)
363 {
364 if ($this->isDebug() && $changes)
365 {
367 if ($debugSession->isBeforeDebuggerStartState())
368 {
369 return;
370 }
371
372 $target = $this->getTarget();
373
374 if ($target->getDocumentCategoryCode() && in_array($target->getDocumentCategoryCode(), $changes))
375 {
377 $sessionWorkflows = $session->getWorkflowContexts()->getWorkflowIdList();
378 if (!empty($sessionWorkflows))
379 {
380 $lastWorkflowId = $sessionWorkflows[array_key_last($sessionWorkflows)];
381 $this->writeCategoryTracking($lastWorkflowId);
382 }
383 }
384
385 Bizproc\Debugger\Listener::getInstance()->onDocumentUpdated($changes);
386 }
387 }
388
389 private function setStarted($documentType, $documentId, $status)
390 {
391 $key = $documentType . '_' . $documentId;
392 static::$startedTemplates[$key] = (string)$status;
393 return $this;
394 }
395
396 private function isStarted($documentType, $documentId, $status)
397 {
398 $key = $documentType . '_' . $documentId;
399 return (
400 isset(static::$startedTemplates[$key])
401 && (string)$status === static::$startedTemplates[$key]
402 );
403 }
404
405 private function writeStatusTracking($workflowId, string $status): ?int
406 {
407 $statuses = $this->getTarget()->getDocumentStatusList();
408 $status = $statuses[$status] ?? [];
409
410 return $this->writeDocumentStatusTrack($workflowId, $status);
411 }
412
413 private function writeCategoryTracking($workflowId): ?int
414 {
415 $documentService = \CBPRuntime::GetRuntime(true)->getDocumentService();
416 $categories = $documentService->getDocumentCategories($this->target->getDocumentType());
417
418 $categoryName = $categories[$this->target->getDocumentCategory()]['name'];
419
420 return $this->writeDocumentCategoryTrack($workflowId, $categoryName);
421 }
422
423 private function canUseForcedTracking(): bool
424 {
425 static $use;
426
427 if (!isset($use))
428 {
429 $use = Option::get('bizproc', 'automation_no_forced_tracking', 'N') === 'N';
430 }
431
432 return $use;
433 }
434
435 private function clearOldTrack(array $documentId, int $templateId, $currentWorkflowId): void
436 {
437 $rowList = WorkflowStateTable::getList([
438 'select' => ['ID'],
439 'filter' => [
440 '!=ID' => $currentWorkflowId,
441 '=MODULE_ID' => $documentId[0],
442 '=ENTITY' => $documentId[1],
443 '=DOCUMENT_ID' => $documentId[2],
444 '=WORKFLOW_TEMPLATE_ID' => $templateId,
445 ],
446 'limit' => 10,
447 ])->fetchAll();
448
449 if ($rowList)
450 {
451 foreach ($rowList as $row)
452 {
453 static::$clearMap[$row['ID']] = true;
454 }
455 $this->setClearJob();
456 }
457 }
458
459 private function setClearJob()
460 {
461 static $inserted = false;
462
463 if (!$inserted)
464 {
465 Main\Application::getInstance()->addBackgroundJob(
466 \Closure::fromCallable([$this, 'doBackgroundJob']),
467 [],
468 Main\Application::JOB_PRIORITY_LOW - 10
469 );
470 $inserted = true;
471 }
472 }
473
474 private function doBackgroundJob()
475 {
476 foreach (array_keys(static::$clearMap) as $id)
477 {
478 \CBPTrackingService::deleteByWorkflow($id);
479 }
480 }
481}
writeTriggerTracking($workflowId, $trigger)
Определения runtime.php:197
onDocumentStatusChangedDebug(?string $workflowId, string $status)
Определения runtime.php:335
runDocumentStatus(string $preGeneratedWorkflowId=null)
Определения runtime.php:294
isDebug(bool $isOnDocumentAdd=false)
Определения runtime.php:310
setTarget(BaseTarget $target)
Определения runtime.php:25
onFieldsChanged(array $changes)
Определения runtime.php:362
runTemplates($documentStatus, string $preGeneratedWorkflowId=null)
Определения runtime.php:115
onDocumentAdd(?Context $context=null)
Определения runtime.php:235
static getInstance()
Определения Listener.php:154
static getActiveSession()
Определения Manager.php:38
const Succeeded
Определения constants.php:45
const Closed
Определения constants.php:10
const Debug
Определения constants.php:159
const Automation
Определения constants.php:156
const Trigger
Определения trackingservice.php:705
$templateId
Определения component_props2.php:51
$template
Определения file_edit.php:49
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$errors
Определения iblock_catalog_edit.php:74
$filter
Определения iblock_catalog_list.php:54
$rowList
Определения iblock_catalog_list.php:273
$context
Определения csv_new_setup.php:223
$status
Определения session.php:10
Определения culture.php:9
if(empty($signedUserToken)) $key
Определения quickway.php:257