Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
SaveSettingsAction.php
1<?php
2
4
16use CFile;
17use CIBlockProperty;
18use CIBlockPropertyDirectory;
19use CIBlockRights;
20use CUserTypeEntity;
21use Throwable;
22
26final class SaveSettingsAction extends Action
27{
36 public function run(int $propertyId, array $fields): bool
37 {
38 Loader::requireModule('highloadblock');
39
40 if (!$this->checkWritePermissions($propertyId))
41 {
42 $this->errorCollection->setError(
43 new Error(Loc::getMessage('IBLOCK_CONTROLLER_PROPERTY_DIRECTION_ACTION_SAVE_ERROR_ACCESS_DENIED'))
44 );
45
46 return false;
47 }
48
49 $fields = $this->cleanEntityFields($fields);
50 if (empty($fields))
51 {
52 $this->errorCollection->setError(
53 new Error(Loc::getMessage('IBLOCK_CONTROLLER_PROPERTY_DIRECTION_ACTION_SAVE_ERROR_BAD_REQUEST'))
54 );
55
56 return false;
57 }
58
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)
62 {
63 $this->errorCollection->setError(
64 new Error(Loc::getMessage('IBLOCK_CONTROLLER_PROPERTY_DIRECTION_ACTION_SAVE_ERROR_BAD_REQUEST'))
65 );
66
67 return false;
68 }
69
71 try
72 {
73 $db->startTransaction();
74
75 $result = $this->save($propertyId, $name, $tableName, $fields);
76 if ($result->isSuccess())
77 {
78 $db->commitTransaction();
79 }
80 else
81 {
82 $db->rollbackTransaction();
83 }
84 }
85 catch (Throwable $e)
86 {
87 $db->rollbackTransaction();
88
89 throw $e;
90 }
91
92 foreach ($result->getErrors() as $error)
93 {
94 $this->errorCollection->setError($error);
95 }
96
97 return $result->isSuccess();
98 }
99
100 private function save(int $propertyId, ?string $name, ?string $tableName, array $fields): Result
101 {
102 $result = new Result();
103
104 $isNewHighload = !empty($name);
105 if ($isNewHighload)
106 {
107 $result = $this->createHighload($fields);
108 if (!$result->isSuccess() || count($this->errorCollection) > 0)
109 {
110 return $result;
111 }
112
113 $highloadBlock = HighloadBlockTable::getById($result->getId())->fetch();
114 }
115 else
116 {
117 $highloadBlock = HighloadBlockTable::getRow([
118 'filter' => [
119 '=TABLE_NAME' => $tableName,
120 ],
121 ]);
122 }
123
124 if (!$highloadBlock)
125 {
126 $result->addError(
127 new Error(Loc::getMessage('IBLOCK_CONTROLLER_PROPERTY_DIRECTION_ACTION_SAVE_ERROR_BAD_REQUEST'))
128 );
129
130 return $result;
131 }
132
136 $entity = HighloadBlockTable::compileEntity($highloadBlock);
137 $result = $this->saveHighloadValues($entity, $fields, $isNewHighload);
138
139 if ($result->isSuccess())
140 {
141 $result = $this->updatePropertyTable($propertyId, $highloadBlock['TABLE_NAME'], $isNewHighload);
142 }
143
144 return $result;
145 }
146
154 private function checkWritePermissions(int $propertyId): bool
155 {
156 $property = CIBlockProperty::GetByID($propertyId)->Fetch();
157 if ($property)
158 {
159 $iblockId = (int)$property['IBLOCK_ID'];
160
161 return CIBlockRights::UserHasRightTo($iblockId, $iblockId, 'iblock_edit');
162 }
163
164 return false;
165 }
166
174 private function cleanEntityFields(array $fields): array
175 {
176 $availableFields = array_fill_keys([
177 'DIRECTORY_NAME',
178 'DIRECTORY_TABLE_NAME',
179 'DIRECTORY_ITEMS',
180 ], true);
181
182 return array_intersect_key($fields, $availableFields);
183 }
184
192 private function createHighload(array $fields): AddResult
193 {
194 $result = new AddResult();
195
196 $title = trim($fields['DIRECTORY_NAME']);
197 if (empty($title))
198 {
199 $this->errorCollection->setError(
200 new Error(Loc::getMessage("IBLOCK_CONTROLLER_PROPERTY_DIRECTION_ACTION_SAVE_HIGHLOAD_ERROR_NAME_IS_ABSENT"))
201 );
202
203 return $result;
204 }
205
206 $name = mb_strtoupper(mb_substr($title, 0, 1)).mb_substr($title, 1);
207 if (!preg_match('/^[A-Z][A-Za-z0-9]*$/', $name))
208 {
209 $this->errorCollection->setError(
210 new Error(Loc::getMessage("IBLOCK_CONTROLLER_PROPERTY_DIRECTION_ACTION_SAVE_HIGHLOAD_ERROR_NAME_IS_INVALID"))
211 );
212
213 return $result;
214 }
215
216 $tableName = CIBlockPropertyDirectory::createHighloadTableName($title);
217 if ($tableName === false)
218 {
219 $this->errorCollection->setError(
220 new Error(Loc::getMessage("IBLOCK_CONTROLLER_PROPERTY_DIRECTION_ACTION_SAVE_HIGHLOAD_ERROR_NAME_IS_ABSENT"))
221 );
222
223 return $result;
224 }
225
226 $data = array(
227 'NAME' => $name,
228 'TABLE_NAME' => $tableName,
229 );
230
231 $result = HighloadBlockTable::add($data);
232 if (!$result->isSuccess())
233 {
234 return $result;
235 }
236
237 $highloadBlockId = $result->getId();
238 if (is_array($fields['DIRECTORY_ITEMS']))
239 {
240 $fieldsNames = reset($fields['DIRECTORY_ITEMS']);
241 $fieldsNames['UF_DEF'] = '';
242 $fieldsNames['UF_FILE'] = '';
243
244 $sort = 100;
245 $userTypeEntity = new CUserTypeEntity();
246 $userFieldEntityId = 'HLBLOCK_' . $highloadBlockId;
247
248 foreach($fieldsNames as $fieldName => $fieldValue)
249 {
250 if ('UF_DELETE' === $fieldName)
251 {
252 continue;
253 }
254
255 $fieldMandatory = 'N';
256 switch($fieldName)
257 {
258 case 'UF_NAME':
259 case 'UF_XML_ID':
260 $fieldType = 'string';
261 $fieldMandatory = 'Y';
262 break;
263
264 case 'UF_LINK':
265 case 'UF_DESCRIPTION':
266 case 'UF_FULL_DESCRIPTION':
267 $fieldType = 'string';
268 break;
269
270 case 'UF_SORT':
271 $fieldType = 'integer';
272 break;
273
274 case 'UF_FILE':
275 $fieldType = 'file';
276 break;
277
278 case 'UF_DEF':
279 $fieldType = 'boolean';
280 break;
281
282 default:
283 $fieldType = 'string';
284 }
285
286 $userFieldValues = [
287 'ENTITY_ID' => $userFieldEntityId,
288 'FIELD_NAME' => $fieldName,
289 'USER_TYPE_ID' => $fieldType,
290 'XML_ID' => '',
291 'SORT' => $sort,
292 'MULTIPLE' => 'N',
293 'MANDATORY' => $fieldMandatory,
294 'SHOW_FILTER' => 'N',
295 'SHOW_IN_LIST' => 'Y',
296 'EDIT_IN_LIST' => 'Y',
297 'IS_SEARCHABLE' => 'N',
298 'SETTINGS' => [],
299 ];
300
301 $userTypeEntity->Add($userFieldValues);
302 $sort += 100;
303 }
304 }
305
306 return $result;
307 }
308
318 private function saveHighloadValues(Entity $entity, array $fields, bool $isNewHighload): Result
319 {
320 $result = new Result();
321
322 $directoryValues = $fields['DIRECTORY_ITEMS'] ?? null;
323 if (!is_array($directoryValues))
324 {
325 return $result;
326 }
327
328 $entityDataClass = $entity->getDataClass();
329 $fieldsList = $entityDataClass::getMap();
330 if (count($fieldsList) === 1 && isset($fieldsList['ID']))
331 {
332 $fieldsList = $entity->getFields();
333 }
334
335 $images = $this->getRequestImages();
336
337 foreach($directoryValues as $itemKey => $item)
338 {
339 if (!is_array($item))
340 {
341 continue;
342 }
343
344 $itemId = mb_substr($itemKey, 0, 1) === 'n' ? 0 : (int)$itemKey;
345 if (isset($item["UF_DELETE"]) && $item["UF_DELETE"] === 'Y')
346 {
347 if ($itemId > 0)
348 {
349 $entityDataClass::delete($itemId);
350 }
351 continue;
352 }
353 elseif (!isset($item['UF_NAME']) || empty(trim($item['UF_NAME'])))
354 {
355 continue;
356 }
357
358 if (isset($images[$itemKey]) && is_array($images[$itemKey]))
359 {
360 $item['UF_FILE'] = $images[$itemKey];
361 }
362 elseif (isset($item['UF_FILE']) && $item['UF_FILE'] === 'null')
363 {
364 $item['UF_FILE'] = null;
365 }
366 else
367 {
368 // to prevent deletion
369 unset($item['UF_FILE']);
370 }
371
372 if (empty($item["UF_XML_ID"]))
373 {
374 $item['UF_XML_ID'] = Random::getString(8, true);
375 }
376
377 if (isset($item['UF_DEF']))
378 {
379 $value = (string)$item['UF_DEF'];
380 $item['UF_DEF'] = $value === '1' || $value === 'Y' ? 1 : 0;
381 }
382
383 // clear fields list
384 $item = array_filter(
385 $item,
386 static fn($name) => isset($fieldsList[$name]),
387 ARRAY_FILTER_USE_KEY
388 );
389
390 if ($isNewHighload)
391 {
392 $entityDataClass::add($item);
393 }
394 else
395 {
396 if ($itemId > 0)
397 {
398 $existRow = $entityDataClass::getRowById($itemId);
399 if ($existRow)
400 {
401 $result->addErrors(
402 $entityDataClass::update($itemId, $item)->getErrors()
403 );
404 }
405 }
406 else
407 {
408 $result->addErrors(
409 $entityDataClass::add($item)->getErrors()
410 );
411 }
412 }
413 }
414
415 return $result;
416 }
417
423 private function getRequestImages(): array
424 {
425 $result = [];
426
427 $files = Context::getCurrent()->getRequest()->getFileList();
428 $requestFiles = $files['fields'] ?? null;
429 if (is_array($requestFiles))
430 {
431 CFile::ConvertFilesToPost($requestFiles, $result);
432
433 // remove UF_FILE key
434 $result = $result['DIRECTORY_ITEMS'] ?? [];
435 foreach ($result as $rowId => $data)
436 {
437 $result[$rowId] = $data['UF_FILE'];
438 }
439 }
440
441 return $result;
442 }
443
444 private function updatePropertyTable(int $propertyId, string $tableName, bool $isNewHighload): Result
445 {
446 $result = new Result();
447
448 $ibp = new CIBlockProperty();
449 $oldFields = $ibp::GetByID($propertyId)->Fetch();
450 if ($oldFields)
451 {
452 $settings = (array)($oldFields['USER_TYPE_SETTINGS'] ?? []);
453
454 $isChangeTableName = isset($settings['TABLE_NAME']) && $settings['TABLE_NAME'] !== $tableName;
455 if ($isNewHighload || $isChangeTableName)
456 {
457 $settings['TABLE_NAME'] = $tableName;
458
459 $ibp->Update($propertyId, [
460 'USER_TYPE_SETTINGS' => serialize($settings),
461 ]);
462 if ($ibp->LAST_ERROR)
463 {
464 $result->addError(
465 new Error($ibp->LAST_ERROR)
466 );
467 }
468 }
469 }
470
471 return $result;
472 }
473}
static getConnection($name="")
static getCurrent()
Definition context.php:241
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29