PageRenderTime 61ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/catalog/lib/product/systemfield.php

https://gitlab.com/alexprowars/bitrix
PHP | 633 lines | 500 code | 68 blank | 65 comment | 62 complexity | 1c3d1e6e574834b5b4e2b7386aa28aa9 MD5 | raw file
  1. <?php
  2. namespace Bitrix\Catalog\Product;
  3. use Bitrix\Main;
  4. use Bitrix\Main\Localization\Loc;
  5. use Bitrix\Main\ORM;
  6. use Bitrix\Catalog;
  7. use Bitrix\Catalog\Grid\Panel\ProductGroupAction;
  8. use Bitrix\Highloadblock as Highload;
  9. final class SystemField
  10. {
  11. public const EVENT_ID_BUILD_FIELD_LIST = 'OnProductUserFieldBuildList';
  12. public const STATUS_CONTINUE = 'continue';
  13. public const STATUS_FINAL = 'final';
  14. /** @deprecated */
  15. public const CODE_MARKING_CODE_GROUP = Catalog\Product\SystemField\MarkingCodeGroup::FIELD_ID;
  16. public const OPERATION_EXPORT = 'EXPORT';
  17. public const OPERATION_IMPORT = 'IMPORT';
  18. public const OPERATION_PROVIDER = 'PROVIDER';
  19. public const DESCRIPTION_MODE_FIELD_NAME = 'FIELD_NAME';
  20. public const DESCRIPTION_MODE_UI_LIST = 'UI_ENTITY_LIST';
  21. public const DESCRIPTION_MODE_FULL = 'FULL';
  22. private static ?array $currentFieldSet = null;
  23. private static array $defaultFieldList = [
  24. Catalog\Product\SystemField\MarkingCodeGroup::class,
  25. Catalog\Product\SystemField\ProductMapping::class,
  26. ];
  27. /**
  28. * @return string
  29. */
  30. public static function execAgent(): string
  31. {
  32. $result = '';
  33. $createResult = self::create();
  34. if (!$createResult->isSuccess())
  35. {
  36. $result = '\Bitrix\Catalog\Product\SystemField::execAgent();';
  37. }
  38. return $result;
  39. }
  40. /**
  41. * @return Main\Result
  42. */
  43. public static function create(): Main\Result
  44. {
  45. $result = new Main\Result();
  46. self::$currentFieldSet = null;
  47. $fieldList = self::getBuildedFieldList();
  48. if (empty($fieldList))
  49. {
  50. $result->setData(['STATUS' => self::STATUS_FINAL]);
  51. return $result;
  52. }
  53. foreach ($fieldList as $field)
  54. {
  55. $internalResult = $field::create();
  56. if (!$internalResult->isSuccess())
  57. {
  58. foreach ($internalResult->getErrors() as $error)
  59. {
  60. $result->addError($error);
  61. }
  62. }
  63. }
  64. $result->setData(['STATUS' => self::STATUS_FINAL]);
  65. return $result;
  66. }
  67. /**
  68. * @return void
  69. */
  70. public static function delete(): void
  71. {
  72. self::$currentFieldSet = null;
  73. }
  74. public static function getSelectFields(string $operation): array
  75. {
  76. $result = [];
  77. foreach (self::getCurrentFieldSet($operation) as $field)
  78. {
  79. $result = array_merge(
  80. $result,
  81. $field::getOperationSelectFieldList($operation)
  82. );
  83. }
  84. return $result;
  85. }
  86. /**
  87. * @param string $operation
  88. * @return array|Catalog\Product\SystemField\Base[]
  89. */
  90. private static function getCurrentFieldSet(string $operation): array
  91. {
  92. self::loadCurrentFieldSet($operation);
  93. return self::$currentFieldSet[$operation] ?? [];
  94. }
  95. private static function getDefaultFieldSet(): array
  96. {
  97. return [
  98. self::OPERATION_PROVIDER => null,
  99. self::OPERATION_IMPORT => null,
  100. self::OPERATION_EXPORT => null,
  101. ];
  102. }
  103. private static function loadCurrentFieldSet(string $operation): void
  104. {
  105. if (self::$currentFieldSet === null)
  106. {
  107. self::$currentFieldSet = self::getDefaultFieldSet();
  108. }
  109. if (!array_key_exists($operation, self::$currentFieldSet))
  110. {
  111. return;
  112. }
  113. if (self::$currentFieldSet[$operation] === null)
  114. {
  115. self::$currentFieldSet[$operation] = [];
  116. $fieldList = self::getBuildedFieldList();
  117. if (!empty($fieldList))
  118. {
  119. foreach ($fieldList as $field)
  120. {
  121. if ($field::checkAllowedOperation($operation) && $field::isExists())
  122. {
  123. self::$currentFieldSet[$operation][] = $field;
  124. }
  125. }
  126. unset($field);
  127. }
  128. unset($fieldList);
  129. }
  130. }
  131. public static function getProviderSelectFields(): array
  132. {
  133. return self::getSelectFields(self::OPERATION_PROVIDER);
  134. }
  135. public static function getExportSelectFields(): array
  136. {
  137. return self::getSelectFields(self::OPERATION_EXPORT);
  138. }
  139. public static function getImportSelectFields(): array
  140. {
  141. return self::getSelectFields(self::OPERATION_IMPORT);
  142. }
  143. /**
  144. * @deprecated
  145. * @see self::getSelectFields
  146. *
  147. * @return array
  148. */
  149. public static function getFieldList(): array
  150. {
  151. return self::getProviderSelectFields();
  152. }
  153. /**
  154. * @deprecated
  155. * @see prepareRow()
  156. *
  157. * @param array &$row
  158. * @param string $operation
  159. * @return void
  160. */
  161. public static function convertRow(array &$row, string $operation = self::OPERATION_PROVIDER): void
  162. {
  163. self::prepareRow($row, $operation);
  164. }
  165. public static function prepareRow(array &$row, string $operation = self::OPERATION_IMPORT): void
  166. {
  167. foreach (self::getCurrentFieldSet($operation) as $field)
  168. {
  169. $row = $field::prepareValue($operation, $row);
  170. }
  171. unset($field);
  172. }
  173. /**
  174. * @param ProductGroupAction $panel
  175. * @return array|null
  176. */
  177. public static function getGroupActions(ProductGroupAction $panel): ?array
  178. {
  179. $catalog = $panel->getCatalogConfig();
  180. if (empty($catalog))
  181. {
  182. return null;
  183. }
  184. $fieldList = self::getBuildedFieldList();
  185. if (empty($fieldList))
  186. {
  187. return null;
  188. }
  189. $result = [];
  190. foreach ($fieldList as $field)
  191. {
  192. $action = $field::getGridAction($panel);
  193. if (!empty($action))
  194. {
  195. $result[] = $action;
  196. }
  197. }
  198. unset($action, $field, $fieldList);
  199. return (!empty($result) ? $result : null);
  200. }
  201. public static function getByUserFieldName(string $fieldName): ?string
  202. {
  203. $fieldList = self::getBuildedFieldList();
  204. if (empty($fieldList))
  205. {
  206. return null;
  207. }
  208. $result = null;
  209. foreach ($fieldList as $field)
  210. {
  211. $baseParams = $field::getUserFieldBaseParam();
  212. if ($baseParams['FIELD_NAME'] === $fieldName)
  213. {
  214. /** @var string $result */
  215. $result = $field;
  216. break;
  217. }
  218. }
  219. unset($baseParams, $field, $fieldList);
  220. return $result;
  221. }
  222. public static function getFieldsByRestrictions(array $restrictions, array $config = []): array
  223. {
  224. $fieldList = self::getBuildedFieldList();
  225. if (empty($fieldList))
  226. {
  227. return [];
  228. }
  229. $simpleList = isset($config['FIELD_NAME']) && $config['FIELD_NAME'] === 'Y';
  230. $result = [];
  231. foreach ($fieldList as $field)
  232. {
  233. if (
  234. $field::checkRestictions($restrictions)
  235. && $field::isExists()
  236. )
  237. {
  238. $data = $field::getUserFieldBaseParam();
  239. if ($simpleList)
  240. {
  241. $result[] = $data['FIELD_NAME'];
  242. }
  243. else
  244. {
  245. $result[] = [
  246. $data['FIELD_NAME'] => $field::getTitle(),
  247. ];
  248. }
  249. }
  250. }
  251. unset($field, $fieldList);
  252. return $result;
  253. }
  254. public static function getFieldNamesByRestrictions(array $restrictions): array
  255. {
  256. return self::getFieldsByRestrictions(
  257. $restrictions,
  258. [
  259. 'FIELD_NAME' => 'Y',
  260. ]
  261. );
  262. }
  263. public static function getPermissionFieldsByRestrictions(array $restrictions): array
  264. {
  265. $fieldList = self::getBuildedFieldList();
  266. if (empty($fieldList))
  267. {
  268. return [];
  269. }
  270. $result = [];
  271. foreach ($fieldList as $field)
  272. {
  273. if ($field::isExists())
  274. {
  275. $data = $field::getUserFieldBaseParam();
  276. $result[$data['FIELD_NAME']] = $field::checkRestictions($restrictions);
  277. }
  278. }
  279. unset($field, $fieldList);
  280. return $result;
  281. }
  282. public static function getAllowedProductTypes(): array
  283. {
  284. $fieldList = self::getBuildedFieldList();
  285. if (empty($fieldList))
  286. {
  287. return [];
  288. }
  289. $result = [];
  290. foreach ($fieldList as $field)
  291. {
  292. $baseParams = $field::getUserFieldBaseParam();
  293. $result[$baseParams['FIELD_NAME']] = $field::getAllowedProductTypeList();
  294. }
  295. unset($field, $fieldList);
  296. return $result;
  297. }
  298. /**
  299. * @param ProductGroupAction $panel
  300. * @param string $fieldName
  301. * @return array|null
  302. */
  303. public static function getGroupActionRequest(ProductGroupAction $panel, string $fieldName): ?array
  304. {
  305. $catalog = $panel->getCatalogConfig();
  306. if (empty($catalog))
  307. {
  308. return null;
  309. }
  310. /** @var Catalog\Product\SystemField\Base $field */
  311. $field = self::getByUserFieldName($fieldName);
  312. if (empty($field))
  313. {
  314. return null;
  315. }
  316. return $field::getGroupActionRequest($panel);
  317. }
  318. /**
  319. * @param ORM\Event $event
  320. * @return ORM\EventResult
  321. * @throws Main\ArgumentException
  322. * @throws Main\ObjectPropertyException
  323. * @throws Main\SystemException
  324. */
  325. public static function handlerHighloadBlockBeforeDelete(ORM\Event $event): ORM\EventResult
  326. {
  327. $result = new ORM\EventResult();
  328. if (Catalog\Product\SystemField\Type\HighloadBlock::isAllowed())
  329. {
  330. $primary = $event->getParameter('primary');
  331. if (!empty($primary))
  332. {
  333. $iterator = Highload\HighloadBlockTable::getList([
  334. 'filter' => $primary,
  335. ]);
  336. $row = $iterator->fetch();
  337. unset($iterator);
  338. if (!empty($row))
  339. {
  340. $fieldList = self::getBuildedFieldList();
  341. foreach ($fieldList as $field)
  342. {
  343. if ($field::getTypeId() !== Catalog\Product\SystemField\Type\HighloadBlock::class)
  344. {
  345. continue;
  346. }
  347. if (!$field::isAllowed() || !$field::isExists())
  348. {
  349. continue;
  350. }
  351. $config = $field::getConfig();
  352. if ($row['NAME'] === $config['HIGHLOADBLOCK']['NAME'])
  353. {
  354. $result->addError(new ORM\EntityError(
  355. Loc::getMessage(
  356. 'BX_CATALOG_PRODUCT_SYSTEMFIELD_ERR_CANNOT_DELETE_HIGHLOADBLOCK',
  357. ['#NAME#' => $row['NAME']]
  358. )
  359. ));
  360. }
  361. unset($config);
  362. }
  363. unset($field, $fieldList);
  364. }
  365. unset($row);
  366. }
  367. unset($primary);
  368. }
  369. return $result;
  370. }
  371. /**
  372. * @param ORM\Event $event
  373. * @return ORM\EventResult
  374. * @throws Main\ArgumentException
  375. * @throws Main\ObjectPropertyException
  376. * @throws Main\SystemException
  377. */
  378. public static function handlerHighloadBlockBeforeUpdate(ORM\Event $event): ORM\EventResult
  379. {
  380. $result = new ORM\EventResult();
  381. if (Catalog\Product\SystemField\Type\HighloadBlock::isAllowed())
  382. {
  383. $primary = $event->getParameter('primary');
  384. $fields = $event->getParameter('fields');
  385. if (!empty($primary))
  386. {
  387. $iterator = Highload\HighloadBlockTable::getList([
  388. 'filter' => $primary,
  389. ]);
  390. $row = $iterator->fetch();
  391. unset($iterator);
  392. if (!empty($row))
  393. {
  394. $fieldList = self::getBuildedFieldList();
  395. foreach ($fieldList as $field)
  396. {
  397. if ($field::getTypeId() !== Catalog\Product\SystemField\Type\HighloadBlock::class)
  398. {
  399. continue;
  400. }
  401. if (!$field::isAllowed() || !$field::isExists())
  402. {
  403. continue;
  404. }
  405. $config = $field::getConfig();
  406. if ($row['NAME'] === $config['HIGHLOADBLOCK']['NAME'])
  407. {
  408. if (
  409. (isset($fields['NAME']) && $row['NAME'] != $fields['NAME'])
  410. || (isset($fields['TABLE_NAME']) && $row['TABLE_NAME'] != $fields['TABLE_NAME'])
  411. )
  412. {
  413. $result->addError(new ORM\EntityError(
  414. Loc::getMessage(
  415. 'BX_CATALOG_PRODUCT_SYSTEMFIELD_ERR_CANNOT_UPDATE_HIGHLOADBLOCK',
  416. ['#NAME#' => $row['NAME']]
  417. )
  418. ));
  419. }
  420. }
  421. unset($config);
  422. }
  423. unset($field, $fieldList);
  424. }
  425. unset($row);
  426. }
  427. unset($primary);
  428. }
  429. return $result;
  430. }
  431. /**
  432. * @param Main\Event $event
  433. * @return Main\EventResult
  434. */
  435. public static function handlerHighloadBlockBeforeUninstall(Main\Event $event): Main\EventResult
  436. {
  437. $blockNames = [];
  438. $module = $event->getParameter('module');
  439. if ($module === 'highloadblock')
  440. {
  441. $fieldList = self::getBuildedFieldList();
  442. foreach ($fieldList as $field)
  443. {
  444. if ($field::getTypeId() !== Catalog\Product\SystemField\Type\HighloadBlock::class)
  445. {
  446. continue;
  447. }
  448. if (!$field::isAllowed() || !$field::isExists())
  449. {
  450. continue;
  451. }
  452. $config = $field::getConfig();
  453. /** @var Catalog\Product\SystemField\Type\HighloadBlock $fieldType */
  454. $fieldType = $field::getTypeId();
  455. $row = $fieldType::getStorageTable($config['HIGHLOADBLOCK']);
  456. if (!empty($row))
  457. {
  458. $blockNames[] = $config['HIGHLOADBLOCK']['NAME'];
  459. }
  460. unset($row, $fieldType, $config);
  461. }
  462. unset($fieldList);
  463. }
  464. unset($module);
  465. if (empty($blockNames))
  466. {
  467. return new Main\EventResult(Main\EventResult::SUCCESS);
  468. }
  469. else
  470. {
  471. if (count($blockNames) === 1)
  472. {
  473. $error = Loc::getMessage(
  474. 'BX_CATALOG_PRODUCT_SYSTEMFIELD_ERR_DISALLOW_UNINSTALL_HIGHLOADBLOCK',
  475. [
  476. '#NAME#' => reset($blockNames),
  477. ]
  478. );
  479. }
  480. else
  481. {
  482. $error = Loc::getMessage(
  483. 'BX_CATALOG_PRODUCT_SYSTEMFIELD_ERR_DISALLOW_UNINSTALL_HIGHLOADBLOCK_LIST',
  484. [
  485. '#NAME#' => implode(', ', $blockNames),
  486. ]
  487. );
  488. }
  489. return new Main\EventResult(
  490. Main\EventResult::ERROR,
  491. [
  492. 'error' => $error,
  493. ],
  494. 'catalog'
  495. );
  496. }
  497. }
  498. /**
  499. * @return array|Catalog\Product\SystemField\Base[]
  500. */
  501. protected static function getBuildedFieldList(): array
  502. {
  503. $result = [];
  504. $list = array_merge(
  505. self::$defaultFieldList,
  506. self::getExternalFieldList()
  507. );
  508. /** @var Catalog\Product\SystemField\Base $className */
  509. foreach ($list as $className)
  510. {
  511. if ($className::isAllowed())
  512. {
  513. $result[] = $className;
  514. }
  515. }
  516. return $result;
  517. }
  518. /**
  519. * @return array|Catalog\Product\SystemField\Base[]
  520. */
  521. protected static function getExternalFieldList(): array
  522. {
  523. $result = [];
  524. $event = new Main\Event(
  525. 'catalog',
  526. self::EVENT_ID_BUILD_FIELD_LIST,
  527. []
  528. );
  529. $event->send();
  530. $eventResult = $event->getResults();
  531. if (!empty($eventResult) && is_array($eventResult))
  532. {
  533. foreach ($eventResult as $row)
  534. {
  535. if ($row->getType() != Main\EventResult::SUCCESS)
  536. {
  537. continue;
  538. }
  539. $classList = $row->getParameters();
  540. if (empty($classList) || !is_array($classList))
  541. {
  542. continue;
  543. }
  544. foreach ($classList as $item)
  545. {
  546. if (!is_string($item))
  547. {
  548. continue;
  549. }
  550. $item = trim($item);
  551. if (
  552. $item === ''
  553. || !class_exists($item)
  554. || !is_a($item, Catalog\Product\SystemField\Base::class, true)
  555. )
  556. {
  557. continue;
  558. }
  559. $result[] = $item;
  560. }
  561. }
  562. }
  563. return $result;
  564. }
  565. }