1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
usertypemanager.php
См. документацию.
1<?php
2
11
12IncludeModuleLangFile(__FILE__);
13
21{
22 const BASE_TYPE_INT = "int";
23 const BASE_TYPE_FILE = "file";
24 const BASE_TYPE_ENUM = "enum";
25 const BASE_TYPE_DOUBLE = "double";
26 const BASE_TYPE_DATETIME = "datetime";
27 const BASE_TYPE_STRING = "string";
28
30 protected $arUserTypes = false;
31 protected $arFieldsCache = [];
32 protected $arRightsCache = [];
37 protected $entityList = null;
38
39 public function CleanCache()
40 {
41 $this->arFieldsCache = [];
42 $this->arUserTypes = false;
43 }
44
56 public function GetUserType($user_type_id = false)
57 {
58 if (!is_array($this->arUserTypes))
59 {
60 $this->arUserTypes = [];
61 foreach (GetModuleEvents("main", "OnUserTypeBuildList", true) as $arEvent)
62 {
63 $res = ExecuteModuleEventEx($arEvent);
64 $this->arUserTypes[$res["USER_TYPE_ID"]] = $res;
65 }
66 }
67 if ($user_type_id !== false)
68 {
69 if (array_key_exists($user_type_id, $this->arUserTypes))
70 {
71 return $this->arUserTypes[$user_type_id];
72 }
73 else
74 {
75 return false;
76 }
77 }
78 else
79 {
80 return $this->arUserTypes;
81 }
82 }
83
84 public function GetDBColumnType($arUserField)
85 {
86 if ($arType = $this->GetUserType($arUserField["USER_TYPE_ID"]))
87 {
88 if (is_callable([$arType["CLASS_NAME"], "getdbcolumntype"]))
89 {
90 return call_user_func_array([$arType["CLASS_NAME"], "getdbcolumntype"], [$arUserField]);
91 }
92 }
93 return "";
94 }
95
96 public function getUtsDBColumnType($arUserField)
97 {
98 if ($arUserField['MULTIPLE'] == 'Y')
99 {
100 $sqlHelper = \Bitrix\Main\Application::getConnection()->getSqlHelper();
101 return $sqlHelper->getColumnTypeByField(new Fields\TextField('TMP'));
102 }
103 else
104 {
105 return $this->GetDBColumnType($arUserField);
106 }
107 }
108
109 public function getUtmDBColumnType($arUserField)
110 {
111 return $this->GetDBColumnType($arUserField);
112 }
113
114 public function PrepareSettings($ID, $arUserField, $bCheckUserType = true)
115 {
116 $user_type_id = $arUserField['USER_TYPE_ID'] ?? null;
117 if ($ID > 0)
118 {
119 $rsUserType = CUserTypeEntity::GetList([], ["ID" => $ID]);
120 $arUserType = $rsUserType->Fetch();
121 if ($arUserType)
122 {
123 $user_type_id = $arUserType["USER_TYPE_ID"];
124 $arUserField += $arUserType;
125 }
126 }
127
128 if (!$bCheckUserType)
129 {
130 if (!isset($arUserField["SETTINGS"]))
131 {
132 return [];
133 }
134
135 if (!is_array($arUserField["SETTINGS"]))
136 {
137 return [];
138 }
139
140 if (empty($arUserField["SETTINGS"]))
141 {
142 return [];
143 }
144 }
145
146 $userType = $this->GetUserType($user_type_id);
147
148 if ($userType && is_callable([$userType['CLASS_NAME'], 'preparesettings']))
149 {
150 return call_user_func_array([$userType['CLASS_NAME'], 'preparesettings'], [$arUserField]);
151 }
152
153 if (!$userType)
154 {
155 return [];
156 }
157
158 return null;
159 }
160
161 public function getCustomData(array $userField, int $entityValueId): array
162 {
163 $hasCustomData =
164 isset($userField['USER_TYPE']['CLASS_NAME'])
165 && is_callable([$userField['USER_TYPE']['CLASS_NAME'], 'getCustomData']);
166
167 $customData = [];
168 if ($hasCustomData)
169 {
170 $customData = call_user_func_array(
171 [$userField['USER_TYPE']['CLASS_NAME'], 'getCustomData'],
172 [$userField, $entityValueId]
173 );
174 }
175
176 return is_array($customData) ? $customData : [];
177 }
178
179 public function OnEntityDelete($entity_id)
180 {
181 $obUserField = new CUserTypeEntity;
182 return $obUserField->DropEntity($entity_id);
183 }
184
191 public function GetUserFields($entity_id, $value_id = 0, $LANG = false, $user_id = false, $selectFields = null)
192 {
193 global $DB;
194
195 $entity_id = static::normalizeId($entity_id);
196 $value_id = intval($value_id);
197
198 $result = $this->getEntities($entity_id, $LANG, $user_id);
199
200 if (!empty($result) && $value_id > 0)
201 {
202 $valuesGottenByEvent = $this->getUserFieldValuesByEvent($result, $entity_id, $value_id);
203
204 if ($selectFields !== null)
205 {
206 $selectFields = array_flip($selectFields);
207 }
208
209 $select = [];
210 foreach ($result as $fieldName => $arUserField)
211 {
212 $result[$fieldName]["ENTITY_VALUE_ID"] = $value_id;
213
214 if (is_array($valuesGottenByEvent))
215 {
216 $result[$fieldName]["VALUE"] = array_key_exists($fieldName, $valuesGottenByEvent) ? $valuesGottenByEvent[$fieldName] : $result[$fieldName]["VALUE"];
217 $result[$fieldName]["CUSTOM_DATA"] = $this->getCustomData($result[$fieldName], $value_id);
218 }
219 elseif ($selectFields === null || isset($selectFields[$fieldName]))
220 {
221 if ($arUserField["MULTIPLE"] == "N"
222 && is_array($arUserField["USER_TYPE"])
223 && array_key_exists("CLASS_NAME", $arUserField["USER_TYPE"])
224 && is_callable([$arUserField["USER_TYPE"]["CLASS_NAME"], "FormatField"]))
225 {
226 $select[] = call_user_func_array([$arUserField["USER_TYPE"]["CLASS_NAME"], "FormatField"], [$arUserField, $fieldName]) . " " . $fieldName;
227 }
228 else
229 {
230 $select[] = $fieldName;
231 }
232 }
233 }
234
235 if (is_array($valuesGottenByEvent))
236 {
237 return $result;
238 }
239
240 if (!empty($select))
241 {
242 $rs = $DB->Query("SELECT " . implode(', ', $select) . " FROM b_uts_" . strtolower($entity_id) . " WHERE VALUE_ID = " . $value_id);
243
244 if ($ar = $rs->Fetch())
245 {
246 foreach ($ar as $key => $value)
247 {
248 $result[$key]["VALUE_EXISTS"] = true;
249 $result[$key]["VALUE_RAW"] = $value;
250
251 if ($result[$key]["MULTIPLE"] == "Y")
252 {
253 if (!str_starts_with($value, 'a') && $value > 0)
254 {
255 $value = $this->LoadMultipleValues($result[$key], $value);
256 }
257 else
258 {
259 $value = unserialize($value, ['allowed_classes' => false]);
260 }
261 }
262 $result[$key]["VALUE"] = $this->OnAfterFetch($result[$key], $value);
263 }
264 }
265 }
266
267 foreach ($result as $fieldName => $userField)
268 {
269 $result[$fieldName]["CUSTOM_DATA"] = $this->getCustomData($userField, $value_id);
270 }
271 }
272
273 return $result;
274 }
275
287 public function getUserFieldsWithReadyData($entity_id, $readyData, $LANG = false, $user_id = false, $primaryIdName = 'VALUE_ID')
288 {
289 if ($readyData === null)
290 {
291 return $this->GetUserFields($entity_id, null, $LANG, $user_id);
292 }
293
294 $entity_id = static::normalizeId($entity_id);
295
296 $result = $this->getEntities($entity_id, $LANG, $user_id);
297
298 foreach ($readyData as $key => $value)
299 {
300 if (array_key_exists($key, $result))
301 {
302 if ($result[$key]["MULTIPLE"] == "Y" && !is_array($value))
303 {
304 $value = unserialize($value, ['allowed_classes' => false]);
305 }
306
307 $result[$key]["VALUE"] = $this->OnAfterFetch($result[$key], $value);
308 $result[$key]["ENTITY_VALUE_ID"] = $readyData[$primaryIdName] ?? null;
309 }
310 }
311
312 return $result;
313 }
314
315 public function GetUserFieldValue($entity_id, $field_id, $value_id, $LANG = false)
316 {
317 global $DB;
318
319 $entity_id = static::normalizeId($entity_id);
320 $field_id = static::normalizeId($field_id);
321 $value_id = intval($value_id);
322 $strTableName = "b_uts_" . strtolower($entity_id);
323 $result = false;
324
325 $arFilter = [
326 "ENTITY_ID" => $entity_id,
327 "FIELD_NAME" => $field_id,
328 ];
329 if ($LANG)
330 {
331 $arFilter["LANG"] = $LANG;
332 }
333 $rs = CUserTypeEntity::GetList([], $arFilter);
334 if ($arUserField = $rs->Fetch())
335 {
336 $values = $this->getUserFieldValuesByEvent([$arUserField['FIELD_NAME'] => $arUserField], $entity_id, $value_id);
337 if (is_array($values))
338 {
339 return $values[$arUserField['FIELD_NAME']];
340 }
341 $arUserField["USER_TYPE"] = $this->GetUserType($arUserField["USER_TYPE_ID"]);
342 $arTableFields = $DB->GetTableFields($strTableName);
343 if (array_key_exists($field_id, $arTableFields))
344 {
345 $simpleFormat = true;
346 $select = "";
347 if ($arUserField["MULTIPLE"] == "N")
348 {
349 if ($arType = $arUserField["USER_TYPE"])
350 {
351 if (is_callable([$arType["CLASS_NAME"], "FormatField"]))
352 {
353 $select = call_user_func_array([$arType["CLASS_NAME"], "FormatField"], [$arUserField, $field_id]);
354 $simpleFormat = false;
355 }
356 }
357 }
358 if ($simpleFormat)
359 {
360 $select = $field_id;
361 }
362
363 $rs = $DB->Query("SELECT " . $select . " " . $DB->quote('VALUE') . " FROM " . $strTableName . " WHERE VALUE_ID = " . $value_id);
364 if ($ar = $rs->Fetch())
365 {
366 if ($arUserField["MULTIPLE"] == "Y")
367 {
368 $result = $this->OnAfterFetch($arUserField, unserialize($ar["VALUE"], ['allowed_classes' => false]));
369 }
370 else
371 {
372 $result = $this->OnAfterFetch($arUserField, $ar["VALUE"]);
373 }
374 }
375 }
376 }
377
378 return $result;
379 }
380
385 public function getEntityList()
386 {
387 if ($this->entityList === null)
388 {
389 $event = new \Bitrix\Main\Event('main', 'onUserTypeEntityOrmMap');
390 $event->send();
391
392 foreach ($event->getResults() as $eventResult)
393 {
394 if ($eventResult->getType() == \Bitrix\Main\EventResult::SUCCESS)
395 {
396 $result = $eventResult->getParameters(); // [ENTITY_ID => 'SomeTable']
397 foreach ($result as $entityId => $entityClass)
398 {
399 if (!str_starts_with($entityClass, '\\'))
400 {
401 $entityClass = '\\' . $entityClass;
402 }
403
404 $this->entityList[$entityId] = $entityClass;
405 }
406 }
407 }
408 }
409
410 return $this->entityList;
411 }
412
413 public function OnAfterFetch($arUserField, $result)
414 {
415 if (is_callable([$arUserField["USER_TYPE"]["CLASS_NAME"], "onafterfetch"]))
416 {
417 if ($arUserField["MULTIPLE"] == "Y")
418 {
419 if (is_array($result))
420 {
421 $resultCopy = $result;
422 $result = [];
423 foreach ($resultCopy as $value)
424 {
425 $convertedValue = call_user_func_array(
426 [$arUserField["USER_TYPE"]["CLASS_NAME"], "onafterfetch"],
427 [
428 $arUserField,
429 [
430 "VALUE" => $value,
431 ],
432 ]
433 );
434 if ($convertedValue !== null)
435 {
436 $result[] = $convertedValue;
437 }
438 }
439 }
440 }
441 else
442 {
443 $result = call_user_func_array(
444 [$arUserField["USER_TYPE"]["CLASS_NAME"], "onafterfetch"],
445 [
446 $arUserField,
447 [
448 "VALUE" => $result,
449 ],
450 ]
451 );
452 }
453 }
454 return $result;
455 }
456
457 public function LoadMultipleValues($arUserField, $valueId)
458 {
459 global $DB;
460 $result = [];
461
462 $rs = $DB->Query("
463 SELECT *
464 FROM b_utm_" . strtolower($arUserField["ENTITY_ID"]) . "
465 WHERE VALUE_ID = " . intval($valueId) . "
466 AND FIELD_ID = " . $arUserField["ID"] . "
467 ");
468 while ($ar = $rs->Fetch())
469 {
470 if ($arUserField["USER_TYPE"]["USER_TYPE_ID"] == "date")
471 {
472 $result[] = substr($ar["VALUE_DATE"], 0, 10);
473 }
474 else
475 {
476 switch ($arUserField["USER_TYPE"]["BASE_TYPE"])
477 {
478 case "int":
479 case "file":
480 case "enum":
481 $result[] = $ar["VALUE_INT"];
482 break;
483 case "double":
484 $result[] = $ar["VALUE_DOUBLE"];
485 break;
486 case "datetime":
487 $result[] = $ar["VALUE_DATE"];
488 break;
489 default:
490 $result[] = $ar["VALUE"];
491 }
492 }
493 }
494 return $result;
495 }
496
497 public function EditFormTab($entity_id)
498 {
499 $entity_id = static::normalizeId($entity_id);
500
501 return [
502 "DIV" => "user_fields_tab_" . $entity_id,
503 "TAB" => GetMessage("USER_TYPE_EDIT_TAB"),
504 "ICON" => "none",
505 "TITLE" => GetMessage("USER_TYPE_EDIT_TAB_TITLE"),
506 ];
507 }
508
509 public function EditFormShowTab($entity_id, $bVarsFromForm, $ID)
510 {
511 global $APPLICATION;
512
513 if ($this->GetRights($entity_id) >= "W")
514 {
515 echo "<tr colspan=\"2\"><td align=\"left\"><a href=\"/bitrix/admin/userfield_edit.php?lang=" . LANG . "&ENTITY_ID=" . urlencode($entity_id) . "&back_url=" . urlencode($APPLICATION->GetCurPageParam("", ["bxpublic"]) . "&tabControl_active_tab=user_fields_tab") . "\">" . GetMessage("USER_TYPE_EDIT_TAB_HREF") . "</a></td></tr>";
516 }
517
518 $arUserFields = $this->GetUserFields($entity_id, $ID, LANGUAGE_ID);
519 if (!empty($arUserFields))
520 {
521 foreach ($arUserFields as $FIELD_NAME => $arUserField)
522 {
523 $arUserField["VALUE_ID"] = intval($ID);
524 echo $this->GetEditFormHTML($bVarsFromForm, $GLOBALS[$FIELD_NAME], $arUserField);
525 }
526 }
527 }
528
529 public function EditFormAddFields($entity_id, &$arFields, array $options = null)
530 {
531 if (!is_array($options))
532 {
533 $options = [];
534 }
535
536 if (!is_array($arFields))
537 {
538 $arFields = [];
539 }
540
541 $files = $options['FILES'] ?? $_FILES;
542 $form = isset($options['FORM']) && is_array($options['FORM']) ? $options['FORM'] : $GLOBALS;
543
544 $arUserFields = $this->GetUserFields($entity_id);
545 foreach ($arUserFields as $arUserField)
546 {
547 $fieldName = $arUserField['FIELD_NAME'];
548 if ($arUserField["EDIT_IN_LIST"] == "Y")
549 {
550 if ($arUserField["USER_TYPE"]["BASE_TYPE"] == "file")
551 {
552 if (isset($files[$fieldName]))
553 {
554 if (is_array($files[$fieldName]["name"]))
555 {
556 $arFields[$fieldName] = [];
557 foreach ($files[$fieldName]["name"] as $key => $value)
558 {
559 $old_id = $form[$fieldName . "_old_id"][$key] ?? null;
560 $arFields[$fieldName][$key] = [
561 "name" => $files[$fieldName]["name"][$key],
562 "type" => $files[$fieldName]["type"][$key],
563 "tmp_name" => $files[$fieldName]["tmp_name"][$key],
564 "error" => $files[$fieldName]["error"][$key],
565 "size" => $files[$fieldName]["size"][$key],
566 "del" =>
567 isset($form[$fieldName . "_del"])
568 && is_array($form[$fieldName . "_del"]) &&
569 (in_array($old_id, $form[$fieldName . "_del"]) ||
570 (
571 array_key_exists($key, $form[$fieldName . "_del"]) &&
572 $form[$fieldName . "_del"][$key] == "Y"
573 )
574 ),
575 "old_id" => $old_id,
576 ];
577 }
578 }
579 else
580 {
581 $arFields[$fieldName] = $files[$fieldName];
582 $arFields[$fieldName]["del"] = $form[$fieldName . "_del"] ?? '';
583 $arFields[$fieldName]["old_id"] = $form[$fieldName . "_old_id"] ?? '';
584 }
585 }
586 else
587 {
588 if (isset($form[$fieldName]))
589 {
590 if (!is_array($form[$fieldName]))
591 {
592 if (intval($form[$fieldName]) > 0)
593 {
594 $arFields[$fieldName] = intval($form[$fieldName]);
595 }
596 }
597 else
598 {
599 $fields = [];
600 foreach ($form[$fieldName] as $val)
601 {
602 if (intval($val) > 0)
603 {
604 $fields[] = intval($val);
605 }
606 }
607 $arFields[$fieldName] = $fields;
608 }
609 }
610 }
611 }
612 else
613 {
614 if (isset($files[$fieldName]))
615 {
616 $arFile = [];
617 CFile::ConvertFilesToPost($files[$fieldName], $arFile);
618
619 if (isset($form[$fieldName]))
620 {
621 if ($arUserField["MULTIPLE"] == "Y")
622 {
623 foreach ($form[$fieldName] as $key => $value)
624 {
625 $arFields[$fieldName][$key] = array_merge($value, $arFile[$key]);
626 }
627 }
628 else
629 {
630 $arFields[$fieldName] = array_merge($form[$fieldName], $arFile);
631 }
632 }
633 else
634 {
635 $arFields[$fieldName] = $arFile;
636 }
637 }
638 else
639 {
640 if (isset($form[$fieldName]))
641 {
642 $arFields[$fieldName] = $form[$fieldName];
643 }
644 }
645 }
646 }
647 }
648 }
649
656 {
657 $arUserFields = $this->GetUserFields($entityId);
658 foreach ($arUserFields as $fieldName => $arUserField)
659 {
660 if ($arUserField['SHOW_FILTER'] != 'N' && $arUserField['USER_TYPE']['BASE_TYPE'] != 'file')
661 {
662 $arFilterFields[] = 'find_' . $fieldName;
663 if ($arUserField['USER_TYPE']['BASE_TYPE'] == 'datetime')
664 {
665 $arFilterFields[] = 'find_' . $fieldName . '_from';
666 $arFilterFields[] = 'find_' . $fieldName . '_to';
667 }
668 }
669 }
670 }
671
673 {
674 $arUserFields = $this->GetUserFields($entityId, 0, $GLOBALS["lang"]);
675 foreach ($arUserFields as $fieldName => $arUserField)
676 {
677 if ($arUserField['SHOW_FILTER'] != 'N' && $arUserField['USER_TYPE']['BASE_TYPE'] != 'file')
678 {
679 if (is_callable([$arUserField['USER_TYPE']['CLASS_NAME'], 'GetFilterData']))
680 {
681 $arFilterFields[] = call_user_func_array(
682 [$arUserField['USER_TYPE']['CLASS_NAME'], 'GetFilterData'],
683 [
684 $arUserField,
685 [
686 'ID' => $fieldName,
687 'NAME' => $arUserField['LIST_FILTER_LABEL'] ?: $arUserField['FIELD_NAME'],
688 ],
689 ]
690 );
691 }
692 }
693 }
694 }
695
696 public function IsNotEmpty($value)
697 {
698 if (is_array($value))
699 {
700 foreach ($value as $v)
701 {
702 if ((string)$v <> '')
703 {
704 return true;
705 }
706 }
707
708 return false;
709 }
710 else
711 {
712 if ((string)$value <> '')
713 {
714 return true;
715 }
716 else
717 {
718 return false;
719 }
720 }
721 }
722
729 {
730 $arUserFields = $this->GetUserFields($entityId);
731 foreach ($arUserFields as $fieldName => $arUserField)
732 {
733 if (
734 $arUserField['SHOW_FILTER'] != 'N' &&
735 $arUserField['USER_TYPE']['BASE_TYPE'] == 'datetime'
736 )
737 {
738 $value1 = $GLOBALS['find_' . $fieldName . '_from'] ?? null;
739 $value2 = $GLOBALS['find_' . $fieldName . '_to'] ?? null;
740 if ($this->IsNotEmpty($value1) && \Bitrix\Main\Type\Date::isCorrect($value1))
741 {
742 $date = new \Bitrix\Main\Type\Date($value1);
743 $arFilter['>=' . $fieldName] = $date;
744 }
745 if ($this->IsNotEmpty($value2) && \Bitrix\Main\Type\Date::isCorrect($value2))
746 {
747 $date = new \Bitrix\Main\Type\Date($value2);
748 if ($arUserField['USER_TYPE_ID'] != 'date')
749 {
750 $date->add('+1 day');
751 }
752 $arFilter['<=' . $fieldName] = $date;
753 }
754 continue;
755 }
756 else
757 {
758 $value = $GLOBALS['find_' . $fieldName] ?? null;
759 }
760 if (
761 $arUserField['SHOW_FILTER'] != 'N'
762 && $arUserField['USER_TYPE']['BASE_TYPE'] != 'file'
763 && $this->IsNotEmpty($value)
764 )
765 {
766 if ($arUserField['SHOW_FILTER'] == 'I')
767 {
768 $arFilter['=' . $fieldName] = $value;
769 }
770 elseif ($arUserField['SHOW_FILTER'] == 'S')
771 {
772 $arFilter['%' . $fieldName] = $value;
773 }
774 else
775 {
776 $arFilter[$fieldName] = $value;
777 }
778 }
779 }
780 }
781
783 {
784 $filterOption = new Bitrix\Main\UI\Filter\Options($filterId);
785 $filterData = $filterOption->getFilter($filterFields);
786
787 $arUserFields = $this->GetUserFields($entityId);
788 foreach ($arUserFields as $fieldName => $arUserField)
789 {
790 if ($arUserField['SHOW_FILTER'] != 'N' && $arUserField['USER_TYPE']['BASE_TYPE'] == 'datetime')
791 {
792 $value1 = $filterData[$fieldName . '_from'] ?? '';
793 $value2 = $filterData[$fieldName . '_to'] ?? '';
794 if ($this->IsNotEmpty($value1) && \Bitrix\Main\Type\Date::isCorrect($value1))
795 {
796 $date = new \Bitrix\Main\Type\Date($value1);
797 $arFilter['>=' . $fieldName] = $date;
798 }
799 if ($this->IsNotEmpty($value2) && \Bitrix\Main\Type\Date::isCorrect($value2))
800 {
801 $date = new \Bitrix\Main\Type\Date($value2);
802 if ($arUserField['USER_TYPE_ID'] != 'date')
803 {
804 $date->add('+1 day');
805 }
806 $arFilter['<=' . $fieldName] = $date;
807 }
808 continue;
809 }
810 elseif ($arUserField['SHOW_FILTER'] != 'N' && $arUserField['USER_TYPE']['BASE_TYPE'] == 'int')
811 {
812 if ($arUserField['USER_TYPE_ID'] == 'boolean')
813 {
814 if (isset($filterData[$fieldName]) && $filterData[$fieldName] === 'Y')
815 {
816 $filterData[$fieldName] = 1;
817 }
818 if (isset($filterData[$fieldName]) && $filterData[$fieldName] === 'N')
819 {
820 $filterData[$fieldName] = 0;
821 }
822 }
823 $value = $filterData[$fieldName] ?? null;
824 }
825 else
826 {
827 $value = $filterData[$fieldName] ?? null;
828 }
829 if (
830 $arUserField['SHOW_FILTER'] != 'N'
831 && $arUserField['USER_TYPE']['BASE_TYPE'] != 'file'
832 && $this->IsNotEmpty($value)
833 )
834 {
835 if ($arUserField['SHOW_FILTER'] == 'I')
836 {
837 unset($arFilter[$fieldName]);
838 $arFilter['=' . $fieldName] = $value;
839 }
840 elseif ($arUserField['SHOW_FILTER'] == 'S')
841 {
842 unset($arFilter[$fieldName]);
843 $arFilter['%' . $fieldName] = $value;
844 }
845 else
846 {
847 $arFilter[$fieldName] = $value;
848 }
849 }
850 }
851 }
852
853 public function AdminListPrepareFields($entity_id, &$arFields)
854 {
855 $arUserFields = $this->GetUserFields($entity_id);
856 foreach ($arUserFields as $FIELD_NAME => $arUserField)
857 {
858 if ($arUserField["EDIT_IN_LIST"] != "Y")
859 {
860 unset($arFields[$FIELD_NAME]);
861 }
862 }
863 }
864
865 public function AdminListAddHeaders($entity_id, &$arHeaders)
866 {
867 $arUserFields = $this->GetUserFields($entity_id, 0, $GLOBALS["lang"]);
868 foreach ($arUserFields as $FIELD_NAME => $arUserField)
869 {
870 if ($arUserField["SHOW_IN_LIST"] == "Y")
871 {
872 $arHeaders[] = [
873 "id" => $FIELD_NAME,
874 "content" => htmlspecialcharsbx($arUserField["LIST_COLUMN_LABEL"] ?: $arUserField["FIELD_NAME"]),
875 "sort" => $arUserField["MULTIPLE"] == "N" ? $FIELD_NAME : false,
876 ];
877 }
878 }
879 }
880
881 public function AddUserFields($entity_id, $arRes, $row)
882 {
883 $arUserFields = $this->GetUserFields($entity_id);
884 foreach ($arUserFields as $FIELD_NAME => $arUserField)
885 {
886 if ($arUserField["SHOW_IN_LIST"] == "Y" && array_key_exists($FIELD_NAME, $arRes))
887 {
888 $this->AddUserField($arUserField, $arRes[$FIELD_NAME], $row);
889 }
890 }
891 }
892
893 public function AddFindFields($entity_id, &$arFindFields)
894 {
895 $arUserFields = $this->GetUserFields($entity_id, 0, $GLOBALS["lang"]);
896 foreach ($arUserFields as $FIELD_NAME => $arUserField)
897 {
898 if ($arUserField["SHOW_FILTER"] != "N" && $arUserField["USER_TYPE"]["BASE_TYPE"] != "file")
899 {
900 if ($arUserField["USER_TYPE"] && is_callable([$arUserField["USER_TYPE"]["CLASS_NAME"], "getfilterhtml"]))
901 {
902 if ($arUserField["LIST_FILTER_LABEL"])
903 {
904 $arFindFields[$FIELD_NAME] = htmlspecialcharsbx($arUserField["LIST_FILTER_LABEL"]);
905 }
906 else
907 {
908 $arFindFields[$FIELD_NAME] = $arUserField["FIELD_NAME"];
909 }
910 }
911 }
912 }
913 }
914
915 public function AdminListShowFilter($entity_id)
916 {
917 $arUserFields = $this->GetUserFields($entity_id, 0, $GLOBALS["lang"]);
918 foreach ($arUserFields as $FIELD_NAME => $arUserField)
919 {
920 if ($arUserField["SHOW_FILTER"] != "N" && $arUserField["USER_TYPE"]["BASE_TYPE"] != "file")
921 {
922 echo $this->GetFilterHTML($arUserField, "find_" . $FIELD_NAME, $GLOBALS["find_" . $FIELD_NAME]);
923 }
924 }
925 }
926
927 public function ShowScript()
928 {
929 global $APPLICATION;
930
931 $APPLICATION->AddHeadScript("/bitrix/js/main/usertype.js");
932
933 return "";
934 }
935
936 public function GetEditFormHTML($bVarsFromForm, $form_value, $arUserField)
937 {
938 global $APPLICATION;
940
941 if ($arUserField["USER_TYPE"])
942 {
943 if ($this->GetRights($arUserField["ENTITY_ID"]) >= "W")
944 {
945 $selfFolderUrl = $adminPage->getSelfFolderUrl();
946 $userFieldUrl = $selfFolderUrl . "userfield_edit.php?lang=" . LANGUAGE_ID . "&ID=" . $arUserField["ID"];
947 $userFieldUrl = $adminSidePanelHelper->editUrlToPublicPage($userFieldUrl);
948 $edit_link = ($arUserField["HELP_MESSAGE"] ? htmlspecialcharsex($arUserField["HELP_MESSAGE"]) . '<br>' : '') . '<a href="' . htmlspecialcharsbx($userFieldUrl . '&back_url=' . urlencode($APPLICATION->GetCurPageParam("", ["bxpublic"]) . '&tabControl_active_tab=user_fields_tab')) . '">' . htmlspecialcharsex(GetMessage("MAIN_EDIT")) . '</a>';
949 }
950 else
951 {
952 $edit_link = '';
953 }
954
955 $hintHTML = '<span id="hint_' . $arUserField["FIELD_NAME"] . '"></span><script>BX.hint_replace(BX(\'hint_' . $arUserField["FIELD_NAME"] . '\'), \'' . CUtil::JSEscape($edit_link) . '\');</script>&nbsp;';
956
957 if ($arUserField["MANDATORY"] == "Y")
958 {
959 $strLabelHTML = $hintHTML . '<span class="adm-required-field">' . htmlspecialcharsbx($arUserField["EDIT_FORM_LABEL"] ?: $arUserField["FIELD_NAME"]) . '</span>' . ':';
960 }
961 else
962 {
963 $strLabelHTML = $hintHTML . htmlspecialcharsbx($arUserField["EDIT_FORM_LABEL"] ?: $arUserField["FIELD_NAME"]) . ':';
964 }
965
966 if (is_callable([$arUserField["USER_TYPE"]["CLASS_NAME"], "geteditformhtml"]))
967 {
968 $js = $this->ShowScript();
969
970 if (!$bVarsFromForm)
971 {
972 $form_value = $arUserField["VALUE"];
973 }
974 elseif ($arUserField["USER_TYPE"]["BASE_TYPE"] == "file")
975 {
976 $form_value = $GLOBALS[$arUserField["FIELD_NAME"] . "_old_id"];
977 }
978 elseif ($arUserField["EDIT_IN_LIST"] == "N")
979 {
980 $form_value = $arUserField["VALUE"];
981 }
982
983 if (
984 $arUserField["MULTIPLE"] === "N"
985 ||
986 !empty($arUserField['USER_TYPE']['USE_FIELD_COMPONENT'])
987 )
988 {
989 $valign = "";
990 $rowClass = "";
991 $html = call_user_func_array(
992 [$arUserField["USER_TYPE"]["CLASS_NAME"], "geteditformhtml"],
993 [
994 $arUserField,
995 [
996 "NAME" => $arUserField["FIELD_NAME"],
997 "VALUE" => (is_array($form_value) ? $form_value : htmlspecialcharsbx($form_value)),
998 "VALIGN" => &$valign,
999 "ROWCLASS" => &$rowClass,
1000 ],
1001 $bVarsFromForm,
1002 ]
1003 );
1004 return '<tr' . ($rowClass != '' ? ' class="' . $rowClass . '"' : '') . '><td' . ($valign <> 'middle' ? ' class="adm-detail-valign-top"' : '') . ' width="40%">' . $strLabelHTML . '</td><td width="60%">' . $html . '</td></tr>' . $js;
1005 }
1006 elseif (is_callable([$arUserField["USER_TYPE"]["CLASS_NAME"], "geteditformhtmlmulty"]))
1007 {
1008 if (!is_array($form_value))
1009 {
1010 $form_value = [];
1011 }
1012 foreach ($form_value as $key => $value)
1013 {
1014 if (!is_array($value))
1015 {
1016 $form_value[$key] = htmlspecialcharsbx($value);
1017 }
1018 }
1019
1020 $rowClass = "";
1021 $html = call_user_func_array(
1022 [$arUserField["USER_TYPE"]["CLASS_NAME"], "geteditformhtmlmulty"],
1023 [
1024 $arUserField,
1025 [
1026 "NAME" => $arUserField["FIELD_NAME"] . "[]",
1027 "VALUE" => $form_value,
1028 "ROWCLASS" => &$rowClass,
1029 ],
1030 $bVarsFromForm,
1031 ]
1032 );
1033 return '<tr' . ($rowClass != '' ? ' class="' . $rowClass . '"' : '') . '><td class="adm-detail-valign-top">' . $strLabelHTML . '</td><td>' . $html . '</td></tr>' . $js;
1034 }
1035 else
1036 {
1037 if (!is_array($form_value))
1038 {
1039 $form_value = [];
1040 }
1041 $html = "";
1042 $i = -1;
1043 foreach ($form_value as $i => $value)
1044 {
1045 if (
1046 (is_array($value) && (implode("", $value) <> ''))
1047 || ((!is_array($value)) && ((string)$value <> ''))
1048 )
1049 {
1050 $html .= '<tr><td>' . call_user_func_array(
1051 [$arUserField["USER_TYPE"]["CLASS_NAME"], "geteditformhtml"],
1052 [
1053 $arUserField,
1054 [
1055 "NAME" => $arUserField["FIELD_NAME"] . "[" . $i . "]",
1056 "VALUE" => (is_array($value) ? $value : htmlspecialcharsbx($value)),
1057 ],
1058 $bVarsFromForm,
1059 ]
1060 ) . '</td></tr>';
1061 }
1062 }
1063 //Add multiple values support
1064 $rowClass = "";
1065 $FIELD_NAME_X = str_replace('_', 'x', $arUserField["FIELD_NAME"]);
1066 $fieldHtml = call_user_func_array(
1067 [$arUserField["USER_TYPE"]["CLASS_NAME"], "geteditformhtml"],
1068 [
1069 $arUserField,
1070 [
1071 "NAME" => $arUserField["FIELD_NAME"] . "[" . ($i + 1) . "]",
1072 "VALUE" => "",
1073 "ROWCLASS" => &$rowClass,
1074 ],
1075 $bVarsFromForm,
1076 ]
1077 );
1078 return '<tr' . ($rowClass != '' ? ' class="' . $rowClass . '"' : '') . '><td class="adm-detail-valign-top">' . $strLabelHTML . '</td><td>' .
1079 '<table id="table_' . $arUserField["FIELD_NAME"] . '">' . $html . '<tr><td>' . $fieldHtml . '</td></tr>' .
1080 '<tr><td style="padding-top: 6px;"><input type="button" value="' . GetMessage("USER_TYPE_PROP_ADD") . '" onClick="addNewRow(\'table_' . $arUserField["FIELD_NAME"] . '\', \'' . $FIELD_NAME_X . '|' . $arUserField["FIELD_NAME"] . '|' . $arUserField["FIELD_NAME"] . '_old_id\')"></td></tr>' .
1081 "<script>BX.addCustomEvent('onAutoSaveRestore', function(ob, data) {
1082 for (let i in data)
1083 {
1084 if (i.substring(0," . (mb_strlen($arUserField['FIELD_NAME']) + 1) . ")=='" . CUtil::JSEscape($arUserField['FIELD_NAME']) . "[')
1085 {
1086 addNewRow('table_" . $arUserField["FIELD_NAME"] . "', '" . $FIELD_NAME_X . '|' . $arUserField["FIELD_NAME"] . '|' . $arUserField["FIELD_NAME"] . "_old_id');
1087 }
1088 }
1089 })</script>" .
1090 '</table>' .
1091 '</td></tr>' . $js;
1092 }
1093 }
1094 }
1095 return '';
1096 }
1097
1098 public function GetFilterHTML($arUserField, $filter_name, $filter_value)
1099 {
1100 if ($arUserField["USER_TYPE"])
1101 {
1102 if (is_callable([$arUserField["USER_TYPE"]["CLASS_NAME"], "getfilterhtml"]))
1103 {
1104 $useFieldComponent = ($arUserField['USER_TYPE']['USE_FIELD_COMPONENT'] ?? false) === true;
1105 $html = call_user_func_array(
1106 [$arUserField["USER_TYPE"]["CLASS_NAME"], "getfilterhtml"],
1107 [
1108 $arUserField,
1109 [
1110 'NAME' => $filter_name,
1111 'VALUE' => ($useFieldComponent ? $filter_value : htmlspecialcharsEx($filter_value)),
1112 ],
1113 ]
1114 ) . CAdminCalendar::ShowScript();
1115
1116 return '<tr><td>' . htmlspecialcharsbx($arUserField["LIST_FILTER_LABEL"] ?: $arUserField["FIELD_NAME"]) . ':</td><td>' . $html . '</td></tr>';
1117 }
1118 }
1119
1120 return '';
1121 }
1122
1128 public function AddUserField($arUserField, $value, $row)
1129 {
1130 if ($arUserField["USER_TYPE"])
1131 {
1132 $js = $this->ShowScript();
1133 $useFieldComponent = !empty($arUserField['USER_TYPE']['USE_FIELD_COMPONENT']);
1134
1135 if (is_callable([$arUserField["USER_TYPE"]["CLASS_NAME"], "getadminlistviewhtml"]))
1136 {
1137 if ($arUserField["MULTIPLE"] == "N")
1138 {
1139 $html = call_user_func_array(
1140 [$arUserField["USER_TYPE"]["CLASS_NAME"], "getadminlistviewhtml"],
1141 [
1142 $arUserField,
1143 [
1144 "NAME" => "FIELDS[" . $row->id . "][" . $arUserField["FIELD_NAME"] . "]",
1145 "VALUE" => ($useFieldComponent ? $value : htmlspecialcharsbx($value)),
1146 ],
1147 ]
1148 );
1149 if ($html === '')
1150 {
1151 $html = '&nbsp;';
1152 }
1153 $row->AddViewField($arUserField["FIELD_NAME"], $html . $js . CAdminCalendar::ShowScript());
1154 }
1155 elseif (is_callable([$arUserField["USER_TYPE"]["CLASS_NAME"], "getadminlistviewhtmlmulty"]))
1156 {
1157 if (is_array($value))
1158 {
1159 $form_value = $value;
1160 }
1161 else
1162 {
1163 $form_value = unserialize($value, ['allowed_classes' => false]);
1164 }
1165
1166 if (!is_array($form_value))
1167 {
1168 $form_value = [];
1169 }
1170
1171 foreach ($form_value as $key => $val)
1172 {
1173 $form_value[$key] = ($useFieldComponent ? $val : htmlspecialcharsbx($val));
1174 }
1175
1176 $html = call_user_func_array(
1177 [$arUserField["USER_TYPE"]["CLASS_NAME"], "getadminlistviewhtmlmulty"],
1178 [
1179 $arUserField,
1180 [
1181 "NAME" => "FIELDS[" . $row->id . "][" . $arUserField["FIELD_NAME"] . "]" . "[]",
1182 "VALUE" => $form_value,
1183 ],
1184 ]
1185 );
1186 if ($html == '')
1187 {
1188 $html = '&nbsp;';
1189 }
1190 $row->AddViewField($arUserField["FIELD_NAME"], $html . $js . CAdminCalendar::ShowScript());
1191 }
1192 else
1193 {
1194 $html = "";
1195
1196 if (is_array($value))
1197 {
1198 $form_value = $value;
1199 }
1200 else
1201 {
1202 $form_value = $value <> '' ? unserialize($value, ['allowed_classes' => false]) : false;
1203 }
1204
1205 if (!is_array($form_value))
1206 {
1207 $form_value = [];
1208 }
1209
1210 foreach ($form_value as $i => $val)
1211 {
1212 if ($html != "")
1213 {
1214 $html .= " / ";
1215 }
1216 $html .= call_user_func_array(
1217 [$arUserField["USER_TYPE"]["CLASS_NAME"], "getadminlistviewhtml"],
1218 [
1219 $arUserField,
1220 [
1221 "NAME" => "FIELDS[" . $row->id . "][" . $arUserField["FIELD_NAME"] . "]" . "[" . $i . "]",
1222 "VALUE" => ($useFieldComponent ? $val : htmlspecialcharsbx($val)),
1223 ],
1224 ]
1225 );
1226 }
1227 if ($html == '')
1228 {
1229 $html = '&nbsp;';
1230 }
1231 $row->AddViewField($arUserField["FIELD_NAME"], $html . $js . CAdminCalendar::ShowScript());
1232 }
1233 }
1234 if ($arUserField["EDIT_IN_LIST"] == "Y" && is_callable([$arUserField["USER_TYPE"]["CLASS_NAME"], "getadminlistedithtml"]))
1235 {
1236 if (!$row->bEditMode)
1237 {
1238 // put dummy
1239 $row->AddEditField($arUserField["FIELD_NAME"], "&nbsp;");
1240 }
1241 elseif ($arUserField["MULTIPLE"] == "N")
1242 {
1243 $html = call_user_func_array(
1244 [$arUserField["USER_TYPE"]["CLASS_NAME"], "getadminlistedithtml"],
1245 [
1246 $arUserField,
1247 [
1248 "NAME" => "FIELDS[" . $row->id . "][" . $arUserField["FIELD_NAME"] . "]",
1249 "VALUE" => ($useFieldComponent ? $value : htmlspecialcharsbx($value)),
1250 ],
1251 ]
1252 );
1253 if ($html == '')
1254 {
1255 $html = '&nbsp;';
1256 }
1257 $row->AddEditField($arUserField["FIELD_NAME"], $html . $js . CAdminCalendar::ShowScript());
1258 }
1259 elseif (is_callable([$arUserField["USER_TYPE"]["CLASS_NAME"], "getadminlistedithtmlmulty"]))
1260 {
1261 if (is_array($value))
1262 {
1263 $form_value = $value;
1264 }
1265 else
1266 {
1267 $form_value = $value <> '' ? unserialize($value, ['allowed_classes' => false]) : false;
1268 }
1269
1270 if (!is_array($form_value))
1271 {
1272 $form_value = [];
1273 }
1274
1275 foreach ($form_value as $key => $val)
1276 {
1277 $form_value[$key] = ($useFieldComponent ? $val : htmlspecialcharsbx($val));
1278 }
1279
1280 $html = call_user_func_array(
1281 [$arUserField["USER_TYPE"]["CLASS_NAME"], "getadminlistedithtmlmulty"],
1282 [
1283 $arUserField,
1284 [
1285 "NAME" => "FIELDS[" . $row->id . "][" . $arUserField["FIELD_NAME"] . "][]",
1286 "VALUE" => $form_value,
1287 ],
1288 ]
1289 );
1290 if ($html == '')
1291 {
1292 $html = '&nbsp;';
1293 }
1294 $row->AddEditField($arUserField["FIELD_NAME"], $html . $js . CAdminCalendar::ShowScript());
1295 }
1296 else
1297 {
1298 $html = "<table id=\"table_" . $arUserField["FIELD_NAME"] . "_" . $row->id . "\">";
1299 if (is_array($value))
1300 {
1301 $form_value = $value;
1302 }
1303 else
1304 {
1305 $form_value = unserialize($value, ['allowed_classes' => false]);
1306 }
1307
1308 if (!is_array($form_value))
1309 {
1310 $form_value = [];
1311 }
1312
1313 $i = -1;
1314 foreach ($form_value as $i => $val)
1315 {
1316 $html .= '<tr><td>' . call_user_func_array(
1317 [$arUserField["USER_TYPE"]["CLASS_NAME"], "getadminlistedithtml"],
1318 [
1319 $arUserField,
1320 [
1321 "NAME" => "FIELDS[" . $row->id . "][" . $arUserField["FIELD_NAME"] . "]" . "[" . $i . "]",
1322 "VALUE" => ($useFieldComponent ? $val : htmlspecialcharsbx($val)),
1323 ],
1324 ]
1325 ) . '</td></tr>';
1326 }
1327 $html .= '<tr><td>' . call_user_func_array(
1328 [$arUserField["USER_TYPE"]["CLASS_NAME"], "getadminlistedithtml"],
1329 [
1330 $arUserField,
1331 [
1332 "NAME" => "FIELDS[" . $row->id . "][" . $arUserField["FIELD_NAME"] . "]" . "[" . ($i + 1) . "]",
1333 "VALUE" => "",
1334 ],
1335 ]
1336 ) . '</td></tr>';
1337 $html .= '<tr><td><input type="button" value="' . GetMessage("USER_TYPE_PROP_ADD") . '" onClick="addNewRow(\'table_' . $arUserField["FIELD_NAME"] . '_' . $row->id . '\', \'FIELDS\\\\[' . $row->id . '\\\\]\\\\[' . $arUserField["FIELD_NAME"] . '\\\\]\')"></td></tr>' .
1338 '</table>';
1339 $row->AddEditField($arUserField["FIELD_NAME"], $html . $js . CAdminCalendar::ShowScript());
1340 }
1341 }
1342 }
1343 }
1344
1345 public function getListView($userfield, $value)
1346 {
1347 $html = '';
1348
1349 if (is_callable([$userfield["USER_TYPE"]["CLASS_NAME"], "getadminlistviewhtml"]))
1350 {
1351 if ($userfield["MULTIPLE"] == "N")
1352 {
1353 $html = call_user_func_array(
1354 [$userfield["USER_TYPE"]["CLASS_NAME"], "getadminlistviewhtml"],
1355 [
1356 $userfield,
1357 [
1358 "VALUE" => htmlspecialcharsbx($value),
1359 ],
1360 ]
1361 );
1362 }
1363 elseif (is_callable([$userfield["USER_TYPE"]["CLASS_NAME"], "getadminlistviewhtmlmulty"]))
1364 {
1365 $form_value = is_array($value) ? $value : unserialize($value, ['allowed_classes' => false]);
1366
1367 if (!is_array($form_value))
1368 {
1369 $form_value = [];
1370 }
1371
1372 foreach ($form_value as $key => $val)
1373 {
1374 $form_value[$key] = htmlspecialcharsbx($val);
1375 }
1376
1377 $html = call_user_func_array(
1378 [$userfield["USER_TYPE"]["CLASS_NAME"], "getadminlistviewhtmlmulty"],
1379 [
1380 $userfield,
1381 [
1382 "VALUE" => $form_value,
1383 ],
1384 ]
1385 );
1386 }
1387 else
1388 {
1389 if (is_array($value))
1390 {
1391 $form_value = $value;
1392 }
1393 else
1394 {
1395 $form_value = $value <> '' ? unserialize($value, ['allowed_classes' => false]) : false;
1396 }
1397
1398 if (!is_array($form_value))
1399 {
1400 $form_value = [];
1401 }
1402
1403 foreach ($form_value as $val)
1404 {
1405 if ($html != "")
1406 {
1407 $html .= " / ";
1408 }
1409
1410 $html .= call_user_func_array(
1411 [$userfield["USER_TYPE"]["CLASS_NAME"], "getadminlistviewhtml"],
1412 [
1413 $userfield,
1414 [
1415 "VALUE" => htmlspecialcharsbx($val),
1416 ],
1417 ]
1418 );
1419 }
1420 }
1421 }
1422
1423 return $html <> '' ? $html : '&nbsp;';
1424 }
1425
1426 public function CallUserTypeComponent($componentName, $componentTemplate, $arUserField, $arAdditionalParameters = [])
1427 {
1428 global $APPLICATION;
1429 $arParams = $arAdditionalParameters;
1430 $arParams['arUserField'] = $arUserField;
1431 ob_start();
1432 $APPLICATION->IncludeComponent(
1433 $componentName,
1434 $componentTemplate,
1435 $arParams,
1436 null,
1437 ["HIDE_ICONS" => "Y"]
1438 );
1439 return ob_get_clean();
1440 }
1441
1447 public function renderField(array $userField, ?array $additionalParameters = []): ?string
1448 {
1449 $userType = $this->getUserType($userField['USER_TYPE_ID']);
1450 if (!empty($userType['CLASS_NAME']) && is_callable([$userType['CLASS_NAME'], 'renderField']))
1451 {
1452 return call_user_func([$userType['CLASS_NAME'], 'renderField'], $userField, $additionalParameters);
1453 }
1454 return null;
1455 }
1456
1457 public function GetPublicView($arUserField, $arAdditionalParameters = [])
1458 {
1459 $event = new \Bitrix\Main\Event("main", "onBeforeGetPublicView", [&$arUserField, &$arAdditionalParameters]);
1460 $event->send();
1461
1462 $arType = $this->GetUserType($arUserField["USER_TYPE_ID"]);
1463
1464 $html = null;
1465 $event = new \Bitrix\Main\Event("main", "onGetPublicView", [$arUserField, $arAdditionalParameters]);
1466 $event->send();
1467 foreach ($event->getResults() as $evenResult)
1468 {
1469 if ($evenResult->getType() == \Bitrix\Main\EventResult::SUCCESS)
1470 {
1471 $html = $evenResult->getParameters();
1472 break;
1473 }
1474 }
1475
1476 if ($html !== null)
1477 {
1478 //All done
1479 }
1480 elseif (isset($arUserField["VIEW_CALLBACK"]) && is_callable($arUserField['VIEW_CALLBACK']))
1481 {
1482 $html = call_user_func_array($arUserField["VIEW_CALLBACK"], [
1483 $arUserField,
1484 $arAdditionalParameters,
1485 ]);
1486 }
1487 elseif ($arType && isset($arType["VIEW_CALLBACK"]) && is_callable($arType['VIEW_CALLBACK']))
1488 {
1489 $html = call_user_func_array($arType["VIEW_CALLBACK"], [
1490 $arUserField,
1491 $arAdditionalParameters,
1492 ]);
1493 }
1494 elseif (isset($arUserField["VIEW_COMPONENT_NAME"]))
1495 {
1496 $html = $this->CallUserTypeComponent(
1497 $arUserField["VIEW_COMPONENT_NAME"],
1498 $arUserField["VIEW_COMPONENT_TEMPLATE"],
1499 $arUserField,
1500 $arAdditionalParameters
1501 );
1502 }
1503 elseif ($arType && isset($arType["VIEW_COMPONENT_NAME"]))
1504 {
1505 $html = $this->CallUserTypeComponent(
1506 $arType["VIEW_COMPONENT_NAME"],
1507 $arType["VIEW_COMPONENT_TEMPLATE"],
1508 $arUserField,
1509 $arAdditionalParameters
1510 );
1511 }
1512 else
1513 {
1514 $html = $this->CallUserTypeComponent(
1515 "bitrix:system.field.view",
1516 $arUserField["USER_TYPE_ID"],
1517 $arUserField,
1518 $arAdditionalParameters
1519 );
1520 }
1521
1522 $event = new \Bitrix\Main\Event("main", "onAfterGetPublicView", [$arUserField, $arAdditionalParameters, &$html]);
1523 $event->send();
1524
1525 return $html;
1526 }
1527
1528 public function getPublicText($userField)
1529 {
1530 $userType = $this->getUserType($userField['USER_TYPE_ID']);
1531 if (!empty($userType['CLASS_NAME']) && is_callable([$userType['CLASS_NAME'], 'getPublicText']))
1532 {
1533 return call_user_func_array([$userType['CLASS_NAME'], 'getPublicText'], [$userField]);
1534 }
1535
1536 return join(', ', array_map(function ($v) {
1537 return is_null($v) || is_scalar($v) ? (string)$v : '';
1538 }, (array)$userField['VALUE']));
1539 }
1540
1541 public function GetPublicEdit($arUserField, $arAdditionalParameters = [])
1542 {
1543 $event = new \Bitrix\Main\Event("main", "onBeforeGetPublicEdit", [&$arUserField, &$arAdditionalParameters]);
1544 $event->send();
1545
1546 $arType = $this->GetUserType($arUserField["USER_TYPE_ID"]);
1547
1548 $html = null;
1549 $event = new \Bitrix\Main\Event("main", "onGetPublicEdit", [$arUserField, $arAdditionalParameters]);
1550 $event->send();
1551 foreach ($event->getResults() as $evenResult)
1552 {
1553 if ($evenResult->getType() == \Bitrix\Main\EventResult::SUCCESS)
1554 {
1555 $html = $evenResult->getParameters();
1556 break;
1557 }
1558 }
1559
1560 if ($html !== null)
1561 {
1562 //All done
1563 }
1564 elseif (isset($arUserField["EDIT_CALLBACK"]) && is_callable($arUserField['EDIT_CALLBACK']))
1565 {
1566 $html = call_user_func_array($arUserField["EDIT_CALLBACK"], [
1567 $arUserField,
1568 $arAdditionalParameters,
1569 ]);
1570 }
1571 elseif ($arType && isset($arType["EDIT_CALLBACK"]) && is_callable($arType['EDIT_CALLBACK']))
1572 {
1573 $html = call_user_func_array($arType["EDIT_CALLBACK"], [
1574 $arUserField,
1575 $arAdditionalParameters,
1576 ]);
1577 }
1578 elseif (isset($arUserField["EDIT_COMPONENT_NAME"]))
1579 {
1580 $html = $this->CallUserTypeComponent(
1581 $arUserField["EDIT_COMPONENT_NAME"],
1582 $arUserField["EDIT_COMPONENT_TEMPLATE"],
1583 $arUserField,
1584 $arAdditionalParameters
1585 );
1586 }
1587 elseif ($arType && isset($arType["EDIT_COMPONENT_NAME"]))
1588 {
1589 $html = $this->CallUserTypeComponent(
1590 $arType["EDIT_COMPONENT_NAME"],
1591 $arType["EDIT_COMPONENT_TEMPLATE"],
1592 $arUserField,
1593 $arAdditionalParameters
1594 );
1595 }
1596 else
1597 {
1598 $html = $this->CallUserTypeComponent(
1599 "bitrix:system.field.edit",
1600 $arUserField["USER_TYPE_ID"],
1601 $arUserField,
1602 $arAdditionalParameters
1603 );
1604 }
1605
1606 $event = new \Bitrix\Main\Event("main", "onAfterGetPublicEdit", [$arUserField, $arAdditionalParameters, &$html]);
1607 $event->send();
1608
1609 return $html;
1610 }
1611
1612 public function GetSettingsHTML($arUserField, $bVarsFromForm = false)
1613 {
1614 if (!is_array($arUserField)) // New field
1615 {
1616 if ($arType = $this->GetUserType($arUserField))
1617 {
1618 if (is_callable([$arType["CLASS_NAME"], "getsettingshtml"]))
1619 {
1620 return call_user_func_array([$arType["CLASS_NAME"], "getsettingshtml"], [false, ["NAME" => "SETTINGS"], $bVarsFromForm]);
1621 }
1622 }
1623 }
1624 else
1625 {
1626 if (!is_array($arUserField["SETTINGS"]) || empty($arUserField["SETTINGS"]))
1627 {
1628 $arUserField["SETTINGS"] = $this->PrepareSettings(0, $arUserField);
1629 }
1630
1631 if ($arType = $this->GetUserType($arUserField["USER_TYPE_ID"]))
1632 {
1633 if (is_callable([$arType["CLASS_NAME"], "getsettingshtml"]))
1634 {
1635 return call_user_func_array([$arType["CLASS_NAME"], "getsettingshtml"], [$arUserField, ["NAME" => "SETTINGS"], $bVarsFromForm]);
1636 }
1637 }
1638 }
1639 return null;
1640 }
1641
1652 public function CheckFields($entity_id, $ID, $arFields, $user_id = false, $checkRequired = true, array $requiredFields = null, array $filteredFields = null)
1653 {
1654 global $APPLICATION;
1655
1656 $requiredFieldMap = ($requiredFields !== null ? array_fill_keys($requiredFields, true) : null);
1657 $aMsg = [];
1658
1659 //1 Get user typed fields list for entity
1660 $selectFields = null;
1661 if ($ID === null || $ID > 0 || !$checkRequired)
1662 {
1663 // need to select all fields only for a new record and check required
1664 $selectFields = array_keys($arFields);
1665 if ($requiredFields !== null)
1666 {
1667 $selectFields = $selectFields + $requiredFields;
1668 }
1669 if ($filteredFields !== null)
1670 {
1671 $selectFields = array_diff($selectFields, $filteredFields);
1672 }
1673 }
1674 $arUserFields = $this->GetUserFields($entity_id, $ID, LANGUAGE_ID, false, $selectFields);
1675
1676 //2 Filter user typed fields
1677 if ($filteredFields !== null && $selectFields === null)
1678 {
1679 $arUserFields = array_filter(
1680 $arUserFields,
1681 static function ($fieldName) use ($filteredFields) {
1682 return in_array($fieldName, $filteredFields);
1683 },
1684 ARRAY_FILTER_USE_KEY
1685 );
1686 }
1687
1688 //3 For each field
1689 foreach ($arUserFields as $FIELD_NAME => $arUserField)
1690 {
1691 $enableRequiredFieldCheck = $arUserField["MANDATORY"] === "Y"
1692 ? $checkRequired : ($requiredFieldMap && isset($requiredFieldMap[$FIELD_NAME]));
1693
1694 //common Check for all fields
1695 $isSingleValue = ($arUserField["MULTIPLE"] === "N");
1696
1697 if (
1698 $enableRequiredFieldCheck
1699 && (
1700 ($ID !== null && $ID <= 0)
1701 || array_key_exists($FIELD_NAME, $arFields)
1702 )
1703 )
1704 {
1705 $EDIT_FORM_LABEL = $arUserField["EDIT_FORM_LABEL"] <> '' ? $arUserField["EDIT_FORM_LABEL"] : $arUserField["FIELD_NAME"];
1706
1707 if ($arUserField["USER_TYPE"]["BASE_TYPE"] === "file")
1708 {
1709 $isNewFilePresent = false;
1710 $files = [];
1711 if (is_array($arUserField["VALUE"]))
1712 {
1713 $files = array_flip($arUserField["VALUE"]);
1714 }
1715 elseif ($arUserField["VALUE"] > 0)
1716 {
1717 $files = [$arUserField["VALUE"] => 0];
1718 }
1719 elseif (is_numeric($arFields[$FIELD_NAME]))
1720 {
1721 if (!$this->isFileValueDeleted($arUserField, (int)$arFields[$FIELD_NAME]))
1722 {
1723 $files = [$arFields[$FIELD_NAME] => 0];
1724 }
1725 }
1726
1727 if ($isSingleValue)
1728 {
1729 $value = $arFields[$FIELD_NAME];
1730 if (is_array($value) && array_key_exists("tmp_name", $value))
1731 {
1732 if (array_key_exists("del", $value) && $value["del"])
1733 {
1734 unset($files[$value["old_id"]]);
1735 }
1736 elseif (array_key_exists("size", $value) && $value["size"] > 0)
1737 {
1738 $isNewFilePresent = true;
1739 }
1740 }
1741 elseif ($value > 0)
1742 {
1743 if (!$this->isFileValueDeleted($arUserField, (int)$value))
1744 {
1745 $isNewFilePresent = true;
1746 $files[$value] = $value;
1747 }
1748 }
1749 }
1750 else
1751 {
1752 if (is_array($arFields[$FIELD_NAME]))
1753 {
1754 foreach ($arFields[$FIELD_NAME] as $value)
1755 {
1756 if (is_array($value) && array_key_exists("tmp_name", $value))
1757 {
1758 if (array_key_exists("del", $value) && $value["del"])
1759 {
1760 unset($files[$value["old_id"]]);
1761 }
1762 elseif (array_key_exists("size", $value) && $value["size"] > 0)
1763 {
1764 $isNewFilePresent = true;
1765 }
1766 }
1767 elseif ($value > 0)
1768 {
1769 if (!$this->isFileValueDeleted($arUserField, (int)$value))
1770 {
1771 $isNewFilePresent = true;
1772 $files[$value] = $value;
1773 }
1774 }
1775 }
1776 }
1777 }
1778
1779 if (!$isNewFilePresent && empty($files))
1780 {
1781 $aMsg[] = ["id" => $FIELD_NAME, "text" => str_replace("#FIELD_NAME#", $EDIT_FORM_LABEL, GetMessage("USER_TYPE_FIELD_VALUE_IS_MISSING"))];
1782 }
1783 }
1784 elseif ($isSingleValue)
1785 {
1786 if ($this->isValueEmpty($arUserField, $arFields[$FIELD_NAME]))
1787 {
1788 $aMsg[] = ["id" => $FIELD_NAME, "text" => str_replace("#FIELD_NAME#", $EDIT_FORM_LABEL, GetMessage("USER_TYPE_FIELD_VALUE_IS_MISSING"))];
1789 }
1790 }
1791 else
1792 {
1793 if (!is_array($arFields[$FIELD_NAME]))
1794 {
1795 $aMsg[] = ["id" => $FIELD_NAME, "text" => str_replace("#FIELD_NAME#", $EDIT_FORM_LABEL, GetMessage("USER_TYPE_FIELD_VALUE_IS_MISSING"))];
1796 }
1797 else
1798 {
1799 $bFound = false;
1800 foreach ($arFields[$FIELD_NAME] as $value)
1801 {
1802 if (
1803 (
1804 is_array($value)
1805 && (implode("", $value) <> '')
1806 )
1807 ||
1808 (
1809 !is_array($value)
1810 && !$this->isValueEmpty($arUserField, $value)
1811 )
1812 )
1813 {
1814 $bFound = true;
1815 break;
1816 }
1817 }
1818 if (!$bFound)
1819 {
1820 $aMsg[] = ["id" => $FIELD_NAME, "text" => str_replace("#FIELD_NAME#", $EDIT_FORM_LABEL, GetMessage("USER_TYPE_FIELD_VALUE_IS_MISSING"))];
1821 }
1822 }
1823 }
1824 }
1825 //identify user type
1826 if ($arUserField["USER_TYPE"])
1827 {
1828 $CLASS_NAME = $arUserField["USER_TYPE"]["CLASS_NAME"];
1829 if (array_key_exists($FIELD_NAME, $arFields) && is_callable([$CLASS_NAME, "checkfields"]))
1830 {
1831 if ($isSingleValue)
1832 {
1833 if (!($arFields[$FIELD_NAME] instanceof SqlExpression))
1834 {
1835 $canUseArrayValueForSingleField = false;
1836 if (
1837 is_callable([$CLASS_NAME, 'canUseArrayValueForSingleField'])
1838 && $CLASS_NAME::canUseArrayValueForSingleField()
1839 )
1840 {
1841 $canUseArrayValueForSingleField = true;
1842 }
1843
1844 if (is_array($arFields[$FIELD_NAME]) && !$canUseArrayValueForSingleField)
1845 {
1846 $fieldName = HtmlFilter::encode(
1847 empty($arUserField['EDIT_FORM_LABEL'])
1848 ? $arUserField['FIELD_NAME']
1849 : $arUserField['EDIT_FORM_LABEL']
1850 );
1851 $messages = [
1852 [
1853 'id' => $arUserField['FIELD_NAME'],
1854 'text' => Loc::getMessage('USER_TYPE_FIELD_VALUE_IS_MULTIPLE', [
1855 '#FIELD_NAME#' => $fieldName,
1856 ]),
1857 ],
1858 ];
1859 }
1860 else
1861 {
1862 //apply appropriate check function
1863 $messages = call_user_func_array(
1864 [
1865 $CLASS_NAME,
1866 'checkfields',
1867 ],
1868 [
1869 $arUserField,
1870 $arFields[$FIELD_NAME],
1871 $user_id,
1872 ]
1873 );
1874 }
1875 $aMsg = array_merge($aMsg, $messages);
1876 }
1877 }
1878 elseif (is_array($arFields[$FIELD_NAME]))
1879 {
1880 foreach ($arFields[$FIELD_NAME] as $value)
1881 {
1882 if (!empty($value))
1883 {
1884 if ($value instanceof SqlExpression)
1885 {
1886 $aMsg[] = [
1887 'id' => $FIELD_NAME,
1888 'text' => "Multiple field \"#FIELD_NAME#\" can't handle SqlExpression because of serialized uts cache",
1889 ];
1890 }
1891 else
1892 {
1893 //apply appropriate check function
1894 $ar = call_user_func_array(
1895 [$CLASS_NAME, "checkfields"],
1896 [$arUserField, $value, $user_id]
1897 );
1898 $aMsg = array_merge($aMsg, $ar);
1899 }
1900 }
1901 }
1902 }
1903 }
1904 }
1905 }
1906
1907 //3 Return succsess/fail flag
1908 if (!empty($aMsg))
1909 {
1910 $e = new CAdminException($aMsg);
1911 $APPLICATION->ThrowException($e);
1912 return false;
1913 }
1914 return true;
1915 }
1916
1926 public function CheckFieldsWithOldData($entity_id, $oldData, $arFields)
1927 {
1928 global $APPLICATION;
1929
1930 $aMsg = [];
1931
1932 //1 Get user typed fields list for entity
1933 $arUserFields = $this->getUserFieldsWithReadyData($entity_id, $oldData, LANGUAGE_ID);
1934
1935 //2 For each field
1936 foreach ($arUserFields as $FIELD_NAME => $arUserField)
1937 {
1938 //identify user type
1939 if ($arUserField["USER_TYPE"])
1940 {
1941 $CLASS_NAME = $arUserField["USER_TYPE"]["CLASS_NAME"];
1942 $EDIT_FORM_LABEL = $arUserField["EDIT_FORM_LABEL"] <> '' ? $arUserField["EDIT_FORM_LABEL"] : $arUserField["FIELD_NAME"];
1943
1944 if (array_key_exists($FIELD_NAME, $arFields) && is_callable([$CLASS_NAME, "checkfields"]))
1945 {
1946 // check required values
1947 if ($arUserField["MANDATORY"] === "Y")
1948 {
1949 if ($arUserField["USER_TYPE"]["BASE_TYPE"] === "file")
1950 {
1951 $isNewFilePresent = false;
1952 $files = [];
1953 if (is_array($arUserField["VALUE"]))
1954 {
1955 $files = array_flip($arUserField["VALUE"]);
1956 }
1957 elseif ($arUserField["VALUE"] > 0)
1958 {
1959 $files = [$arUserField["VALUE"] => 0];
1960 }
1961 elseif (is_numeric($arFields[$FIELD_NAME]))
1962 {
1963 $files = [$arFields[$FIELD_NAME] => 0];
1964 }
1965
1966 if ($arUserField["MULTIPLE"] === "N")
1967 {
1968 $value = $arFields[$FIELD_NAME];
1969 if (is_array($value) && array_key_exists("tmp_name", $value))
1970 {
1971 if (array_key_exists("del", $value) && $value["del"])
1972 {
1973 unset($files[$value["old_id"]]);
1974 }
1975 elseif (array_key_exists("size", $value) && $value["size"] > 0)
1976 {
1977 $isNewFilePresent = true;
1978 }
1979 }
1980 elseif ($value > 0)
1981 {
1982 $isNewFilePresent = true;
1983 $files[$value] = $value;
1984 }
1985 }
1986 else
1987 {
1988 if (is_array($arFields[$FIELD_NAME]))
1989 {
1990 foreach ($arFields[$FIELD_NAME] as $value)
1991 {
1992 if (is_array($value) && array_key_exists("tmp_name", $value))
1993 {
1994 if (array_key_exists("del", $value) && $value["del"])
1995 {
1996 unset($files[$value["old_id"]]);
1997 }
1998 elseif (array_key_exists("size", $value) && $value["size"] > 0)
1999 {
2000 $isNewFilePresent = true;
2001 }
2002 }
2003 elseif ($value > 0)
2004 {
2005 $isNewFilePresent = true;
2006 $files[$value] = $value;
2007 }
2008 }
2009 }
2010 }
2011
2012 if (!$isNewFilePresent && empty($files))
2013 {
2014 $aMsg[] = ["id" => $FIELD_NAME, "text" => str_replace("#FIELD_NAME#", $EDIT_FORM_LABEL, GetMessage("USER_TYPE_FIELD_VALUE_IS_MISSING"))];
2015 }
2016 }
2017 elseif ($arUserField["MULTIPLE"] == "N")
2018 {
2019 if ($this->isValueEmpty($arUserField, $arFields[$FIELD_NAME]))
2020 {
2021 $aMsg[] = ["id" => $FIELD_NAME, "text" => str_replace("#FIELD_NAME#", $EDIT_FORM_LABEL, GetMessage("USER_TYPE_FIELD_VALUE_IS_MISSING"))];
2022 }
2023 }
2024 else
2025 {
2026 if (!is_array($arFields[$FIELD_NAME]))
2027 {
2028 $aMsg[] = ["id" => $FIELD_NAME, "text" => str_replace("#FIELD_NAME#", $EDIT_FORM_LABEL, GetMessage("USER_TYPE_FIELD_VALUE_IS_MISSING"))];
2029 }
2030 else
2031 {
2032 $bFound = false;
2033 foreach ($arFields[$FIELD_NAME] as $value)
2034 {
2035 if (
2036 (is_array($value) && (implode("", $value) <> ''))
2037 || ((!is_array($value)) && ((string)$value <> ''))
2038 )
2039 {
2040 $bFound = true;
2041 break;
2042 }
2043 }
2044 if (!$bFound)
2045 {
2046 $aMsg[] = ["id" => $FIELD_NAME, "text" => str_replace("#FIELD_NAME#", $EDIT_FORM_LABEL, GetMessage("USER_TYPE_FIELD_VALUE_IS_MISSING"))];
2047 }
2048 }
2049 }
2050 }
2051
2052 // check regular values
2053 if ($arUserField["MULTIPLE"] == "N")
2054 {
2055 //apply appropriate check function
2056 $ar = call_user_func_array(
2057 [$CLASS_NAME, "checkfields"],
2058 [$arUserField, $arFields[$FIELD_NAME]]
2059 );
2060 $aMsg = array_merge($aMsg, $ar);
2061 }
2062 elseif (is_array($arFields[$FIELD_NAME]))
2063 {
2064 foreach ($arFields[$FIELD_NAME] as $value)
2065 {
2066 if (!empty($value))
2067 {
2068 //apply appropriate check function
2069 $ar = call_user_func_array(
2070 [$CLASS_NAME, "checkfields"],
2071 [$arUserField, $value]
2072 );
2073 $aMsg = array_merge($aMsg, $ar);
2074 }
2075 }
2076 }
2077 }
2078 }
2079 }
2080
2081 //3 Return succsess/fail flag
2082 if (!empty($aMsg))
2083 {
2084 $e = new CAdminException($aMsg);
2085 $APPLICATION->ThrowException($e);
2086 return false;
2087 }
2088
2089 return true;
2090 }
2091
2092 protected function isValueEmpty(array $userField, $value): bool
2093 {
2094 $className = $userField['USER_TYPE']['CLASS_NAME'] ?? null;
2095 if (!is_a($className, BaseType::class, true))
2096 {
2097 $className = BaseType::class;
2098 }
2099 if (!$className::isMandatorySupported())
2100 {
2101 return false;
2102 }
2103 $isNumberType = (
2104 $userField['USER_TYPE_ID'] === \Bitrix\Main\UserField\Types\IntegerType::USER_TYPE_ID
2105 || $userField['USER_TYPE_ID'] === \Bitrix\Main\UserField\Types\DoubleType::USER_TYPE_ID
2106 );
2107 if (
2108 $isNumberType
2109 && (
2110 $value === 0 || $value === 0.0 || $value === "0" || $value === "0.0" || $value === "0,0"
2111 )
2112 )
2113 {
2114 return false;
2115 }
2116
2117 return (string)$value === "";
2118 }
2119
2120 public function Update($entity_id, $ID, $arFields, $user_id = false)
2121 {
2122 $entity_id = static::normalizeId($entity_id);
2123 $ID = (int)$ID;
2124
2125 $result = $this->updateUserFieldValuesByEvent($entity_id, $ID, $arFields);
2126 if ($result !== null)
2127 {
2128 return $result;
2129 }
2130
2131 $arUpdate = [];
2132 $arInsert = [];
2133 $arInsertType = [];
2134 $arDelete = [];
2135
2136 $arUserFields = $this->GetUserFields($entity_id, $ID, false, $user_id, array_keys($arFields));
2137
2138 foreach ($arUserFields as $FIELD_NAME => $arUserField)
2139 {
2140 if (array_key_exists($FIELD_NAME, $arFields))
2141 {
2142 $arUserField['VALUE_ID'] = $ID;
2143
2144 if ($arUserField["MULTIPLE"] == "N")
2145 {
2146 if (is_callable([$arUserField["USER_TYPE"]["CLASS_NAME"], "onbeforesave"]))
2147 {
2148 $arFields[$FIELD_NAME] = call_user_func_array([$arUserField["USER_TYPE"]["CLASS_NAME"], "onbeforesave"], [$arUserField, $arFields[$FIELD_NAME], $user_id]);
2149 }
2150
2151 $modified = (!array_key_exists('VALUE_RAW', $arUserField) || $arFields[$FIELD_NAME] !== $arUserField['VALUE_RAW']);
2152 if ($modified)
2153 {
2154 if ((string)$arFields[$FIELD_NAME] !== '')
2155 {
2156 $arUpdate[$FIELD_NAME] = $arFields[$FIELD_NAME];
2157 }
2158 elseif (!empty($arUserField['VALUE_EXISTS']))
2159 {
2160 $arUpdate[$FIELD_NAME] = null;
2161 }
2162 }
2163 }
2164 elseif (is_array($arFields[$FIELD_NAME]))
2165 {
2166 $arInsert[$arUserField["ID"]] = [];
2167 $arInsertType[$arUserField["ID"]] = $arUserField["USER_TYPE"];
2168 $arInsertType[$arUserField['ID']]['FIELD_NAME'] = $arUserField['FIELD_NAME'];
2169
2170 if (is_callable([$arUserField["USER_TYPE"]["CLASS_NAME"], "onbeforesaveall"]))
2171 {
2172 $arInsert[$arUserField["ID"]] = call_user_func_array([$arUserField["USER_TYPE"]["CLASS_NAME"], "onbeforesaveall"], [$arUserField, $arFields[$FIELD_NAME], $user_id]);
2173 }
2174 else
2175 {
2176 foreach ($arFields[$FIELD_NAME] as $value)
2177 {
2178 if (is_callable([$arUserField["USER_TYPE"]["CLASS_NAME"], "onbeforesave"]))
2179 {
2180 $value = call_user_func_array([$arUserField["USER_TYPE"]["CLASS_NAME"], "onbeforesave"], [$arUserField, $value, $user_id]);
2181 }
2182
2183 if ((string)$value <> '')
2184 {
2185 switch ($arInsertType[$arUserField["ID"]]["BASE_TYPE"])
2186 {
2187 case "int":
2188 case "file":
2189 case "enum":
2190 $value = intval($value);
2191 break;
2192 case "double":
2193 $value = doubleval($value);
2194 if (!is_finite($value))
2195 {
2196 $value = 0;
2197 }
2198 break;
2199 case "string":
2200 $value = (string)$value;
2201 break;
2202 }
2203 $arInsert[$arUserField["ID"]][] = $value;
2204 }
2205 }
2206 }
2207
2208 if ($arUserField['USER_TYPE_ID'] == 'datetime')
2209 {
2210 $serialized = \Bitrix\Main\UserFieldTable::serializeMultipleDatetime($arInsert[$arUserField["ID"]]);
2211 }
2212 elseif ($arUserField['USER_TYPE_ID'] == 'date')
2213 {
2214 $serialized = \Bitrix\Main\UserFieldTable::serializeMultipleDate($arInsert[$arUserField["ID"]]);
2215 }
2216 else
2217 {
2218 $serialized = serialize($arInsert[$arUserField["ID"]]);
2219 }
2220
2221 $modified = (!array_key_exists('VALUE_RAW', $arUserField) || $serialized !== $arUserField['VALUE_RAW']);
2222 if ($modified)
2223 {
2224 $arUpdate[$FIELD_NAME] = $serialized;
2225
2226 if (!empty($arUserField['VALUE_EXISTS']))
2227 {
2228 $arDelete[$arUserField["ID"]] = true;
2229 }
2230 }
2231 else
2232 {
2233 $arInsert[$arUserField["ID"]] = [];
2234 }
2235 }
2236 }
2237 }
2238
2239 $lower_entity_id = strtolower($entity_id);
2240
2241 $connection = Application::getConnection();
2242 $helper = $connection->getSqlHelper();
2243
2244 if (!empty($arUpdate))
2245 {
2246 $insertFields = $arUpdate;
2247 $insertFields['VALUE_ID'] = $ID;
2248 $strUpdate = $helper->prepareMerge("b_uts_" . $lower_entity_id, ['VALUE_ID'], $insertFields, $arUpdate)[0];
2249 }
2250 else
2251 {
2252 // nothing to insert/update
2253 return true;
2254 }
2255
2256 $connection->startTransaction();
2257
2258 $connection->query($strUpdate);
2259
2260 foreach ($arDelete as $key => $value)
2261 {
2262 $connection->query("DELETE from b_utm_" . $lower_entity_id . " WHERE FIELD_ID = " . intval($key) . " AND VALUE_ID = " . $ID);
2263 }
2264
2265 foreach ($arInsert as $FieldId => $arField)
2266 {
2267 switch ($arInsertType[$FieldId]["BASE_TYPE"])
2268 {
2269 case "int":
2270 case "file":
2271 case "enum":
2272 $COLUMN = "VALUE_INT";
2273 break;
2274 case "double":
2275 $COLUMN = "VALUE_DOUBLE";
2276 break;
2277 case "datetime":
2278 $COLUMN = "VALUE_DATE";
2279 break;
2280 default:
2281 $COLUMN = "VALUE";
2282 }
2283 foreach ($arField as $value)
2284 {
2285 if ($value instanceof \Bitrix\Main\Type\Date)
2286 {
2287 // little hack to avoid timezone vs 00:00:00 ambiguity. for utm only
2288 $value = new \Bitrix\Main\Type\DateTime($value->format('Y-m-d H:i:s'), 'Y-m-d H:i:s');
2289 }
2290
2291 switch ($arInsertType[$FieldId]["BASE_TYPE"])
2292 {
2293 case "int":
2294 case "file":
2295 case "enum":
2296 case "double":
2297 break;
2298 case "datetime":
2299 $userFieldName = $arInsertType[$FieldId]['FIELD_NAME'];
2300 $value = DateTimeType::charToDate($arUserFields[$userFieldName], $value);
2301 break;
2302 default:
2303 $value = "'" . $helper->forSql($value) . "'";
2304 }
2305 $connection->query("INSERT INTO b_utm_" . $lower_entity_id . " (VALUE_ID, FIELD_ID, " . $COLUMN . ")
2306 VALUES (" . intval($ID) . ", '" . $FieldId . "', " . $value . ")");
2307 }
2308 }
2309
2310 $connection->commitTransaction();
2311
2312 return true;
2313 }
2314
2315 public function copy($entity_id, $id, $copiedId, $entityObject, $userId = false, $ignoreList = [])
2316 {
2317 $userFields = $this->getUserFields($entity_id, $id);
2318
2319 $fields = [];
2320 foreach ($userFields as $fieldName => $userField)
2321 {
2322 if (!in_array($fieldName, $ignoreList))
2323 {
2324 if (is_callable([$userField["USER_TYPE"]["CLASS_NAME"], "onBeforeCopy"]))
2325 {
2326 $fields[$fieldName] = call_user_func_array(
2327 [$userField["USER_TYPE"]["CLASS_NAME"], "onBeforeCopy"],
2328 [$userField, $copiedId, $userField["VALUE"], $entityObject, $userId]
2329 );
2330 }
2331 else
2332 {
2333 $fields[$fieldName] = $userField["VALUE"];
2334 }
2335 }
2336 }
2337
2338 $this->update($entity_id, $copiedId, $fields, $userId);
2339
2340 foreach ($userFields as $fieldName => $userField)
2341 {
2342 if (!in_array($fieldName, $ignoreList))
2343 {
2344 if (is_callable([$userField["USER_TYPE"]["CLASS_NAME"], "onAfterCopy"]))
2345 {
2346 $fields[$fieldName] = call_user_func_array(
2347 [$userField["USER_TYPE"]["CLASS_NAME"], "onAfterCopy"],
2348 [$userField, $copiedId, $fields[$fieldName], $entityObject, $userId]
2349 );
2350 }
2351 }
2352 }
2353 }
2354
2355 public function Delete($entity_id, $ID)
2356 {
2357 global $DB;
2358
2359 $ID = (int)$ID;
2360
2361 $result = $this->deleteUserFieldValuesByEvent($entity_id, $ID);
2362 if ($result !== null)
2363 {
2364 return;
2365 }
2366
2367 if ($arUserFields = $this->GetUserFields($entity_id, $ID, false, 0))
2368 {
2369 foreach ($arUserFields as $arUserField)
2370 {
2371 if (is_array($arUserField["VALUE"]))
2372 {
2373 foreach ($arUserField["VALUE"] as $value)
2374 {
2375 if (is_callable([$arUserField["USER_TYPE"]["CLASS_NAME"], "ondelete"]))
2376 {
2377 call_user_func_array([$arUserField["USER_TYPE"]["CLASS_NAME"], "ondelete"], [$arUserField, $value]);
2378 }
2379
2380 if ($arUserField["USER_TYPE"]["BASE_TYPE"] == "file")
2381 {
2382 CFile::Delete($value);
2383 }
2384 }
2385 }
2386 else
2387 {
2388 if (is_callable([$arUserField["USER_TYPE"]["CLASS_NAME"], "ondelete"]))
2389 {
2390 call_user_func_array([$arUserField["USER_TYPE"]["CLASS_NAME"], "ondelete"], [$arUserField, $arUserField["VALUE"]]);
2391 }
2392
2393 if ($arUserField["USER_TYPE"]["BASE_TYPE"] == "file")
2394 {
2395 CFile::Delete($arUserField["VALUE"]);
2396 }
2397 }
2398 }
2399 $DB->Query("DELETE FROM b_utm_" . strtolower($entity_id) . " WHERE VALUE_ID = " . $ID);
2400 $DB->Query("DELETE FROM b_uts_" . strtolower($entity_id) . " WHERE VALUE_ID = " . $ID);
2401 }
2402 }
2403
2404 public function OnSearchIndex($entity_id, $ID)
2405 {
2406 $result = "";
2407 if ($arUserFields = $this->GetUserFields($entity_id, $ID, false, 0))
2408 {
2409 foreach ($arUserFields as $arUserField)
2410 {
2411 if ($arUserField["IS_SEARCHABLE"] == "Y")
2412 {
2413 if ($arUserField["USER_TYPE"])
2414 {
2415 if (is_callable([$arUserField["USER_TYPE"]["CLASS_NAME"], "onsearchindex"]))
2416 {
2417 $result .= "\r\n" . call_user_func_array([$arUserField["USER_TYPE"]["CLASS_NAME"], "onsearchindex"], [$arUserField]);
2418 }
2419 }
2420 }
2421 }
2422 }
2423 return $result;
2424 }
2425
2426 public function GetRights($ENTITY_ID = false, $ID = false)
2427 {
2428 if (($ID !== false) && array_key_exists("ID:" . $ID, $this->arRightsCache))
2429 {
2430 return $this->arRightsCache["ID:" . $ID];
2431 }
2432 if (($ENTITY_ID !== false) && array_key_exists("ENTITY_ID:" . $ENTITY_ID, $this->arRightsCache))
2433 {
2434 return $this->arRightsCache["ENTITY_ID:" . $ENTITY_ID];
2435 }
2436
2437 global $USER;
2438 if (is_object($USER) && $USER->CanDoOperation('edit_other_settings'))
2439 {
2440 $RIGHTS = "X";
2441 }
2442 else
2443 {
2444 $RIGHTS = "D";
2445 if ($ID !== false)
2446 {
2447 $ar = CUserTypeEntity::GetByID($ID);
2448 if ($ar)
2449 {
2450 $ENTITY_ID = $ar["ENTITY_ID"];
2451 }
2452 }
2453
2454 foreach (GetModuleEvents("main", "OnUserTypeRightsCheck", true) as $arEvent)
2455 {
2456 $res = ExecuteModuleEventEx($arEvent, [$ENTITY_ID]);
2457 if ($res > $RIGHTS)
2458 {
2459 $RIGHTS = $res;
2460 }
2461 }
2462 }
2463
2464 if ($ID !== false)
2465 {
2466 $this->arRightsCache["ID:" . $ID] = $RIGHTS;
2467 }
2468 if ($ENTITY_ID !== false)
2469 {
2470 $this->arRightsCache["ENTITY_ID:" . $ENTITY_ID] = $RIGHTS;
2471 }
2472
2473 return $RIGHTS;
2474 }
2475
2484 public function getEntityField($arUserField, $fieldName = null, $fieldParameters = [])
2485 {
2486 if (empty($fieldName))
2487 {
2488 $fieldName = $arUserField['FIELD_NAME'];
2489 }
2490
2491 if (is_callable([$arUserField['USER_TYPE']['CLASS_NAME'], 'getEntityField']))
2492 {
2493 $field = call_user_func([$arUserField['USER_TYPE']['CLASS_NAME'], 'getEntityField'], $fieldName, $fieldParameters);
2494 }
2495 elseif ($arUserField['USER_TYPE']['USER_TYPE_ID'] == 'date')
2496 {
2497 $field = new Fields\DateField($fieldName, $fieldParameters);
2498 }
2499 else
2500 {
2501 switch ($arUserField['USER_TYPE']['BASE_TYPE'])
2502 {
2503 case 'int':
2504 case 'enum':
2505 case 'file':
2506 $field = (new Fields\IntegerField($fieldName, $fieldParameters))
2507 ->configureNullable()
2508 ;
2509 break;
2510 case 'double':
2511 $field = (new Fields\FloatField($fieldName, $fieldParameters))
2512 ->configureNullable()
2513 ;
2514 break;
2515 case 'string':
2516 $field = (new Fields\StringField($fieldName, $fieldParameters))
2517 ->configureNullable()
2518 ;
2519 break;
2520 case 'datetime':
2521 $field = (new Fields\DatetimeField($fieldName, $fieldParameters))
2522 ->configureNullable()
2523 ->configureUseTimezone(isset($arUserField['SETTINGS']['USE_TIMEZONE']) && $arUserField['SETTINGS']['USE_TIMEZONE'] == 'Y')
2524 ;
2525 break;
2526 default:
2527 throw new \Bitrix\Main\ArgumentException(sprintf(
2528 'Unknown userfield base type `%s`', $arUserField["USER_TYPE"]['BASE_TYPE']
2529 ));
2530 }
2531 }
2532
2533 $ufHandlerClass = $arUserField['USER_TYPE']['CLASS_NAME'];
2534
2535 if (is_subclass_of($ufHandlerClass, BaseType::class))
2536 {
2537 $defaultValue = $ufHandlerClass::getDefaultValue($arUserField);
2538 $field->configureDefaultValue($defaultValue);
2539 }
2540
2541 return $field;
2542 }
2543
2550 public function getEntityReferences($arUserField, Fields\ScalarField $entityField)
2551 {
2552 if (is_callable([$arUserField['USER_TYPE']['CLASS_NAME'], 'getEntityReferences']))
2553 {
2554 return call_user_func([$arUserField['USER_TYPE']['CLASS_NAME'], 'getEntityReferences'], $arUserField, $entityField);
2555 }
2556
2557 return [];
2558 }
2559
2560 protected function getUserFieldValuesByEvent(array $userFields, string $entityId, int $value): ?array
2561 {
2562 $result = [];
2563 if ($value === 0)
2564 {
2565 return null;
2566 }
2567 $isGotByEvent = false;
2568 $event = new \Bitrix\Main\Event('main', 'onGetUserFieldValues', ['userFields' => $userFields, 'entityId' => $entityId, 'value' => $value]);
2569 $event->send();
2570 foreach ($event->getResults() as $eventResult)
2571 {
2572 if ($eventResult->getType() === \Bitrix\Main\EventResult::SUCCESS)
2573 {
2574 $parameters = $eventResult->getParameters();
2575 if (isset($parameters['values']) && is_array($parameters['values']))
2576 {
2577 $isGotByEvent = true;
2578 foreach ($userFields as $fieldName => $userField)
2579 {
2580 if (isset($parameters['values'][$fieldName]))
2581 {
2582 $result[$fieldName] = $parameters['values'][$fieldName];
2583 }
2584 }
2585 }
2586 }
2587 }
2588 if ($isGotByEvent)
2589 {
2590 return $result;
2591 }
2592
2593 return null;
2594 }
2595
2596 protected function updateUserFieldValuesByEvent(string $entityId, int $id, array $fields): ?bool
2597 {
2598 $result = null;
2599
2600 $event = new \Bitrix\Main\Event('main', 'onUpdateUserFieldValues', ['entityId' => $entityId, 'id' => $id, 'fields' => $fields]);
2601 $event->send();
2602 foreach ($event->getResults() as $eventResult)
2603 {
2604 if ($eventResult->getType() === \Bitrix\Main\EventResult::SUCCESS)
2605 {
2606 $result = true;
2607 }
2608 elseif ($eventResult->getType() === \Bitrix\Main\EventResult::ERROR)
2609 {
2610 $result = false;
2611 }
2612 }
2613
2614 return $result;
2615 }
2616
2617 protected function deleteUserFieldValuesByEvent(string $entityId, int $id): ?bool
2618 {
2619 $result = null;
2620
2621 $event = new \Bitrix\Main\Event('main', 'onDeleteUserFieldValues', ['entityId' => $entityId, 'id' => $id]);
2622 $event->send();
2623 foreach ($event->getResults() as $eventResult)
2624 {
2625 if ($eventResult->getType() === \Bitrix\Main\EventResult::SUCCESS)
2626 {
2627 $result = true;
2628 }
2629 elseif ($eventResult->getType() === \Bitrix\Main\EventResult::ERROR)
2630 {
2631 $result = false;
2632 }
2633 }
2634
2635 return $result;
2636 }
2637
2638 protected function getEntities($entity_id, $LANG, $user_id)
2639 {
2640 $cacheId = $entity_id . "." . $LANG . '.' . (int)$user_id;
2641
2642 $result = [];
2643 if (!array_key_exists($cacheId, $this->arFieldsCache))
2644 {
2645 $arFilter = ["ENTITY_ID" => $entity_id];
2646 if ($LANG)
2647 {
2648 $arFilter["LANG"] = $LANG;
2649 }
2650 $rs = CUserTypeEntity::GetList([], $arFilter);
2651 while ($arUserField = $rs->Fetch())
2652 {
2653 if ($arType = $this->GetUserType($arUserField["USER_TYPE_ID"]))
2654 {
2655 if ($user_id !== 0 && is_callable([$arType["CLASS_NAME"], "checkpermission"]))
2656 {
2657 if (!call_user_func_array([$arType["CLASS_NAME"], "checkpermission"], [$arUserField, $user_id]))
2658 {
2659 continue;
2660 }
2661 }
2662 $arUserField["USER_TYPE"] = $arType;
2663 $arUserField["VALUE"] = false;
2664 if (!is_array($arUserField["SETTINGS"]) || empty($arUserField["SETTINGS"]))
2665 {
2666 $arUserField["SETTINGS"] = $this->PrepareSettings(0, $arUserField);
2667 }
2668 $result[$arUserField["FIELD_NAME"]] = $arUserField;
2669 }
2670 }
2671 $this->arFieldsCache[$cacheId] = $result;
2672 }
2673 else
2674 {
2675 $result = $this->arFieldsCache[$cacheId];
2676 }
2677
2678 return $result;
2679 }
2680
2681 protected static function normalizeId(string $id): string
2682 {
2683 return preg_replace("/[^0-9A-Z_]+/", "", $id);
2684 }
2685
2686 protected function isFileValueDeleted(array $userField, int $fileId): bool
2687 {
2688 $fieldName = $userField['FIELD_NAME'] ?? '';
2689
2690 if (is_string($fieldName) && $fieldName !== '')
2691 {
2692 $deletedValues = Application::getInstance()->getContext()->getRequest()->get($fieldName . '_del');
2693
2694 if (!is_array($deletedValues))
2695 {
2696 $deletedValues = [$deletedValues];
2697 }
2698
2699 foreach ($deletedValues as $deletedValue)
2700 {
2701 if ($fileId === (int)$deletedValue)
2702 {
2703 return true;
2704 }
2705 }
2706
2707 $fileInputUtility = FileInputUtility::instance();
2708 $delResult = $fileInputUtility->checkDeletedFiles($fileInputUtility->getUserFieldCid($userField));
2709 if (in_array($fileId, $delResult))
2710 {
2711 return true;
2712 }
2713 }
2714
2715 return false;
2716 }
2717}
global $APPLICATION
Определения include.php:80
static getConnection($name="")
Определения application.php:638
static isCorrect($time, $format=null)
Определения date.php:359
DropEntity($entity_id)
Определения usertype.php:909
Определения usertype.php:985
AdminListAddFilterV2($entityId, &$arFilter, $filterId, $filterFields)
Определения usertypemanager.php:782
EditFormAddFields($entity_id, &$arFields, array $options=null)
Определения usertypemanager.php:529
const BASE_TYPE_FILE
Определения usertypemanager.php:23
$entityList
Определения usertypemanager.php:37
getUserFieldsWithReadyData($entity_id, $readyData, $LANG=false, $user_id=false, $primaryIdName='VALUE_ID')
Определения usertypemanager.php:287
const BASE_TYPE_INT
Определения usertypemanager.php:22
OnEntityDelete($entity_id)
Определения usertypemanager.php:179
LoadMultipleValues($arUserField, $valueId)
Определения usertypemanager.php:457
GetEditFormHTML($bVarsFromForm, $form_value, $arUserField)
Определения usertypemanager.php:936
GetFilterHTML($arUserField, $filter_name, $filter_value)
Определения usertypemanager.php:1098
EditFormTab($entity_id)
Определения usertypemanager.php:497
getEntities($entity_id, $LANG, $user_id)
Определения usertypemanager.php:2638
const BASE_TYPE_DOUBLE
Определения usertypemanager.php:25
GetDBColumnType($arUserField)
Определения usertypemanager.php:84
CleanCache()
Определения usertypemanager.php:39
AdminListPrepareFields($entity_id, &$arFields)
Определения usertypemanager.php:853
GetUserType($user_type_id=false)
Определения usertypemanager.php:56
AdminListAddFilterFieldsV2($entityId, &$arFilterFields)
Определения usertypemanager.php:672
AddUserField($arUserField, $value, $row)
Определения usertypemanager.php:1128
$arRightsCache
Определения usertypemanager.php:32
getUtsDBColumnType($arUserField)
Определения usertypemanager.php:96
OnAfterFetch($arUserField, $result)
Определения usertypemanager.php:413
GetRights($ENTITY_ID=false, $ID=false)
Определения usertypemanager.php:2426
AdminListShowFilter($entity_id)
Определения usertypemanager.php:915
const BASE_TYPE_ENUM
Определения usertypemanager.php:24
AdminListAddFilter($entityId, &$arFilter)
Определения usertypemanager.php:728
GetUserFields($entity_id, $value_id=0, $LANG=false, $user_id=false, $selectFields=null)
Определения usertypemanager.php:191
EditFormShowTab($entity_id, $bVarsFromForm, $ID)
Определения usertypemanager.php:509
ShowScript()
Определения usertypemanager.php:927
const BASE_TYPE_DATETIME
Определения usertypemanager.php:26
renderField(array $userField, ?array $additionalParameters=[])
Определения usertypemanager.php:1447
getEntityList()
Определения usertypemanager.php:385
getCustomData(array $userField, int $entityValueId)
Определения usertypemanager.php:161
PrepareSettings($ID, $arUserField, $bCheckUserType=true)
Определения usertypemanager.php:114
$arUserTypes
Определения usertypemanager.php:30
AdminListAddFilterFields($entityId, &$arFilterFields)
Определения usertypemanager.php:655
getUserFieldValuesByEvent(array $userFields, string $entityId, int $value)
Определения usertypemanager.php:2560
AddUserFields($entity_id, $arRes, $row)
Определения usertypemanager.php:881
const BASE_TYPE_STRING
Определения usertypemanager.php:27
GetUserFieldValue($entity_id, $field_id, $value_id, $LANG=false)
Определения usertypemanager.php:315
IsNotEmpty($value)
Определения usertypemanager.php:696
AdminListAddHeaders($entity_id, &$arHeaders)
Определения usertypemanager.php:865
getPublicText($userField)
Определения usertypemanager.php:1528
$arFieldsCache
Определения usertypemanager.php:31
AddFindFields($entity_id, &$arFindFields)
Определения usertypemanager.php:893
getUtmDBColumnType($arUserField)
Определения usertypemanager.php:109
$options
Определения commerceml2.php:49
$arFields
Определения dblapprove.php:5
$selfFolderUrl
Определения discount_coupon_list.php:18
& nbsp
Определения epilog_main_admin.php:38
$bVarsFromForm
Определения file_edit.php:44
bx popup label bx width30 PAGE_NEW_MENU_NAME text width
Определения file_new.php:677
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$res
Определения filter_act.php:7
$result
Определения get_property_values.php:14
if($ajaxMode) $ID
Определения get_user.php:27
$select
Определения iblock_catalog_list.php:194
$filterFields
Определения iblock_catalog_list.php:55
$selectFields
Определения iblock_catalog_list.php:160
global $adminSidePanelHelper
Определения init_admin.php:7
global $adminPage
Определения init_admin.php:7
global $DB
Определения cron_frame.php:29
ExecuteModuleEventEx($arEvent, $arParams=[])
Определения tools.php:5214
htmlspecialcharsbx($string, $flags=ENT_COMPAT, $doubleEncode=true)
Определения tools.php:2701
GetModuleEvents($MODULE_ID, $MESSAGE_ID, $bReturnArray=false)
Определения tools.php:5177
IncludeModuleLangFile($filepath, $lang=false, $bReturnArray=false)
Определения tools.php:3778
GetMessage($name, $aReplace=null)
Определения tools.php:3397
Определения collection.php:2
$files
Определения mysql_to_pgsql.php:30
$GLOBALS['____1690880296']
Определения license.php:1
$entityId
Определения payment.php:4
$event
Определения prolog_after.php:141
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
$ar
Определения options.php:199
if(empty($signedUserToken)) $key
Определения quickway.php:257
$LANG
Определения rss.php:26
font style
Определения invoice.php:442
font size
Определения invoice.php:442
$val
Определения options.php:1793
$arRes
Определения options.php:104
$rs
Определения action.php:82
$arFilter
Определения user_search.php:106
$arFilterFields
Определения user_search.php:40
$fields
Определения yandex_run.php:501