403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/cvetdv.ru/bitrix/modules/bizproc/lib/automation/engine/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/cvetdv.ru/bitrix/modules/bizproc/lib/automation/engine/runtime.php
<?php

namespace Bitrix\Bizproc\Automation\Engine;

use Bitrix\Main;
use Bitrix\Bizproc;
use Bitrix\Bizproc\Workflow\Entity\WorkflowInstanceTable;
use Bitrix\Bizproc\Workflow\Entity\WorkflowStateTable;
use Bitrix\Bizproc\Automation\Target\BaseTarget;
use Bitrix\Main\Config\Option;
use Bitrix\Main\InvalidOperationException;
use Bitrix\Main\Localization\Loc;
use Bitrix\Bizproc\Runtime\Starter\Context;

Loc::loadMessages(__FILE__);

class Runtime
{
	use Bizproc\Debugger\Mixins\WriterDebugTrack;

	protected $target;
	protected static $startedTemplates = [];
	private static array $clearMap = [];

	public function setTarget(BaseTarget $target)
	{
		$this->target = $target;
		return $this;
	}

	/**
	 * @return BaseTarget
	 * @throws InvalidOperationException
	 */
	public function getTarget()
	{
		if ($this->target === null)
		{
			throw new InvalidOperationException('Target must be set by setTarget method.');
		}

		return $this->target;
	}

	protected function getWorkflowInstanceIds()
	{
		$documentType = $this->getTarget()->getDocumentType();
		$documentId = $this->getTarget()->getDocumentId();
		$ids = WorkflowInstanceTable::getList([
			'select' => ['ID'],
			'filter' => [
				'=MODULE_ID' => $documentType[0],
				'=ENTITY' => $documentType[1],
				'=DOCUMENT_ID' => $documentId,
				'@STARTED_EVENT_TYPE' => [\CBPDocumentEventType::Automation, \CBPDocumentEventType::Debug],
				'=TEMPLATE.DOCUMENT_TYPE' => $documentType[2],
			],
		])->fetchAll();
		$workflowInstanceIds = array_column($ids, 'ID');

		$runtime = \CBPRuntime::getRuntime();
		$workflows = $runtime->getWorkflows();
		$workflowsRuntimeIds = [];
		foreach ($workflows as $id => $workflow)
		{
			$eventType = $workflow->getRootActivity()->getDocumentEventType();
			if (
				($eventType === \CBPDocumentEventType::Automation || $eventType === \CBPDocumentEventType::Debug)
				&& \CBPHelper::isEqualDocument($workflow->getDocumentType(), $documentType)
				&& \CBPHelper::isEqualDocument($workflow->getDocumentId(), $this->getTarget()->getComplexDocumentId())
			)
			{
				$workflowsRuntimeIds[] = $id;
			}
		}

		return array_merge($workflowInstanceIds, $workflowsRuntimeIds);
	}

	public function getCurrentWorkflowId(): ?string
	{
		$documentType = $this->getTarget()->getDocumentType();

		$template = new Template(
			$documentType,
			$this->getTarget()->getDocumentStatus()
		);

		if ($template->getId() > 0)
		{
			$filter = [
				'=DOCUMENT_ID' => $this->getTarget()->getDocumentId(),
				'=TEMPLATE.ID' => $template->getId(),
			];

			if ($this->isDebug())
			{
				$session = Bizproc\Debugger\Session\Manager::getActiveSession();
				$filter['@ID'] = $session->getWorkflowContexts()->getWorkflowIdList();
			}

			$row = WorkflowStateTable::getList([
				'select' => ['ID'],
				'filter' => $filter,
				'order' => ['STARTED' => 'DESC'],
				'limit' => 1,
			])->fetch();

			return $row ? $row['ID'] : null;
		}

		return null;
	}

	protected function runTemplates($documentStatus, string $preGeneratedWorkflowId = null)
	{
		$isDebug = $this->isDebug();
		$template = new Template($this->getTarget()->getDocumentType(), $documentStatus);
		$workflowId = null;

		if ($template->getId() > 0)
		{
			$errors = [];
			$trigger = $this->getTarget()->getAppliedTrigger();
			$this->getTarget()->setAppliedTrigger([]);

			if (
				!$template->isExternalModified()
				&& !$isDebug
				&& !$trigger
				&& !$template->getRobots()
			)
			{
				return false;
			}

			$documentType = $this->getTarget()->getDocumentType();
			$documentId = $this->getTarget()->getDocumentId();
			$documentComplexId = [$documentType[0], $documentType[1], $documentId];
			$useForcedTracking = $this->canUseForcedTracking() && !$template->isExternalModified();

			$startParameters = [
				\CBPDocument::PARAM_TAGRET_USER => null, //Started by System
				\CBPDocument::PARAM_USE_FORCED_TRACKING => $isDebug || $useForcedTracking,
				\CBPDocument::PARAM_IGNORE_SIMULTANEOUS_PROCESSES_LIMIT => true,
				\CBPDocument::PARAM_DOCUMENT_TYPE => $documentType,
				\CBPDocument::PARAM_DOCUMENT_EVENT_TYPE =>
					$isDebug ? \CBPDocumentEventType::Debug : \CBPDocumentEventType::Automation,
				\CBPDocument::PARAM_PRE_GENERATED_WORKFLOW_ID => $preGeneratedWorkflowId ?? null,
			];

			if (isset($trigger['RETURN']) && is_array($trigger['RETURN']))
			{
				$startParameters += $trigger['RETURN'];
			}

			foreach ($template->getParameters() as $parameterId => $parameter)
			{
				if (!isset($startParameters[$parameterId]) && isset($parameter['Default']))
				{
					$startParameters[$parameterId] = $parameter['Default'];
				}
			}

			$this->setStarted($documentType[2], $documentId, $documentStatus);

			$args = [$template->getId(), $documentComplexId, $startParameters, $errors];

			if ($isDebug && $preGeneratedWorkflowId)
			{
				$session = Bizproc\Debugger\Session\Manager::getActiveSession();
				$session->addWorkflowContext($preGeneratedWorkflowId, $template);
			}

			$workflowId = $isDebug
				? \CBPDocument::startDebugWorkflow(...$args)
				: \CBPDocument::startWorkflow(...$args)
			;

			if (!$errors && $workflowId)
			{
				if ($trigger)
				{
					$this->writeTriggerTracking($workflowId, $trigger);
				}

				if ($useForcedTracking && !$isDebug)
				{
					$this->clearOldTrack($documentComplexId, $template->getId(), $workflowId);
				}
			}
		}

		return $workflowId;
	}

	protected function writeTriggerTracking($workflowId, $trigger)
	{
		$trackingService = \CBPRuntime::getRuntime(true)->getTrackingService();

		$trackingService->write(
			$workflowId,
			\CBPTrackingType::Trigger,
			'APPLIED_TRIGGER',
			\CBPActivityExecutionStatus::Closed,
			\CBPActivityExecutionResult::Succeeded,
			'',
			$trigger['ID']
		);
	}

	protected function stopTemplates()
	{
		$errors = [];
		$instanceIds = $this->getWorkflowInstanceIds();
		$documentType = $this->getTarget()->getDocumentType();
		$documentId = [$documentType[0], $documentType[1], $this->getTarget()->getDocumentId()];
		foreach ($instanceIds as $instanceId)
		{
			\CBPDocument::terminateWorkflow(
				$instanceId,
				$documentId,
				$errors,
				Loc::getMessage('BIZPROC_AUTOMATION_TEMPLATE_TERMINATED')
			);
		}
	}

	/**
	 * Document creation handler.
	 *
	 * @return void
	 * @throws InvalidOperationException
	 */
	public function onDocumentAdd(?Context $context = null)
	{
		$preGeneratedWorkflowId = \CBPRuntime::generateWorkflowId();
		$isManualAdd = $context && $context->isManualOperation();

		if (!$isManualAdd && $this->isDebug(true))
		{
			$debugSession = Bizproc\Debugger\Session\Manager::getActiveSession();

			if ($debugSession->isBeforeDebuggerStartState())
			{
				$debugSession->addDocument($this->getTarget()->getDocumentId());

				return;
			}

			$debugSession->addWorkflowContext($preGeneratedWorkflowId, []);

			$status = $this->getTarget()->getDocumentStatus();
			$this->writeSessionLegendTrack($preGeneratedWorkflowId);
			$this->writeStatusTracking($preGeneratedWorkflowId, $status);
			$this->writeCategoryTracking($preGeneratedWorkflowId);
		}

		$this->runDocumentStatus($preGeneratedWorkflowId);
	}

	/**
	 * Document status changed handler.
	 *
	 * @return void
	 * @throws InvalidOperationException
	 */
	public function onDocumentStatusChanged()
	{
		$preGeneratedWorkflowId = \CBPRuntime::generateWorkflowId();
		if ($this->isDebug())
		{
			$debugSession = Bizproc\Debugger\Session\Manager::getActiveSession();

			if ($debugSession->isBeforeDebuggerStartState())
			{
				return;
			}

			$debugSession->addWorkflowContext($preGeneratedWorkflowId, []);

			$status = $this->getTarget()->getDocumentStatus();
			$documentType = $this->getTarget()->getDocumentType()[2];
			$documentId = $this->getTarget()->getDocumentId();
			if (!$this->isStarted($documentType, $documentId, $status))
			{
				$this->onDocumentStatusChangedDebug($preGeneratedWorkflowId, $status);
			}
		}

		$this->runDocumentStatus($preGeneratedWorkflowId);
	}

	public function runDocumentStatus(string $preGeneratedWorkflowId = null): ?string
	{
		$status = $this->getTarget()->getDocumentStatus();
		$documentType = $this->getTarget()->getDocumentType()[2];
		$documentId = $this->getTarget()->getDocumentId();

		if ($status && !$this->isStarted($documentType, $documentId, $status))
		{
			$this->stopTemplates();

			return $this->runTemplates($status, $preGeneratedWorkflowId);
		}

		return null;
	}

	protected function isDebug(bool $isOnDocumentAdd = false): bool
	{
		$debugSession = Bizproc\Debugger\Session\Manager::getActiveSession();
		if (!$debugSession)
		{
			return false;
		}

		$documentType = $this->getTarget()->getDocumentType();
		if (!$debugSession->isStartedInDocumentType($documentType))
		{
			return false;
		}

		$documentId = $this->getTarget()->getComplexDocumentId();
		if (!$isOnDocumentAdd || $debugSession->isExperimentalMode() || $debugSession->isFixed())
		{
			return $debugSession->isSessionDocument($documentId);
		}

		$documentCategoryId = $this->getTarget()->getDocumentCategory();

		return $documentCategoryId === $debugSession->getDocumentCategoryId();
	}

	protected function onDocumentStatusChangedDebug(?string $workflowId, string $status)
	{
		if ($workflowId)
		{
			$trigger = $this->getTarget()->getAppliedTrigger();
			if ($trigger)
			{
				$trigger['APPLIED_RULE_LOG'] = $this->getTarget()->getAppliedTriggerConditionResults();
				$this->writeAppliedTriggerTrack($workflowId, $trigger);
			}

			$this->writeStatusTracking($workflowId, $status);
		}

		Bizproc\Debugger\Listener::getInstance()->onDocumentStatusChanged($status);
	}

	/**
	 * Document moving handler.
	 *
	 * @return void
	 */
	public function onDocumentMove()
	{
		$this->stopTemplates();
	}

	public function onFieldsChanged(array $changes)
	{
		if ($this->isDebug() && $changes)
		{
			$debugSession = Bizproc\Debugger\Session\Manager::getActiveSession();
			if ($debugSession->isBeforeDebuggerStartState())
			{
				return;
			}

			$target = $this->getTarget();

			if ($target->getDocumentCategoryCode() && in_array($target->getDocumentCategoryCode(), $changes))
			{
				$session = Bizproc\Debugger\Session\Manager::getActiveSession();
				$sessionWorkflows = $session->getWorkflowContexts()->getWorkflowIdList();
				if (!empty($sessionWorkflows))
				{
					$lastWorkflowId = $sessionWorkflows[array_key_last($sessionWorkflows)];
					$this->writeCategoryTracking($lastWorkflowId);
				}
			}

			Bizproc\Debugger\Listener::getInstance()->onDocumentUpdated($changes);
		}
	}

	private function setStarted($documentType, $documentId, $status)
	{
		$key = $documentType . '_' . $documentId;
		static::$startedTemplates[$key] = (string)$status;
		return $this;
	}

	private function isStarted($documentType, $documentId, $status)
	{
		$key = $documentType . '_' . $documentId;
		return (
			isset(static::$startedTemplates[$key])
			&& (string)$status === static::$startedTemplates[$key]
		);
	}

	private function writeStatusTracking($workflowId, string $status): ?int
	{
		$statuses = $this->getTarget()->getDocumentStatusList();
		$status = $statuses[$status] ?? [];

		return $this->writeDocumentStatusTrack($workflowId, $status);
	}

	private function writeCategoryTracking($workflowId): ?int
	{
		$documentService = \CBPRuntime::GetRuntime(true)->getDocumentService();
		$categories = $documentService->getDocumentCategories($this->target->getDocumentType());

		$categoryName = $categories[$this->target->getDocumentCategory()]['name'];

		return $this->writeDocumentCategoryTrack($workflowId, $categoryName);
	}

	private function canUseForcedTracking(): bool
	{
		static $use;

		if (!isset($use))
		{
			$use = Option::get('bizproc', 'automation_no_forced_tracking', 'N') === 'N';
		}

		return $use;
	}

	private function clearOldTrack(array $documentId, int $templateId, $currentWorkflowId): void
	{
		$rowList = WorkflowStateTable::getList([
			'select' => ['ID'],
			'filter' => [
				'!=ID' => $currentWorkflowId,
				'=MODULE_ID' => $documentId[0],
				'=ENTITY' => $documentId[1],
				'=DOCUMENT_ID' => $documentId[2],
				'=WORKFLOW_TEMPLATE_ID' => $templateId,
			],
			'limit' => 10,
		])->fetchAll();

		if ($rowList)
		{
			foreach ($rowList as $row)
			{
				static::$clearMap[$row['ID']] = true;
			}
			$this->setClearJob();
		}
	}

	private function setClearJob()
	{
		static $inserted = false;

		if (!$inserted)
		{
			Main\Application::getInstance()->addBackgroundJob(
				\Closure::fromCallable([$this, 'doBackgroundJob']),
				[],
				Main\Application::JOB_PRIORITY_LOW - 10
			);
			$inserted = true;
		}
	}

	private function doBackgroundJob()
	{
		foreach (array_keys(static::$clearMap) as $id)
		{
			\CBPTrackingService::deleteByWorkflow($id);
		}
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit