Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
debugger.php
1<?php
2
4
17
18class Debugger extends Base
19{
20 public function configureActions()
21 {
22 return [
23 'finishDebugSession' => [
24 '+prefilters' => [
25 new ContentType([ContentType::JSON])
26 ],
27 ],
28 ];
29 }
30
31 public function fillAutomationViewAction(string $sessionId): ?array
32 {
33 $session = $this->getSession($sessionId);
34
35 if (!$session)
36 {
37 return null;
38 }
39
40 $isBeforeDebuggerStartState = $session->isBeforeDebuggerStartState();
41
42 if ($isBeforeDebuggerStartState)
43 {
44 $documentId = null;
45 $documentType = $session->getParameterDocumentType();
46 }
47 else
48 {
49 [$documentId, $documentType] = $this->getActiveDocument($session);
50
51 if (!$documentId)
52 {
53 return null;
54 }
55 }
56
57 $documentService = \CBPRuntime::GetRuntime(true)->getDocumentService();
59 $target = $documentService->createAutomationTarget($documentType);
60
61 $target->setDocumentId($documentId);
62 [$status, $statusList] = $this->getStatus($target, $session);
63
64 $template = new Template($documentType, $status);
65 $documentFields = $isBeforeDebuggerStartState ? [] : $this->getDocumentFields($documentType);
66
67 $triggers = $target->getTriggers(array_keys($statusList));
68 $target->prepareTriggersToShow($triggers);
69
70 $workflowId = $target->getRuntime()->getCurrentWorkflowId();
71 $hasInstance = $workflowId && WorkflowInstanceTable::exists($workflowId);
72
73 $workflowStatus = $hasInstance ? \CBPWorkflowStatus::Suspended : \CBPWorkflowStatus::Completed;
74 $workflowEvents = [];
75 $debuggerState = Manager::getDebuggerState()->getId();
76
77 if ($hasInstance)
78 {
80 $workflow = \CBPRuntime::GetRuntime(true)->getWorkflow($workflowId, true);
81 foreach ($workflow->getDebugEventIds() as $eventName)
82 {
83 foreach ($template->getRobots() as $robot)
84 {
85 if ($robot->getDelayName() === $eventName)
86 {
87 $workflowEvents[] = [
88 'name' => $eventName,
89 'sourceId' => $robot->getName(),
90 ];
91 break;
92 }
93 }
94 }
95 }
96
97 $documentCategoryId =
98 $isBeforeDebuggerStartState
99 ? $session->getDocumentCategoryId()
100 : $target->getDocumentCategory()
101 ;
102
103 $documentValues =
104 $isBeforeDebuggerStartState
105 ? []
106 : $this->getDocumentValues($documentType, $target->getComplexDocumentId(), $documentFields)
107 ;
108
109 return [
110 'triggers' => $triggers,
111 'template' => Automation\Component\Base::getTemplateViewData($template->toArray(), $documentType),
112 'documentId' => $documentId,
113 'documentStatus' => $status,
114 'statusList' => array_values($statusList),
115 'documentCategoryId' => $documentCategoryId,
116 'documentFields' => array_values($documentFields),
117 'documentValues' => $documentValues,
118 'workflowId' => $workflowId,
119 'workflowStatus' => $workflowStatus,
120 'workflowEvents' => $workflowEvents,
121 'debuggerState' => $debuggerState,
122 'track' => $this->getTrack($workflowId, $workflowStatus),
123 'globalVariables' => array_values(Automation\Helper::getGlobalVariables($documentType)),
124 'globalConstants' => array_values(Automation\Helper::getGlobalConstants($documentType)),
125 ];
126 }
127
128 private function getDocumentFields(array $documentType): array
129 {
130 $fields = Automation\Helper::getDocumentFields($documentType);
131
132 foreach ($fields as $id => $field)
133 {
134 if (
135 FieldType::isBaseType($field['Type'])
136 && strpos($field['Id'], '.') === false
137 && strpos($field['Id'], '_PRINTABLE') === false
138 && strpos($field['Id'], '_IDS') === false
139 )
140 {
141 $fields[$id]['Watchable'] = true;
142 }
143 }
144
145 return $fields;
146 }
147
148 private function getDocumentValues(array $documentType, array $documentId, array $fields): array
149 {
150 $documentService = \CBPRuntime::GetRuntime(true)->getDocumentService();
151 $lazyList = $documentService->GetDocument($documentId);
152
153 $values = [];
154
155 foreach ($fields as $fieldId => $property)
156 {
157 if (empty($property['Watchable']))
158 {
159 continue;
160 }
161
162 $fieldType = $documentService->getFieldTypeObject($documentType, $property);
163 $fieldType->setDocumentId($documentId);
164
165 $values[$fieldId] = $fieldType->formatValue($lazyList[$fieldId]);
166 }
167
168 return $values;
169 }
170
171 public function setDocumentStatusAction($statusId): ?array
172 {
173 $session = $this->getSession();
174
175 if (!$session)
176 {
177 return null;
178 }
179
180 [$documentId, $documentType] = $this->getActiveDocument($session);
181
182 if (!$documentId)
183 {
184 return null;
185 }
186
187 $documentService = \CBPRuntime::GetRuntime(true)->getDocumentService();
189 $target = $documentService->createAutomationTarget($documentType);
190
191 $target->setDocumentId($documentId);
192
193 if ($target->getDocumentStatus() === $statusId)
194 {
195 return null;
196 }
197
198 $target->setDocumentStatus($statusId);
199 $target->getRuntime()->onDocumentStatusChanged();
200
201 $template = new Template($documentType, $statusId);
202
203 return [
204 'newStatus' => $statusId,
205 'template' => Automation\Component\Base::getTemplateViewData($template->toArray(), $documentType),
206 ];
207 }
208
209 public function resumeAutomationTemplateAction(string $sessionId)
210 {
211 $session = $this->getSession($sessionId);
212
213 if (!$session)
214 {
215 return null;
216 }
217
218 [$documentId, $documentType] = $this->getActiveDocument($session);
219
220 if (!$documentId)
221 {
222 return null;
223 }
224
225 $currentState = Manager::getDebuggerState();
226
227 if ($currentState->is(DebuggerState::RUN))
228 {
229 $newState = DebuggerState::pause();
230 }
231 else
232 {
233 $newState = DebuggerState::run();
234 }
235
236 Manager::setDebuggerState($newState);
237
238 $documentService = \CBPRuntime::GetRuntime(true)->getDocumentService();
239 $automationTarget = $documentService->createAutomationTarget($documentType);
240 $automationTarget->setDocumentId($documentId);
241
242 $workflowId = $automationTarget->getRuntime()->getCurrentWorkflowId();
243 $hasInstance = $workflowId && WorkflowInstanceTable::exists($workflowId);
244
245 if ($hasInstance && $newState->is(DebuggerState::RUN))
246 {
248 $workflow = \CBPRuntime::GetRuntime(true)->getWorkflow($workflowId);
249 $workflow->resume();
250 }
251
252 return [
253 'workflowId' => $workflowId,
254 'debuggerState' => $newState->getId(),
255 ];
256 }
257
258 public function emulateExternalEventAction(string $workflowId, string $eventId): ?bool
259 {
260 $session = $this->getSession();
261
262 if (!$session)
263 {
264 return null;
265 }
266
267 if (!$session->hasWorkflow($workflowId) || !WorkflowInstanceTable::exists($workflowId))
268 {
269 $this->addError(new Error(Loc::getMessage('BIZPROC_CONTROLLER_DEBUGGER_NO_WORKFLOW')));
270
271 return null;
272 }
273
274 $runtime = \CBPRuntime::GetRuntime(true);
275 $workflow = $runtime->getWorkflow($workflowId);
276
277 if (!($workflow instanceof DebugWorkflow))
278 {
279 $this->addError(new Error(Loc::getMessage('BIZPROC_CONTROLLER_DEBUGGER_NO_WORKFLOW')));
280
281 return null;
282 }
283
284 $workflow->sendDebugEvent($eventId);
285
286 return true;
287 }
288
290 public function finishDebugSessionAction(string $sessionId, bool $deleteDocument = false): ?array
291 {
292 $session = $this->getSession($sessionId);
293
294 if (!$session)
295 {
296 return null;
297 }
298
299 if (!$session->canUserFinish($this->getCurrentUser()->getId()))
300 {
301 $this->addError(new Error(Loc::getMessage('BIZPROC_CONTROLLER_DEBUGGER_CAN_FINISH_ERROR')));
302
303 return null;
304 }
305
306 $toDeleteDocument = $session->isExperimentalMode() && $deleteDocument ? $session->getFixedDocument() : null;
307
308 $result = Manager::finishSession($session);
309 if (!$result->isSuccess())
310 {
311 $this->addErrors($result->getErrors());
312 }
313 else
314 {
315 Listener::getInstance()->onSessionFinished($sessionId);
316
317 if ($toDeleteDocument)
318 {
319 $documentService = \CBPRuntime::GetRuntime(true)->getDocumentService();
320 $documentService->deleteDocument($toDeleteDocument->getParameterDocumentId());
321 }
322 }
323
324 return null;
325 }
326
327 public function loadAllLogAction(string $sessionId): ?array
328 {
329 $userId = (int)$this->getCurrentUser()->getId();
330
331 $session = \Bitrix\Bizproc\Debugger\Session\Manager::getSessionById($sessionId);
332 if (!$session)
333 {
334 $this->addError(new Error(Loc::getMessage('BIZPROC_CONTROLLER_DEBUGGER_NO_SESSION')));
335
336 return null;
337 }
338
339 if (!$session->canUserDebug($userId))
340 {
341 $this->addError(new Error(Loc::getMessage('BIZPROC_CONTROLLER_DEBUGGER_CAN_DEBUG_ERROR')));
342
343 return null;
344 }
345
346 $logs = [];
347
348 $trackingResult = new \CBPTrackingServiceResult();
349 $trackingResult->InitFromArray($session->getLogs());
350
351 while ($log = $trackingResult->fetch())
352 {
354 $values = $log->collectValues();
355 $values['MODIFIED'] = (string)($values['MODIFIED']);
356 $logs[] = $values;
357 }
358
359 return [
360 'logs' => $logs,
361 'workflowRobots' => $session->getRobots(),
362 ];
363 }
364
365 private function getTrack(?string $workflowId, int $workflowStatus): array
366 {
367 $rows = [];
368
369 if ($workflowId)
370 {
371 $trackResult = \CBPTrackingService::GetList(['ID' => 'ASC'], ['WORKFLOW_ID' => $workflowId]);
372
373 while ($row = $trackResult->fetch())
374 {
375 $row['WORKFLOW_STATUS'] = $workflowStatus;
376 $rows[] = $row;
377 }
378 }
379
380 return $rows;
381 }
382
383 private function getSession(string $id = null): ?Session
384 {
385 $userId = $this->getCurrentUser()->getId();
386
387 $session = $id ? Manager::getSessionById($id) : Manager::getActiveSession();
388 if (!$session)
389 {
390 $this->addError(new Error(Loc::getMessage('BIZPROC_CONTROLLER_DEBUGGER_NO_SESSION')));
391
392 return null;
393 }
394
395 if (!$session->canUserDebug($userId))
396 {
397 $this->addError(new Error(Loc::getMessage('BIZPROC_CONTROLLER_DEBUGGER_CAN_DEBUG_ERROR')));
398
399 return null;
400 }
401
402 return $session;
403 }
404
405 private function getActiveDocument(Session $session): array
406 {
407 $document = $session->getFixedDocument();
408
409 if (!$document || !$this->isDocumentExists($document->getParameterDocumentId()))
410 {
411 $this->addError(new Error(Loc::getMessage('BIZPROC_CONTROLLER_DEBUGGER_NO_DOCUMENT'), 404));
412
413 return [null, null];
414 }
415
416 return [$document->getDocumentId(), $session->getParameterDocumentType()];
417 }
418
419 private function getStatus(Automation\Target\BaseTarget $target, Session $session): array
420 {
421 $isBeforeDebuggerStartState = $session->isBeforeDebuggerStartState();
422
423 if ($isBeforeDebuggerStartState)
424 {
425 $statusList = $target->getDocumentStatusList($session->getDocumentCategoryId());
426 $status = array_key_first($statusList);
427
428 return [$status, $statusList];
429 }
430
431 return [$target->getDocumentStatus(), $target->getDocumentStatusList($target->getDocumentCategory())];
432 }
433
434 private function isDocumentExists(array $documentId): bool
435 {
436 $documentService = \CBPRuntime::GetRuntime(true)->getDocumentService();
437
438 try
439 {
440 $documentService->getDocumentType($documentId);
441 }
442 catch (\Exception $e)
443 {
444 return false;
445 }
446
447 return true;
448 }
449
451 public function startSessionAction(string $documentSigned, int $mode): ?array
452 {
453 [$documentType, $documentCategoryId] = \CBPDocument::unSignParameters($documentSigned);
454 $userId = (int)$this->getCurrentUser()->getId();
455
456 if (!Manager::canUserDebugAutomation($userId, $documentType))
457 {
458 $this->addError(new Error(Loc::getMessage('BIZPROC_CONTROLLER_DEBUGGER_CAN_DEBUG_ERROR')));
459
460 return null;
461 }
462
463 $result = Manager::startSession($documentType, $mode, $userId, $documentCategoryId);
464 if (!$result->isSuccess())
465 {
466 $this->addErrors($result->getErrorCollection()->toArray());
467
468 return null;
469 }
470
472 $session = $result->getObject();
473 if ($session->getMode() === \Bitrix\Bizproc\Debugger\Session\Mode::EXPERIMENTAL)
474 {
475 $documentId = $this->createExperimentalDocument($documentType, $documentCategoryId);
476 if (!$documentId)
477 {
478 Manager::finishSession($session);
479 $this->addError(new Error(Loc::getMessage('BIZPROC_CONTROLLER_DEBUGGER_NO_DOCUMENT')));
480
481 return null;
482 }
483
484 return $this->fixateSessionDocumentAction($documentId);
485 }
486
487 return [
488 'documentSigned' => \CBPDocument::signParameters([$documentType]),
489 'session' => $session->toArray(),
490 ];
491 }
492
493 private function createExperimentalDocument(array $documentType, string $documentCategoryId): ?string
494 {
495 $documentService = \CBPRuntime::GetRuntime(true)->getDocumentService();
496
497 $fields = [
498 'TITLE' => \Bitrix\Main\Localization\Loc::getMessage(
499 'BIZPROC_CONTROLLER_DEBUGGER_DOCUMENT_TITLE',
500 ['#ENTITY#' => $documentService->getDocumentTypeName($documentType)]
501 ),
502 'CATEGORY_ID' => (int)$documentCategoryId
503 ];
504
505 return $documentService->createTestDocument(
506 $documentType,
507 $fields,
508 (int)(\Bitrix\Main\Engine\CurrentUser::get()->getId())
509 );
510 }
511
512 public function fixateSessionDocumentAction(string $documentId): ?array
513 {
514 $session = $this->getSession();
515 if (!$session)
516 {
517 return null;
518 }
519
520 $result = $session->fixateDocument($documentId);
521 if (!$result->isSuccess())
522 {
523 $this->addErrors($result->getErrorCollection()->toArray());
524
525 return null;
526 }
527
528 $documentService = \CBPRuntime::GetRuntime(true)->getDocumentService();
530 $target = $documentService->createAutomationTarget($session->getParameterDocumentType());
531 $target->setDocumentId($documentId);
532 $target->getRuntime()->onDocumentAdd();
533
535 $updatedSession = $result->getObject();
536
537 return [
538 'documentSigned' => $updatedSession->getFixedDocument()->getSignedDocument(),
539 'session' => $updatedSession->toArray(),
540 ];
541 }
542
543 public function removeSessionDocumentAction(array $documentIds = []): ?array
544 {
545 $session = $this->getSession();
546
547 if (!$session)
548 {
549 return null;
550 }
551
552 $documents = clone($session->getDocuments());
553
554 foreach ($documents as $document)
555 {
556 if (in_array($document->getDocumentId(), $documentIds, true))
557 {
558 $session->removeFromDocuments($document);
559 }
560 }
561
562 return [
563 'session' => $session,
564 ];
565 }
566
567 public function loadRobotsByWorkflowIdAction(string $sessionId, string $workflowId): ?array
568 {
569 $userId = (int)$this->getCurrentUser()->getId();
570
571 $session = \Bitrix\Bizproc\Debugger\Session\Manager::getSessionById($sessionId);
572 if (!$session)
573 {
574 $this->addError(new Error(Loc::getMessage('BIZPROC_CONTROLLER_DEBUGGER_NO_SESSION')));
575
576 return null;
577 }
578
579 if (!$session->canUserDebug($userId))
580 {
581 $this->addError(new Error(Loc::getMessage('BIZPROC_CONTROLLER_DEBUGGER_CAN_DEBUG_ERROR')));
582
583 return null;
584 }
585
586 if (!$session->hasWorkflow($workflowId))
587 {
588 $this->addError(new Error(Loc::getMessage('BIZPROC_CONTROLLER_DEBUGGER_NO_WORKFLOW')));
589
590 return null;
591 }
592
593 $robots = [];
594
595 foreach ($session->getWorkflowContexts() as $context)
596 {
597 if ($context->getWorkflowId() !== $workflowId)
598 {
599 continue;
600 }
601
602 $templateShards = $context->fillTemplateShards();
603 $robots = $templateShards ? $templateShards->getRobotData() : [];
604 break;
605 }
606
607 return [
608 'workflowRobots' => $robots
609 ];
610 }
611}
static addError($error)
Definition base.php:278
static addErrors(array $errors)
Definition base.php:287
removeSessionDocumentAction(array $documentIds=[])
Definition debugger.php:543
loadRobotsByWorkflowIdAction(string $sessionId, string $workflowId)
Definition debugger.php:567
finishDebugSessionAction(string $sessionId, bool $deleteDocument=false)
Definition debugger.php:290
emulateExternalEventAction(string $workflowId, string $eventId)
Definition debugger.php:258
static isBaseType(string $type)
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29