36 public function run(
int $propertyId, array $fields): bool
38 Loader::requireModule(
'highloadblock');
40 if (!$this->checkWritePermissions($propertyId))
42 $this->errorCollection->setError(
43 new Error(
Loc::getMessage(
'IBLOCK_CONTROLLER_PROPERTY_DIRECTION_ACTION_SAVE_ERROR_ACCESS_DENIED'))
49 $fields = $this->cleanEntityFields($fields);
52 $this->errorCollection->setError(
59 $name = isset($fields[
'DIRECTORY_NAME']) && is_scalar($fields[
'DIRECTORY_NAME']) ? (string)$fields[
'DIRECTORY_NAME'] :
null;
60 $tableName = isset($fields[
'DIRECTORY_TABLE_NAME']) && is_scalar($fields[
'DIRECTORY_TABLE_NAME']) ? (string)$fields[
'DIRECTORY_TABLE_NAME'] :
null;
61 if (!$tableName && !
$name)
63 $this->errorCollection->setError(
73 $db->startTransaction();
75 $result = $this->save($propertyId,
$name, $tableName, $fields);
76 if ($result->isSuccess())
78 $db->commitTransaction();
82 $db->rollbackTransaction();
87 $db->rollbackTransaction();
92 foreach ($result->getErrors() as $error)
94 $this->errorCollection->setError($error);
97 return $result->isSuccess();
100 private function save(
int $propertyId, ?
string $name, ?
string $tableName, array $fields):
Result
104 $isNewHighload = !empty(
$name);
107 $result = $this->createHighload($fields);
108 if (!$result->isSuccess() || count($this->errorCollection) > 0)
113 $highloadBlock = HighloadBlockTable::getById($result->getId())->fetch();
117 $highloadBlock = HighloadBlockTable::getRow([
119 '=TABLE_NAME' => $tableName,
127 new Error(
Loc::getMessage(
'IBLOCK_CONTROLLER_PROPERTY_DIRECTION_ACTION_SAVE_ERROR_BAD_REQUEST'))
136 $entity = HighloadBlockTable::compileEntity($highloadBlock);
137 $result = $this->saveHighloadValues($entity, $fields, $isNewHighload);
139 if ($result->isSuccess())
141 $result = $this->updatePropertyTable($propertyId, $highloadBlock[
'TABLE_NAME'], $isNewHighload);
154 private function checkWritePermissions(
int $propertyId): bool
156 $property = CIBlockProperty::GetByID($propertyId)->Fetch();
159 $iblockId = (int)$property[
'IBLOCK_ID'];
161 return CIBlockRights::UserHasRightTo($iblockId, $iblockId,
'iblock_edit');
174 private function cleanEntityFields(array $fields): array
176 $availableFields = array_fill_keys([
178 'DIRECTORY_TABLE_NAME',
182 return array_intersect_key($fields, $availableFields);
192 private function createHighload(array $fields): AddResult
194 $result =
new AddResult();
196 $title = trim($fields[
'DIRECTORY_NAME']);
199 $this->errorCollection->setError(
200 new Error(
Loc::getMessage(
"IBLOCK_CONTROLLER_PROPERTY_DIRECTION_ACTION_SAVE_HIGHLOAD_ERROR_NAME_IS_ABSENT"))
206 $name = mb_strtoupper(mb_substr($title, 0, 1)).mb_substr($title, 1);
207 if (!preg_match(
'/^[A-Z][A-Za-z0-9]*$/',
$name))
209 $this->errorCollection->setError(
210 new Error(
Loc::getMessage(
"IBLOCK_CONTROLLER_PROPERTY_DIRECTION_ACTION_SAVE_HIGHLOAD_ERROR_NAME_IS_INVALID"))
216 $tableName = CIBlockPropertyDirectory::createHighloadTableName($title);
217 if ($tableName ===
false)
219 $this->errorCollection->setError(
220 new Error(
Loc::getMessage(
"IBLOCK_CONTROLLER_PROPERTY_DIRECTION_ACTION_SAVE_HIGHLOAD_ERROR_NAME_IS_ABSENT"))
228 'TABLE_NAME' => $tableName,
231 $result = HighloadBlockTable::add($data);
232 if (!$result->isSuccess())
237 $highloadBlockId = $result->getId();
238 if (is_array($fields[
'DIRECTORY_ITEMS']))
240 $fieldsNames = reset($fields[
'DIRECTORY_ITEMS']);
241 $fieldsNames[
'UF_DEF'] =
'';
242 $fieldsNames[
'UF_FILE'] =
'';
245 $userTypeEntity =
new CUserTypeEntity();
246 $userFieldEntityId =
'HLBLOCK_' . $highloadBlockId;
248 foreach($fieldsNames as $fieldName => $fieldValue)
250 if (
'UF_DELETE' === $fieldName)
255 $fieldMandatory =
'N';
260 $fieldType =
'string';
261 $fieldMandatory =
'Y';
265 case 'UF_DESCRIPTION':
266 case 'UF_FULL_DESCRIPTION':
267 $fieldType =
'string';
271 $fieldType =
'integer';
279 $fieldType =
'boolean';
283 $fieldType =
'string';
287 'ENTITY_ID' => $userFieldEntityId,
288 'FIELD_NAME' => $fieldName,
289 'USER_TYPE_ID' => $fieldType,
293 'MANDATORY' => $fieldMandatory,
294 'SHOW_FILTER' =>
'N',
295 'SHOW_IN_LIST' =>
'Y',
296 'EDIT_IN_LIST' =>
'Y',
297 'IS_SEARCHABLE' =>
'N',
301 $userTypeEntity->Add($userFieldValues);
318 private function saveHighloadValues(Entity $entity, array $fields,
bool $isNewHighload): Result
320 $result =
new Result();
322 $directoryValues = $fields[
'DIRECTORY_ITEMS'] ??
null;
323 if (!is_array($directoryValues))
328 $entityDataClass = $entity->getDataClass();
329 $fieldsList = $entityDataClass::getMap();
330 if (count($fieldsList) === 1 && isset($fieldsList[
'ID']))
332 $fieldsList = $entity->getFields();
335 $images = $this->getRequestImages();
337 foreach($directoryValues as $itemKey => $item)
339 if (!is_array($item))
344 $itemId = mb_substr($itemKey, 0, 1) ===
'n' ? 0 : (int)$itemKey;
345 if (isset($item[
"UF_DELETE"]) && $item[
"UF_DELETE"] ===
'Y')
349 $entityDataClass::delete($itemId);
353 elseif (!isset($item[
'UF_NAME']) || empty(trim($item[
'UF_NAME'])))
358 if (isset($images[$itemKey]) && is_array($images[$itemKey]))
360 $item[
'UF_FILE'] = $images[$itemKey];
362 elseif (isset($item[
'UF_FILE']) && $item[
'UF_FILE'] ===
'null')
364 $item[
'UF_FILE'] =
null;
369 unset($item[
'UF_FILE']);
372 if (empty($item[
"UF_XML_ID"]))
374 $item[
'UF_XML_ID'] = Random::getString(8,
true);
377 if (isset($item[
'UF_DEF']))
379 $value = (string)$item[
'UF_DEF'];
380 $item[
'UF_DEF'] = $value ===
'1' || $value ===
'Y' ? 1 : 0;
384 $item = array_filter(
386 static fn(
$name) => isset($fieldsList[
$name]),
392 $entityDataClass::add($item);
398 $existRow = $entityDataClass::getRowById($itemId);
402 $entityDataClass::update($itemId, $item)->
getErrors()
409 $entityDataClass::add($item)->
getErrors()
423 private function getRequestImages(): array
428 $requestFiles = $files[
'fields'] ??
null;
429 if (is_array($requestFiles))
431 CFile::ConvertFilesToPost($requestFiles, $result);
434 $result = $result[
'DIRECTORY_ITEMS'] ?? [];
435 foreach ($result as $rowId => $data)
437 $result[$rowId] = $data[
'UF_FILE'];
444 private function updatePropertyTable(
int $propertyId,
string $tableName,
bool $isNewHighload): Result
446 $result =
new Result();
448 $ibp =
new CIBlockProperty();
449 $oldFields = $ibp::GetByID($propertyId)->Fetch();
452 $settings = (array)($oldFields[
'USER_TYPE_SETTINGS'] ?? []);
454 $isChangeTableName = isset($settings[
'TABLE_NAME']) && $settings[
'TABLE_NAME'] !== $tableName;
455 if ($isNewHighload || $isChangeTableName)
457 $settings[
'TABLE_NAME'] = $tableName;
459 $ibp->Update($propertyId, [
460 'USER_TYPE_SETTINGS' => serialize($settings),
462 if ($ibp->LAST_ERROR)
465 new Error($ibp->LAST_ERROR)
static getMessage($code, $replace=null, $language=null)