Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
templateprovider.php
1<?php
2
4
5use Bitrix\Bizproc\Workflow\Template\Entity\EO_WorkflowTemplate_Collection;
7use Bitrix\Bizproc\WorkflowTemplateTable;
16
18{
19 protected const ENTITY_ID = 'bizproc-template';
20 protected const TAB_ID = 'templates';
21 protected const ITEM_MODULE_ID_PREFIX = 'module:';
22 protected const ITEM_DOCUMENT_TYPE_PREFIX = 'document:';
23
24 protected ?array $complexDocumentTypesCache = null;
25
26 public function __construct(array $options = [])
27 {
28 parent::__construct();
29
30 $this->options['showManual'] = (isset($options['showManual']) && $options['showManual'] === true);
31 }
32
33 public function isAvailable(): bool
34 {
35 return $this->getCurrentUserId() > 0;
36 }
37
38 public function getItems(array $ids): array
39 {
40 $ids = array_filter(array_map('intval', $ids));
41 $templates = $this->getTemplatesByIds($ids);
42 $currentUserId = $this->getCurrentUserId();
43
44 $items = [];
45 foreach ($templates as $template)
46 {
47 if ($this->canUserStartWorkflow($currentUserId, $template->getDocumentComplexType()))
48 {
49 $items[] = $this->makeItem(['id' => $template->getId(), 'title' => $template->getName()], false);
50 }
51 }
52
53 return $items;
54 }
55
56 public function fillDialog(Dialog $dialog): void
57 {
58 $this->addTemplatesTab($dialog);
59 $currentUserId = $this->getCurrentUserId();
60
61 $complexDocumentTypes = $this->getComplexDocumentTypes();
62 foreach ($complexDocumentTypes as $documentType)
63 {
64 $moduleId = $documentType[0];
65 if (IsModuleInstalled($moduleId) && $this->canUserStartWorkflow($currentUserId, $documentType))
66 {
67 $moduleItem = $this->getModuleItem($dialog, $moduleId);
68 if (!$dialog->getItemCollection()->has($moduleItem))
69 {
70 $moduleItem->setNodeOptions(['dynamic' => true, 'open' => false]);
71 $dialog->addItem($moduleItem);
72 }
73 }
74 }
75
76 $this->openPreselectedItemTree($dialog);
77 }
78
79 protected function addTemplatesTab(Dialog $dialog): void
80 {
81 $icon =
82 'data:image/svg+xml,%3Csvg width=%2224%22 height=%2224%22 viewBox=%220 0 24 24%22 fill=%22none%22'
83 . ' xmlns=%22http://www.w3.org/2000/svg%22%3E%3Cpath'
84 . ' d=%22M5.89991 7.87642C5.89991 6.8374 6.7422 5.99512 7.78121 5.99512H16.2483C17.2873 5.99512 18.1296'
85 . ' 6.8374 18.1296 7.87642V9.7578H19.6965C19.8641 9.7578 19.948 9.96044 19.8295 10.079L17.1106'
86 . ' 12.7978C17.0372 12.8713 16.9181 12.8713 16.8446 12.7978L14.1257 10.079C14.0072 9.96044 14.0912 9.7578'
87 . ' 14.2588 9.7578H15.8878V8.63549C15.8878 8.39305 15.6913 8.19651 15.4489 8.19651H8.58066C8.33822 8.19651'
88 . ' 8.14169 8.39305 8.14169 8.63549V9.51372L5.89991 9.26298V7.87642Z%22'
89 . ' fill=%22%23525C69%22/%3E%3Cpath d=%22M5.89991 14.2046V16.1233C5.89991 17.1623 6.7422 18.0046 7.78121'
90 . ' 18.0046H16.2483C17.2873 18.0046 18.1296 17.1623 18.1296 16.1233V14.6184L15.8878'
91 . ' 14.3677V15.3642C15.8878 15.6067 15.6913 15.8032 15.4489 15.8032H8.58066C8.33822 15.8032 8.14169 15.6067'
92 . ' 8.14169 15.3642V14.2046H9.7412C9.9088 14.2046 9.99274 14.002 9.87423 13.8835L7.15538 11.1646C7.08191'
93 . ' 11.0911 6.96279 11.0911 6.88932 11.1646L4.17047 13.8835C4.05195 14.002 4.13589 14.2046 4.3035'
94 . ' 14.2046H5.89991Z%22 fill=%22%23525C69%22/%3E%3C/svg%3E%0A'
95 ;
96
97 $dialog->addTab(new Tab([
98 'id' => static::TAB_ID,
99 'title' => Loc::getMessage('BIZPROC_ENTITY_SELECTOR_TEMPLATES_TAB_TEMPLATES_TITLE'),
100 'itemOrder' => ['sort' => 'asc nulls last'],
101 'stub' => true,
102 'stubOptions' => [
103 'title' => Loc::getMessage('BIZPROC_ENTITY_SELECTOR_TEMPLATES_TAB_STUB_TITLE'),
104 ],
105 'icon' => [
106 'default' => $icon, // /bitrix/js/ui/icon-set/actions/images/refresh-1.svg
107 'selected' => str_replace('525C69', 'fff', $icon),
108 ], // todo
109 ]));
110 }
111
112 protected function openPreselectedItemTree(Dialog $dialog): void
113 {
114 $currentUserId = $this->getCurrentUserId();
115
116 $preselectedItems = $dialog->getPreselectedCollection()->getEntityItems(static::ENTITY_ID);
117 $ids = array_keys($preselectedItems);
118 $templates = $this->getTemplatesByIds(array_filter(array_map('intval', $ids)));
119
120 foreach ($templates as $template)
121 {
122 if (
123 IsModuleInstalled($template->getModuleId())
124 && $this->canUserStartWorkflow($currentUserId, $template->getDocumentComplexType())
125 )
126 {
127 $this->openTemplateTree($dialog, $template);
128 }
129 }
130 }
131
132 protected function openTemplateTree(Dialog $dialog, Tpl $template): void
133 {
134 $currentUserId = $this->getCurrentUserId();
135
136 $moduleItem = $dialog->getItemCollection()->get(
137 static::ENTITY_ID,
138 $this->createModuleId($template->getModuleId())
139 );
140 if ($moduleItem)
141 {
142 $moduleItem
143 ->setNodeOptions(['open' => true, 'dynamic' => false, 'itemOrder' => ['sort' => 'asc nulls last']])
144 ->setSort(1)
145 ;
146
147 $documentItem = $moduleItem->getChildren()->get(
148 static::ENTITY_ID,
149 $this->createDocumentId($template->getModuleId(), $template->getDocumentType())
150 );
151 if (!$documentItem)
152 {
153 $this->fillModuleItem($dialog, $moduleItem, $currentUserId);
154 $documentItem = $moduleItem->getChildren()->get(
155 static::ENTITY_ID,
156 $this->createDocumentId($template->getModuleId(), $template->getDocumentType())
157 );
158 }
159 $documentItem
160 ->setNodeOptions(['open' => true, 'dynamic' => false, 'itemOrder' => ['sort' => 'asc nulls last']]) // dynamic => true
161 ->setSort(1)
162 ;
163
164 $templateItem = $documentItem->getChildren()->get(static::ENTITY_ID, $template->getId());
165 if (!$templateItem)
166 {
167 $this->fillDocumentItem($dialog, $documentItem, $currentUserId);
168 $templateItem = $documentItem->getChildren()->get(static::ENTITY_ID, $template->getId());
169 }
170 $templateItem->setSort(1);
171 }
172 }
173
174 protected function getModuleItem(Dialog $dialog, string $moduleId): Item
175 {
176 $id = $this->createModuleId($moduleId);
177 $moduleItem = $dialog->getItemCollection()->get(static::ENTITY_ID, $id);
178 if ($moduleItem === null)
179 {
180 $title =
181 Loc::getMessage('BIZPROC_ENTITY_SELECTOR_TEMPLATES_MODULE_' . mb_strtoupper($moduleId))
182 ?: $moduleId
183 ;
184 $moduleItem = $this->makeItem(['id' => $id, 'title' => $title]);
185 $moduleItem->setCustomData(['moduleId' => $moduleId]);
186 $moduleItem->setSearchable(false);
187 }
188
189 return $moduleItem;
190 }
191
192 protected function getDocumentItem(Dialog $dialog, array $complexDocumentType): Item
193 {
194 $id = $this->createDocumentId($complexDocumentType[0], $complexDocumentType[2]);
195 $documentItem = $dialog->getItemCollection()->get(static::ENTITY_ID, $id);
196 if ($documentItem === null)
197 {
198 $documentService = \CBPRuntime::getRuntime()->getDocumentService();
199
200 $title = $documentService->getDocumentTypeCaption($complexDocumentType);
201 if (\CBPHelper::isEmptyValue($title))
202 {
203 $title = $complexDocumentType[2];
204 }
205
206 $documentItem = $this->makeItem(['id' => $id, 'title' => $title]);
207 $documentItem->setCustomData([
208 'moduleId' => $complexDocumentType[0],
209 'documentType' => $complexDocumentType[2],
210 ]);
211 $documentItem->setSearchable(false);
212 }
213
214 return $documentItem;
215 }
216
217 public function getChildren(Item $parentItem, Dialog $dialog): void
218 {
219 $currentUserId = $this->getCurrentUserId();
220 $parentItemId = $parentItem->getId();
221
222 if (mb_strpos($parentItemId, static::ITEM_MODULE_ID_PREFIX) === 0)
223 {
224 if (mb_strpos($parentItemId, static::ITEM_DOCUMENT_TYPE_PREFIX) !== false)
225 {
226 $this->fillDocumentItem($dialog, $parentItem, $currentUserId);
227 }
228 else
229 {
230 $this->fillModuleItem($dialog, $parentItem, $currentUserId);
231 }
232
233 $dialog->addItems($parentItem->getChildren()->getAll());
234 }
235
236 parent::getChildren($parentItem, $dialog);
237 }
238
239 protected function fillModuleItem(Dialog $dialog, Item $moduleItem, int $currentUserId): void
240 {
241 $moduleId = $this->parseModuleItemId($moduleItem->getId());
242 if ($moduleId && IsModuleInstalled($moduleId))
243 {
244 $complexDocumentTypes = $this->getComplexDocumentTypes($moduleId);
245 foreach ($complexDocumentTypes as $complexDocumentType)
246 {
247 if ($this->canUserStartWorkflow($currentUserId, $complexDocumentType))
248 {
249 $documentItem = $this->getDocumentItem($dialog, $complexDocumentType);
250 $documentItem->setNodeOptions(['dynamic' => true]);
251 $moduleItem->addChild($documentItem);
252 }
253 }
254 }
255 }
256
257 protected function fillDocumentItem(Dialog $dialog, Item $documentItem, int $currentUserId): void
258 {
259 [$moduleId, $documentType] = $this->parseDocumentItemId($documentItem->getId());
260
261 if ($moduleId && $documentType && IsModuleInstalled($moduleId))
262 {
263 $templates = $this->getTemplatesByDocumentType($moduleId, $documentType);
264 foreach ($templates as $template)
265 {
266 if ($this->canUserStartWorkflow($currentUserId, $template->getDocumentComplexType()))
267 {
268 $item = $this->makeItem(['id' => $template->getId(), 'title' => $template->getName()]);
269 $documentItem->addChild($item);
270 }
271 }
272 }
273 }
274
275 private function getTemplatesByIds(array $ids): EO_WorkflowTemplate_Collection
276 {
277 if (!$ids)
278 {
279 return new EO_WorkflowTemplate_Collection();
280 }
281
282 $query =
283 WorkflowTemplateTable::query()
284 ->setSelect(['ID', 'MODULE_ID', 'ENTITY', 'DOCUMENT_TYPE', 'NAME'])
285 ->where($this->getDefaultTemplateFilter())
286 ;
287 if (count($ids) === 1)
288 {
289 $query->where('ID', $ids[0]);
290 }
291 else
292 {
293 $query->whereIn('ID', $ids);
294 }
295
296 return $query->exec()->fetchCollection();
297 }
298
299 private function getTemplatesByDocumentType(
300 string $moduleId,
301 string $documentType
302 ): \Bitrix\Bizproc\Workflow\Template\Entity\EO_WorkflowTemplate_Collection
303 {
304 $query =
305 WorkflowTemplateTable::query()
306 ->setSelect(['ID', 'MODULE_ID', 'ENTITY', 'DOCUMENT_TYPE', 'NAME'])
307 ->where('MODULE_ID', $moduleId)
308 ->where('DOCUMENT_TYPE', $documentType)
309 ->where($this->getDefaultTemplateFilter())
310 ;
311
312 return $query->exec()->fetchCollection();
313 }
314
315 protected function getComplexDocumentTypes(string $moduleId = ''): array
316 {
317 if ($this->complexDocumentTypesCache === null)
318 {
319 $query =
320 WorkflowTemplateTable::query()
321 ->setDistinct()
322 ->setSelect(['MODULE_ID', 'ENTITY', 'DOCUMENT_TYPE'])
323 ->where($this->getDefaultTemplateFilter())
324 ;
325 $complexDocumentTypes = $query->exec()->fetchAll();
326
327 $this->complexDocumentTypesCache = [];
328 foreach ($complexDocumentTypes as $documentType)
329 {
330 $this->complexDocumentTypesCache[] =
331 [$documentType['MODULE_ID'], $documentType['ENTITY'], $documentType['DOCUMENT_TYPE']]
332 ;
333 }
334 }
335
336 $filter = static fn ($docType) => ($docType[0] === $moduleId);
337
338 return $moduleId ? array_filter($this->complexDocumentTypesCache, $filter) : $this->complexDocumentTypesCache;
339 }
340
341 public function doSearch(SearchQuery $searchQuery, Dialog $dialog): void
342 {
343 $currentUserId = $this->getCurrentUserId();
344
345 $templates =
346 WorkflowTemplateTable::query()
347 ->setSelect(['ID', 'MODULE_ID', 'ENTITY', 'DOCUMENT_TYPE', 'NAME'])
348 ->whereLike('NAME', "%{$searchQuery->getQuery()}%")
349 ->where($this->getDefaultTemplateFilter())
350 ->exec()
351 ->fetchCollection();
352
353 $items = [];
354 foreach ($templates as $template)
355 {
356 if ($this->canUserStartWorkflow($currentUserId, $template->getDocumentComplexType()))
357 {
358 $items[] = $this->makeItem(['id' => $template->getId(), 'title' => $template->getName()], false);
359 }
360 }
361
362 if ($items)
363 {
364 $dialog->addItems($items);
365 }
366 }
367
369 {
370 $filter = \Bitrix\Main\ORM\Query\Query::filter();
371 $filter->where('ACTIVE', 'Y');
372
373 $autoExecuteFilter =
374 \Bitrix\Main\ORM\Query\Query::filter()
375 ->logic(ConditionTree::LOGIC_OR)
376 ->where('AUTO_EXECUTE', '<', \CBPDocumentEventType::Automation)
377 ;
378
379 if ($this->options['showManual'])
380 {
381 $autoExecuteFilter->where('AUTO_EXECUTE', \CBPDocumentEventType::Manual);
382 }
383
384 return $filter->where($autoExecuteFilter);
385 }
386
387 protected function canUserStartWorkflow(int $userId, array $complexDocumentType): bool
388 {
389 if ($this->isUserWorkflowTemplateAdmin($userId))
390 {
391 return true;
392 }
393
394 try
395 {
396 return \CBPDocument::canUserOperateDocumentType(
397 \CBPCanUserOperateOperation::StartWorkflow,
398 $userId,
399 $complexDocumentType
400 );
401 }
402 catch (\CBPArgumentNullException $exception)
403 {
404 //return false;
405 }
406
407 return false;
408 }
409
410 private function makeItem(array $data, bool $addTab = true): Item
411 {
412 $item = new Item([
413 'id' => $data['id'],
414 'entityId' => static::ENTITY_ID,
415 'title' => $data['title'],
416 ]);
417 if ($addTab)
418 {
419 $item->addTab(static::TAB_ID);
420 }
421
422 return $item;
423 }
424
425 protected function isUserWorkflowTemplateAdmin(int $userId): bool
426 {
427 return (new \CBPWorkflowTemplateUser($userId))->isAdmin();
428 }
429
430 protected function getCurrentUserId(): int
431 {
432 return (int)(CurrentUser::get()->getId());
433 }
434
435 protected function createModuleId(string $moduleId): string
436 {
437 return static::ITEM_MODULE_ID_PREFIX . $moduleId;
438 }
439
440 protected function createDocumentId(string $moduleId, string $documentId): string
441 {
442 return $this->createModuleId($moduleId) . '@' . static::ITEM_DOCUMENT_TYPE_PREFIX . $documentId;
443 }
444
445 protected function parseModuleItemId(string $id): string
446 {
447 return mb_substr($id, strlen(static::ITEM_MODULE_ID_PREFIX));
448 }
449
450 protected function parseDocumentItemId(string $id): array
451 {
452 [$moduleItemId, $documentItemId] = mb_split('@', $id);
453
454 $document = mb_substr($documentItemId, strlen(static::ITEM_DOCUMENT_TYPE_PREFIX));
455
456 return [$this->parseModuleItemId($moduleItemId), $document];
457 }
458}
fillDocumentItem(Dialog $dialog, Item $documentItem, int $currentUserId)
fillModuleItem(Dialog $dialog, Item $moduleItem, int $currentUserId)
getDocumentItem(Dialog $dialog, array $complexDocumentType)
canUserStartWorkflow(int $userId, array $complexDocumentType)
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29