1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
workflowpersister.php
См. документацию.
1<?php
2
4
9{
10 protected $serviceInstanceId = "";
11 protected $ownershipDelta = 300;
12 protected $useGZipCompression = false;
13
14 private static $instance;
15
16 public function __clone()
17 {
18 trigger_error('Clone in not allowed.', E_USER_ERROR);
19 }
20
21 protected function __construct()
22 {
23 $this->serviceInstanceId = uniqid("", true);
24 $this->useGZipCompression = \CBPWorkflowTemplateLoader::useGZipCompression();
25 }
26
30 public static function getPersister()
31 {
32 if (!isset(self::$instance))
33 {
34 $c = __CLASS__;
35 self::$instance = new $c;
36 }
37
38 return self::$instance;
39 }
40
41 private function retrieveWorkflow($instanceId, $silent = false)
42 {
43 global $DB;
44
45 $queryCondition = $this->getLockerQueryCondition();
46
47 if (!$silent && !$this->lock($instanceId))
48 {
49 throw new Exception(GetMessage("BPCGWP_WF_LOCKED"), \CBPRuntime::EXCEPTION_CODE_INSTANCE_LOCKED);
50 }
51
52 $dbResult = $DB->Query(
53 "SELECT WORKFLOW, WORKFLOW_RO, case when ". $queryCondition . " then 'Y' else 'N' end as UPDATEABLE ".
54 "FROM b_bp_workflow_instance ".
55 "WHERE ID = '".$DB->ForSql($instanceId)."' "
56 );
57 if ($arResult = $dbResult->Fetch())
58 {
59 if ($arResult["UPDATEABLE"] == "Y" && !$silent)
60 {
61 $sqlUpdate = $DB->PrepareUpdate(
62 'b_bp_workflow_instance',
63 [
64 'OWNER_ID' => $this->serviceInstanceId,
65 'OWNED_UNTIL' => Main\Type\DateTime::createFromTimestamp($this->GetOwnershipTimeout()),
66 ]
67 );
68
69 $DB->Query(
70 'UPDATE b_bp_workflow_instance SET ' . $sqlUpdate . ' WHERE ID = \''.$DB->ForSql($instanceId).'\' '
71 );
72 }
73 elseif (!$silent)
74 {
75 $this->unlock($instanceId);
76 throw new Exception(GetMessage("BPCGWP_WF_LOCKED"), \CBPRuntime::EXCEPTION_CODE_INSTANCE_LOCKED);
77 }
78
79 if (!$silent)
80 {
81 $this->unlock($instanceId);
82 }
83
84 return [$arResult["WORKFLOW"], $arResult["WORKFLOW_RO"]];
85 }
86
87 if (!$silent)
88 {
89 $this->unlock($instanceId);
90 }
91
92 throw new Exception(GetMessage("BPCGWP_INVALID_WF"), \CBPRuntime::EXCEPTION_CODE_INSTANCE_NOT_FOUND);
93 }
94
95 protected function insertWorkflow($id, $buffer, $status, $bUnlocked, array $creationData = [])
96 {
97 global $DB;
98
99 $queryCondition = $this->getLockerQueryCondition();
100
101 if ($status == CBPWorkflowStatus::Completed || $status == CBPWorkflowStatus::Terminated)
102 {
103 $DB->Query(
104 "DELETE FROM b_bp_workflow_instance ".
105 "WHERE ID = '".$DB->ForSql($id)."'"
106 );
107 }
108 else
109 {
110 $dbResult = $DB->Query(
111 "SELECT ID, case when " . $queryCondition . " then 'Y' else 'N' end as UPDATEABLE ".
112 "FROM b_bp_workflow_instance ".
113 "WHERE ID = '".$DB->ForSql($id)."' "
114 );
115 if ($arResult = $dbResult->Fetch())
116 {
117 if ($arResult["UPDATEABLE"] == "Y")
118 {
119 $sqlUpdate = $DB->PrepareUpdate(
120 'b_bp_workflow_instance',
121 [
122 'WORKFLOW' => $buffer,
123 'STATUS' => (int)$status,
124 'MODIFIED' => new Main\Type\DateTime(),
125 'OWNER_ID' => $bUnlocked ? false : $this->serviceInstanceId,
126 'OWNED_UNTIL' => $bUnlocked ? false : Main\Type\DateTime::createFromTimestamp($this->GetOwnershipTimeout()),
127 ]
128 );
129
130 $DB->Query(
131 'UPDATE b_bp_workflow_instance SET ' . $sqlUpdate . ' WHERE ID = \''.$DB->ForSql($id).'\' '
132 );
133 }
134 else
135 {
136 throw new Exception(GetMessage('BPCGWP_WF_LOCKED'), \CBPRuntime::EXCEPTION_CODE_INSTANCE_LOCKED);
137 }
138 }
139 else
140 {
141 $status = (int) $status;
142 $ownerId = ($bUnlocked ? false : $this->serviceInstanceId);
143 $ownedUntil = ($bUnlocked ? false : Main\Type\DateTime::createFromTimestamp($this->GetOwnershipTimeout()));
144
145 $moduleId = isset($creationData['MODULE_ID']) ? $creationData['MODULE_ID'] : '';
146 $entity = isset($creationData['ENTITY']) ? $creationData['ENTITY'] : '';
147 $documentId = isset($creationData['DOCUMENT_ID']) ? $creationData['DOCUMENT_ID'] : '';
148 $tplId = isset($creationData['WORKFLOW_TEMPLATE_ID']) ? (int) $creationData['WORKFLOW_TEMPLATE_ID'] : 0;
149 $startedBy = isset($creationData['STARTED_BY']) ? (int) $creationData['STARTED_BY'] : 0;
150 $startedEventType = isset($creationData['STARTED_EVENT_TYPE']) ? (int) $creationData['STARTED_EVENT_TYPE'] : 0;
151 $ro = isset($creationData['RO']) ? $creationData['RO'] : false;
152 $nowTime = new Main\Type\DateTime();
153
154 $sqlInsert = $DB->PrepareInsert(
155 'b_bp_workflow_instance',
156 [
157 'ID' => $id,
158 'WORKFLOW' => $buffer,
159 'WORKFLOW_RO' => $ro,
160 'STATUS' => $status,
161 'MODIFIED' => $nowTime,
162 'OWNER_ID' => $ownerId,
163 'OWNED_UNTIL' => $ownedUntil,
164 'MODULE_ID' => $moduleId,
165 'ENTITY' => $entity,
166 'DOCUMENT_ID' => $documentId,
167 'WORKFLOW_TEMPLATE_ID' => $tplId,
168 'STARTED' => $nowTime,
169 'STARTED_BY' => $startedBy,
170 'STARTED_EVENT_TYPE' => $startedEventType,
171 ]
172 );
173
174 $DB->Query(
175 'INSERT INTO b_bp_workflow_instance (' . $sqlInsert[0] . ') VALUES (' . $sqlInsert[1] .')'
176 );
177 }
178 }
179 }
180
181 protected function getOwnershipTimeout()
182 {
183 return time() + $this->ownershipDelta;
184 }
185
186 public function loadWorkflow($instanceId, $silent = false)
187 {
188 [$state, $ro] = $this->RetrieveWorkflow($instanceId, $silent);
189
190 if ($state)
191 {
192 return $this->RestoreFromSerializedForm($state, $ro);
193 }
194
195 throw new Exception("WorkflowNotFound");
196 }
197
198 protected function restoreFromSerializedForm($buffer, $ro)
199 {
200 if ($this->useGZipCompression)
201 {
202 $buffer = gzuncompress($buffer);
203 $ro = $ro ? gzuncompress($ro) : null;
204 }
205
206 if ($buffer == '')
207 {
208 throw new Exception("EmptyWorkflowInstance");
209 }
210
212 $activity = CBPActivity::Load($buffer);
213
214 if ($ro)
215 {
216 $ro = Main\Web\Json::decode($ro);
217 if (is_array($ro))
218 {
219 $activity->setReadOnlyData($ro);
220 }
221 }
222
223 return $activity;
224 }
225
226 public function saveWorkflow(CBPActivity $rootActivity, $bUnlocked)
227 {
228 $creationData = [];
229 if ($rootActivity->workflow->isNew())
230 {
231 $dt = $rootActivity->GetDocumentId();
232 $creationData['MODULE_ID'] = $dt[0];
233 $creationData['ENTITY'] = $dt[1];
234 $creationData['DOCUMENT_ID'] = $dt[2];
235 $creationData['WORKFLOW_TEMPLATE_ID'] = $rootActivity->GetWorkflowTemplateId();
236 $creationData['STARTED_EVENT_TYPE'] = $rootActivity->getDocumentEventType();
237
238 $startedBy = $rootActivity->{\CBPDocument::PARAM_TAGRET_USER};
239 if ($startedBy)
240 {
241 $creationData['STARTED_BY'] = \CBPHelper::StripUserPrefix($startedBy);
242 }
244 $creationData['RO'] = $this->getJsonCompressed($rootActivity->pullReadOnlyData());
245 }
246 else
247 {
249 $rootActivity->pullReadOnlyData();
250 }
251
252 $workflowStatus = $rootActivity->GetWorkflowStatus();
253
254 if ($rootActivity->workflow->isAbandoned())
255 {
256 $workflowStatus = CBPWorkflowStatus::Completed;
257 }
258
259 $buffer = "";
260 if (($workflowStatus != CBPWorkflowStatus::Completed) && ($workflowStatus != CBPWorkflowStatus::Terminated))
261 {
262 $buffer = $this->GetSerializedForm($rootActivity);
263 }
264
265 $this->InsertWorkflow($rootActivity->GetWorkflowInstanceId(), $buffer, $workflowStatus, $bUnlocked, $creationData);
266 }
267
268 protected function getSerializedForm(CBPActivity $rootActivity)
269 {
270 $buffer = $rootActivity->Save();
271
272 if ($this->useGZipCompression)
273 $buffer = gzcompress($buffer, 9);
274 return $buffer;
275 }
276
277 private function getJsonCompressed($data): string
278 {
279 $buffer = Main\Web\Json::encode($data);
280
281 if ($this->useGZipCompression)
282 {
283 $buffer = gzcompress($buffer, 9);
284 }
285 return $buffer;
286 }
287
288 public function unlockWorkflow(CBPActivity $rootActivity)
289 {
290 global $DB;
291
292 if ($rootActivity == null)
293 throw new Exception("rootActivity");
294
295 $DB->Query(
296 "UPDATE b_bp_workflow_instance SET ".
297 " OWNER_ID = NULL, ".
298 " OWNED_UNTIL = NULL ".
299 "WHERE ID = '".$DB->ForSql($rootActivity->GetWorkflowInstanceId())."' ".
300 " AND ( ".
301 " (OWNER_ID = '".$DB->ForSql($this->serviceInstanceId)."' ".
302 " AND OWNED_UNTIL >= ".$DB->CurrentTimeFunction().") ".
303 " OR ".
304 " (OWNER_ID IS NULL) ".
305 " OR ".
306 " (OWNER_ID IS NOT NULL ".
307 " AND OWNED_UNTIL < ".$DB->CurrentTimeFunction().") ".
308 " )"
309 );
310 }
311
312 protected function getLockerQueryCondition()
313 {
314 global $DB;
315
316 return "(OWNER_ID IS NULL OR OWNER_ID = '".$DB->ForSql($this->serviceInstanceId)."')";
317 }
318
319 private function lock(string $workflowId): bool
320 {
321 if (!$this->useDbLock())
322 {
323 return true;
324 }
325
326 return $this->lockDb($workflowId);
327 }
328
329 private function unlock(string $workflowId): bool
330 {
331 if (!$this->useDbLock())
332 {
333 return true;
334 }
335
336 return $this->lockDb($workflowId, true);
337 }
338
339 private function useDbLock()
340 {
341 static $use;
342
343 if ($use === null)
344 {
345 $use = (Main\Config\Option::get('bizproc', 'workflow_dblock', 'N') === 'Y');
346 }
347
348 return $use;
349 }
350
351 private function lockDb(string $workflowId, bool $release = false): bool
352 {
353 $name = 'bizproc_' . $workflowId;
354 $connection = Main\Application::getInstance()->getConnection();
355
356 if ($release)
357 {
358 return $connection->unlock($name);
359 }
360
361 return $connection->lock($name);
362 }
363}
$arResult
Определения generate_coupon.php:16
static getPersister()
Определения workflowpersister.php:30
getLockerQueryCondition()
Определения workflowpersister.php:312
global $DB
Определения cron_frame.php:29
GetMessage($name, $aReplace=null)
Определения tools.php:3397
$dbResult
Определения updtr957.php:3