EavSetup.php 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Eav\Setup;
  7. use Magento\Eav\Model\Entity\Setup\Context;
  8. use Magento\Eav\Model\Entity\Setup\PropertyMapperInterface;
  9. use Magento\Eav\Model\ResourceModel\Entity\Attribute\Group\CollectionFactory;
  10. use Magento\Framework\App\CacheInterface;
  11. use Magento\Framework\App\ObjectManager;
  12. use Magento\Framework\App\ResourceConnection;
  13. use Magento\Framework\Exception\LocalizedException;
  14. use Magento\Framework\Setup\ModuleDataSetupInterface;
  15. /**
  16. * @api
  17. * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
  18. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  19. * @codeCoverageIgnore
  20. * @since 100.0.2
  21. */
  22. class EavSetup
  23. {
  24. /**
  25. * Cache
  26. *
  27. * @var CacheInterface
  28. */
  29. private $cache;
  30. /**
  31. * Attribute group collection factory
  32. *
  33. * @var CollectionFactory
  34. */
  35. private $attrGroupCollectionFactory;
  36. /**
  37. * Attribute mapper
  38. *
  39. * @var PropertyMapperInterface
  40. */
  41. private $attributeMapper;
  42. /**
  43. * Setup model
  44. *
  45. * @var ModuleDataSetupInterface
  46. */
  47. private $setup;
  48. /**
  49. * General Attribute Group Name
  50. *
  51. * @var string
  52. */
  53. private $_generalGroupName = 'General';
  54. /**
  55. * Default attribute group name to id pairs
  56. *
  57. * @var array
  58. */
  59. private $defaultGroupIdAssociations = ['general' => 1];
  60. /**
  61. * Default attribute group name
  62. *
  63. * @var string
  64. */
  65. private $_defaultGroupName = 'Default';
  66. /**
  67. * Default attribute set name
  68. *
  69. * @var string
  70. */
  71. private $_defaultAttributeSetName = 'Default';
  72. /**
  73. * Init
  74. *
  75. * @param ModuleDataSetupInterface $setup
  76. * @param Context $context
  77. * @param CacheInterface $cache
  78. * @param CollectionFactory $attrGroupCollectionFactory
  79. */
  80. public function __construct(
  81. ModuleDataSetupInterface $setup,
  82. Context $context,
  83. CacheInterface $cache,
  84. CollectionFactory $attrGroupCollectionFactory
  85. ) {
  86. $this->cache = $cache;
  87. $this->attrGroupCollectionFactory = $attrGroupCollectionFactory;
  88. $this->attributeMapper = $context->getAttributeMapper();
  89. $this->setup = $setup;
  90. }
  91. /**
  92. * Gets setup model
  93. * @deprecated 102.0.0
  94. * @return ModuleDataSetupInterface
  95. */
  96. public function getSetup()
  97. {
  98. return $this->setup;
  99. }
  100. /**
  101. * Gets attribute group collection factory
  102. *
  103. * @return \Magento\Eav\Model\ResourceModel\Entity\Attribute\Group\Collection
  104. */
  105. public function getAttributeGroupCollectionFactory()
  106. {
  107. return $this->attrGroupCollectionFactory->create();
  108. }
  109. /**
  110. * Clean cache
  111. *
  112. * @return $this
  113. */
  114. public function cleanCache()
  115. {
  116. $this->cache->clean([\Magento\Eav\Model\Cache\Type::CACHE_TAG]);
  117. return $this;
  118. }
  119. /**
  120. * Install Default Group Ids
  121. *
  122. * @return $this
  123. */
  124. public function installDefaultGroupIds()
  125. {
  126. $setIds = $this->getAllAttributeSetIds();
  127. foreach ($this->defaultGroupIdAssociations as $defaultGroupCode => $defaultGroupId) {
  128. foreach ($setIds as $set) {
  129. $groupId = $this->setup->getTableRow(
  130. 'eav_attribute_group',
  131. 'attribute_group_code',
  132. $defaultGroupCode,
  133. 'attribute_group_id',
  134. 'attribute_set_id',
  135. $set
  136. );
  137. if (!$groupId) {
  138. $groupId = $this->setup->getTableRow(
  139. 'eav_attribute_group',
  140. 'attribute_set_id',
  141. $set,
  142. 'attribute_group_id'
  143. );
  144. }
  145. $this->setup->updateTableRow(
  146. 'eav_attribute_group',
  147. 'attribute_group_id',
  148. $groupId,
  149. 'default_id',
  150. $defaultGroupId
  151. );
  152. }
  153. }
  154. return $this;
  155. }
  156. /******************* ENTITY TYPES *****************/
  157. /**
  158. * Add an entity type
  159. *
  160. * If already exists updates the entity type with params data
  161. *
  162. * @param string $code
  163. * @param array $params
  164. * @return $this
  165. */
  166. public function addEntityType($code, array $params)
  167. {
  168. $data = [
  169. 'entity_type_code' => $code,
  170. 'entity_model' => $params['entity_model'],
  171. 'attribute_model' => $this->_getValue($params, 'attribute_model'),
  172. 'entity_table' => $this->_getValue($params, 'table', 'eav_entity'),
  173. 'value_table_prefix' => $this->_getValue($params, 'table_prefix'),
  174. 'entity_id_field' => $this->_getValue($params, 'id_field'),
  175. 'increment_model' => $this->_getValue($params, 'increment_model'),
  176. 'increment_per_store' => $this->_getValue($params, 'increment_per_store', 0),
  177. 'increment_pad_length' => $this->_getValue($params, 'increment_pad_length', 8),
  178. 'increment_pad_char' => $this->_getValue($params, 'increment_pad_char', 0),
  179. 'additional_attribute_table' => $this->_getValue($params, 'additional_attribute_table'),
  180. 'entity_attribute_collection' => $this->_getValue($params, 'entity_attribute_collection'),
  181. ];
  182. if (isset($params['entity_type_id'])) {
  183. $data['entity_type_id'] = $params['entity_type_id'];
  184. }
  185. if ($this->getEntityType($code, 'entity_type_id')) {
  186. $this->updateEntityType($code, $data);
  187. } else {
  188. $this->setup->getConnection()->insert(
  189. $this->setup->getTable('eav_entity_type'),
  190. $data
  191. );
  192. }
  193. if (isset($params['entity_type_id'])) {
  194. $this->addAttributeSet($code, $this->_defaultAttributeSetName, null, $params['entity_type_id']);
  195. } else {
  196. $this->addAttributeSet($code, $this->_defaultAttributeSetName);
  197. }
  198. $this->addAttributeGroup($code, $this->_defaultGroupName, $this->_generalGroupName);
  199. return $this;
  200. }
  201. /**
  202. * Update entity row
  203. *
  204. * @param string $code
  205. * @param string $field
  206. * @param string $value
  207. * @return $this
  208. */
  209. public function updateEntityType($code, $field, $value = null)
  210. {
  211. $this->setup->updateTableRow(
  212. 'eav_entity_type',
  213. 'entity_type_id',
  214. $this->getEntityTypeId($code),
  215. $field,
  216. $value
  217. );
  218. return $this;
  219. }
  220. /**
  221. * Retrieve Entity Type Data
  222. *
  223. * @param int|string $id
  224. * @param string $field
  225. * @return mixed
  226. */
  227. public function getEntityType($id, $field = null)
  228. {
  229. return $this->setup->getTableRow(
  230. 'eav_entity_type',
  231. is_numeric($id) ? 'entity_type_id' : 'entity_type_code',
  232. $id,
  233. $field
  234. );
  235. }
  236. /**
  237. * Retrieve Entity Type Id By Id or Code
  238. *
  239. * @param int|string $entityTypeId
  240. * @return int
  241. * @throws LocalizedException
  242. */
  243. public function getEntityTypeId($entityTypeId)
  244. {
  245. if (!is_numeric($entityTypeId)) {
  246. $entityTypeId = $this->getEntityType($entityTypeId, 'entity_type_id');
  247. }
  248. if (!is_numeric($entityTypeId)) {
  249. throw new LocalizedException(__('The entity ID is incorrect. Verify the ID and try again.'));
  250. }
  251. return $entityTypeId;
  252. }
  253. /**
  254. * Remove entity type by Id or Code
  255. *
  256. * @param int|string $id
  257. * @return $this
  258. */
  259. public function removeEntityType($id)
  260. {
  261. if (is_numeric($id)) {
  262. $this->setup->deleteTableRow('eav_entity_type', 'entity_type_id', $id);
  263. } else {
  264. $this->setup->deleteTableRow('eav_entity_type', 'entity_type_code', (string)$id);
  265. }
  266. return $this;
  267. }
  268. /******************* ATTRIBUTE SETS *****************/
  269. /**
  270. * Retrieve Attribute Set Sort order
  271. *
  272. * @param int|string $entityTypeId
  273. * @param int $sortOrder
  274. * @return int
  275. */
  276. public function getAttributeSetSortOrder($entityTypeId, $sortOrder = null)
  277. {
  278. if (!is_numeric($sortOrder)) {
  279. $bind = ['entity_type_id' => $this->getEntityTypeId($entityTypeId)];
  280. $select = $this->setup->getConnection()->select()->from(
  281. $this->setup->getTable('eav_attribute_set'),
  282. 'MAX(sort_order)'
  283. )->where(
  284. 'entity_type_id = :entity_type_id'
  285. );
  286. $sortOrder = $this->setup->getConnection()->fetchOne($select, $bind) + 1;
  287. }
  288. return $sortOrder;
  289. }
  290. /**
  291. * Add Attribute Set
  292. *
  293. * @param int|string $entityTypeId
  294. * @param string $name
  295. * @param int $sortOrder
  296. * @param int $setId
  297. * @return $this
  298. */
  299. public function addAttributeSet($entityTypeId, $name, $sortOrder = null, $setId = null)
  300. {
  301. $data = [
  302. 'entity_type_id' => $this->getEntityTypeId($entityTypeId),
  303. 'attribute_set_name' => $name,
  304. 'sort_order' => $this->getAttributeSetSortOrder($entityTypeId, $sortOrder),
  305. ];
  306. if ($setId !== null) {
  307. $data['attribute_set_id'] = $setId;
  308. }
  309. $setId = $this->getAttributeSet($entityTypeId, $name, 'attribute_set_id');
  310. if ($setId) {
  311. $this->updateAttributeSet($entityTypeId, $setId, $data);
  312. } else {
  313. $this->setup->getConnection()->insert(
  314. $this->setup->getTable('eav_attribute_set'),
  315. $data
  316. );
  317. $this->addAttributeGroup($entityTypeId, $name, $this->_generalGroupName);
  318. }
  319. return $this;
  320. }
  321. /**
  322. * Update attribute set data
  323. *
  324. * @param int|string $entityTypeId
  325. * @param int $id
  326. * @param string $field
  327. * @param mixed $value
  328. * @return $this
  329. */
  330. public function updateAttributeSet($entityTypeId, $id, $field, $value = null)
  331. {
  332. $this->setup->updateTableRow(
  333. 'eav_attribute_set',
  334. 'attribute_set_id',
  335. $this->getAttributeSetId($entityTypeId, $id),
  336. $field,
  337. $value,
  338. 'entity_type_id',
  339. $this->getEntityTypeId($entityTypeId)
  340. );
  341. return $this;
  342. }
  343. /**
  344. * Retrieve Attribute set data by id or name
  345. *
  346. * @param int|string $entityTypeId
  347. * @param int|string $id
  348. * @param string $field
  349. * @return mixed
  350. */
  351. public function getAttributeSet($entityTypeId, $id, $field = null)
  352. {
  353. return $this->setup->getTableRow(
  354. 'eav_attribute_set',
  355. is_numeric($id) ? 'attribute_set_id' : 'attribute_set_name',
  356. $id,
  357. $field,
  358. 'entity_type_id',
  359. $this->getEntityTypeId($entityTypeId)
  360. );
  361. }
  362. /**
  363. * Retrieve Attribute Set Id By Id or Name
  364. *
  365. * @param int|string $entityTypeId
  366. * @param int|string $setId
  367. * @return int
  368. * @throws LocalizedException
  369. */
  370. public function getAttributeSetId($entityTypeId, $setId)
  371. {
  372. if (!is_numeric($setId)) {
  373. $setId = $this->getAttributeSet($entityTypeId, $setId, 'attribute_set_id');
  374. }
  375. if (!is_numeric($setId)) {
  376. throw new LocalizedException(__('The attribute set ID is incorrect. Verify the ID and try again.'));
  377. }
  378. return $setId;
  379. }
  380. /**
  381. * Remove Attribute Set
  382. *
  383. * @param int|string $entityTypeId
  384. * @param int|string $id
  385. * @return $this
  386. */
  387. public function removeAttributeSet($entityTypeId, $id)
  388. {
  389. $this->setup->deleteTableRow(
  390. 'eav_attribute_set',
  391. 'attribute_set_id',
  392. $this->getAttributeSetId($entityTypeId, $id)
  393. );
  394. return $this;
  395. }
  396. /**
  397. * Set Default Attribute Set to Entity Type
  398. *
  399. * @param int|string $entityType
  400. * @param string $attributeSet
  401. * @return $this
  402. */
  403. public function setDefaultSetToEntityType($entityType, $attributeSet = 'Default')
  404. {
  405. $entityTypeId = $this->getEntityTypeId($entityType);
  406. $setId = $this->getAttributeSetId($entityTypeId, $attributeSet);
  407. $this->updateEntityType($entityTypeId, 'default_attribute_set_id', $setId);
  408. return $this;
  409. }
  410. /**
  411. * Get identifiers of all attribute sets
  412. *
  413. * @param int|string|null $entityTypeId
  414. * @return array
  415. */
  416. public function getAllAttributeSetIds($entityTypeId = null)
  417. {
  418. $select = $this->setup->getConnection()->select()
  419. ->from($this->setup->getTable('eav_attribute_set'), 'attribute_set_id');
  420. $bind = [];
  421. if ($entityTypeId !== null) {
  422. $bind['entity_type_id'] = $this->getEntityTypeId($entityTypeId);
  423. $select->where('entity_type_id = :entity_type_id');
  424. }
  425. return $this->setup->getConnection()->fetchCol($select, $bind);
  426. }
  427. /**
  428. * Retrieve Default Attribute Set for Entity Type
  429. *
  430. * @param string|int $entityType
  431. * @return int
  432. */
  433. public function getDefaultAttributeSetId($entityType)
  434. {
  435. $bind = ['entity_type' => $entityType];
  436. if (is_numeric($entityType)) {
  437. $where = 'entity_type_id = :entity_type';
  438. } else {
  439. $where = 'entity_type_code = :entity_type';
  440. }
  441. $select = $this->setup->getConnection()->select()->from(
  442. $this->setup->getTable('eav_entity_type'),
  443. 'default_attribute_set_id'
  444. )->where(
  445. $where
  446. );
  447. return $this->setup->getConnection()->fetchOne($select, $bind);
  448. }
  449. /******************* ATTRIBUTE GROUPS *****************/
  450. /**
  451. * Retrieve Attribute Group Sort order
  452. *
  453. * @param int|string $entityTypeId
  454. * @param int|string $setId
  455. * @param int $sortOrder
  456. * @return int
  457. */
  458. public function getAttributeGroupSortOrder($entityTypeId, $setId, $sortOrder = null)
  459. {
  460. if (!is_numeric($sortOrder)) {
  461. $bind = ['attribute_set_id' => $this->getAttributeSetId($entityTypeId, $setId)];
  462. $select = $this->setup->getConnection()->select()->from(
  463. $this->setup->getTable('eav_attribute_group'),
  464. 'MAX(sort_order)'
  465. )->where(
  466. 'attribute_set_id = :attribute_set_id'
  467. );
  468. $sortOrder = $this->setup->getConnection()->fetchOne($select, $bind) + 1;
  469. }
  470. return $sortOrder;
  471. }
  472. /**
  473. * Add Attribute Group
  474. *
  475. * @param int|string $entityTypeId
  476. * @param int|string $setId
  477. * @param string $name
  478. * @param int $sortOrder
  479. * @return $this
  480. */
  481. public function addAttributeGroup($entityTypeId, $setId, $name, $sortOrder = null)
  482. {
  483. $setId = $this->getAttributeSetId($entityTypeId, $setId);
  484. $data = ['attribute_set_id' => $setId, 'attribute_group_name' => $name];
  485. $attributeGroupCode = $this->convertToAttributeGroupCode($name);
  486. if (isset($this->defaultGroupIdAssociations[$attributeGroupCode])) {
  487. $data['default_id'] = $this->defaultGroupIdAssociations[$attributeGroupCode];
  488. }
  489. if ($sortOrder !== null) {
  490. $data['sort_order'] = $sortOrder;
  491. }
  492. $groupId = $this->getAttributeGroup($entityTypeId, $setId, $attributeGroupCode, 'attribute_group_id');
  493. if ($groupId) {
  494. $this->updateAttributeGroup($entityTypeId, $setId, $groupId, $data);
  495. } else {
  496. if ($sortOrder === null) {
  497. $data['sort_order'] = $this->getAttributeGroupSortOrder($entityTypeId, $setId, $sortOrder);
  498. }
  499. if (empty($data['attribute_group_code'])) {
  500. if (empty($attributeGroupCode)) {
  501. // in the following code md5 is not used for security purposes
  502. $attributeGroupCode = md5($name);
  503. }
  504. $data['attribute_group_code'] = $attributeGroupCode;
  505. }
  506. $this->setup->getConnection()->insert(
  507. $this->setup->getTable('eav_attribute_group'),
  508. $data
  509. );
  510. }
  511. return $this;
  512. }
  513. /**
  514. * @param string $groupName
  515. * @return string
  516. * @since 100.1.0
  517. */
  518. public function convertToAttributeGroupCode($groupName)
  519. {
  520. return trim(preg_replace('/[^a-z0-9]+/', '-', strtolower($groupName)), '-');
  521. }
  522. /**
  523. * Update Attribute Group Data
  524. *
  525. * @param int|string $entityTypeId
  526. * @param int|string $setId
  527. * @param int|string $id
  528. * @param string $field
  529. * @param mixed $value
  530. * @return $this
  531. */
  532. public function updateAttributeGroup($entityTypeId, $setId, $id, $field, $value = null)
  533. {
  534. $this->setup->updateTableRow(
  535. 'eav_attribute_group',
  536. 'attribute_group_id',
  537. $this->getAttributeGroupId($entityTypeId, $setId, $id),
  538. $field,
  539. $value,
  540. 'attribute_set_id',
  541. $this->getAttributeSetId($entityTypeId, $setId)
  542. );
  543. return $this;
  544. }
  545. /**
  546. * Retrieve Attribute Group Data
  547. *
  548. * @param int|string $entityTypeId
  549. * @param int|string $setId
  550. * @param int|string $id
  551. * @param string $field
  552. * @return mixed
  553. */
  554. public function getAttributeGroup($entityTypeId, $setId, $id, $field = null)
  555. {
  556. if (is_numeric($id)) {
  557. $searchField = 'attribute_group_id';
  558. } else {
  559. $id = $this->convertToAttributeGroupCode($id);
  560. if (isset($this->defaultGroupIdAssociations[$id])) {
  561. $searchField = 'default_id';
  562. $id = $this->defaultGroupIdAssociations[$id];
  563. } else {
  564. $searchField = 'attribute_group_code';
  565. }
  566. }
  567. return $this->setup->getTableRow(
  568. 'eav_attribute_group',
  569. $searchField,
  570. $id,
  571. $field,
  572. 'attribute_set_id',
  573. $this->getAttributeSetId($entityTypeId, $setId)
  574. );
  575. }
  576. /**
  577. * Retrieve Attribute Group Data by Code
  578. *
  579. * @param int|string $entityTypeId
  580. * @param int|string $setId
  581. * @param string $code
  582. * @param string $field
  583. * @return mixed
  584. * @since 100.1.0
  585. */
  586. public function getAttributeGroupByCode($entityTypeId, $setId, $code, $field = null)
  587. {
  588. return $this->setup->getTableRow(
  589. 'eav_attribute_group',
  590. 'attribute_group_code',
  591. $code,
  592. $field,
  593. 'attribute_set_id',
  594. $this->getAttributeSetId($entityTypeId, $setId)
  595. );
  596. }
  597. /**
  598. * Retrieve Attribute Group Id by Id or Name
  599. *
  600. * @param int|string $entityTypeId
  601. * @param int|string $setId
  602. * @param int|string $groupId
  603. * @return $this
  604. * @throws LocalizedException
  605. */
  606. public function getAttributeGroupId($entityTypeId, $setId, $groupId)
  607. {
  608. if (!is_numeric($groupId)) {
  609. $groupId = $this->getAttributeGroup($entityTypeId, $setId, $groupId, 'attribute_group_id');
  610. }
  611. if (!is_numeric($groupId)) {
  612. $groupId = $this->getDefaultAttributeGroupId($entityTypeId, $setId);
  613. }
  614. if (!is_numeric($groupId)) {
  615. throw new LocalizedException(__('The attribute group ID is incorrect. Verify the ID and try again.'));
  616. }
  617. return $groupId;
  618. }
  619. /**
  620. * Remove Attribute Group By Id or Name
  621. *
  622. * @param int|string $entityTypeId
  623. * @param int|string $setId
  624. * @param int|string $id
  625. * @return $this
  626. */
  627. public function removeAttributeGroup($entityTypeId, $setId, $id)
  628. {
  629. $this->setup->deleteTableRow(
  630. 'eav_attribute_group',
  631. 'attribute_group_id',
  632. $this->getAttributeGroupId($entityTypeId, $setId, $id)
  633. );
  634. return $this;
  635. }
  636. /**
  637. * Retrieve Default Attribute Group Id By Entity Type and Attribute Set
  638. *
  639. * @param string|int $entityType
  640. * @param int $attributeSetId
  641. * @return int
  642. */
  643. public function getDefaultAttributeGroupId($entityType, $attributeSetId = null)
  644. {
  645. $entityType = $this->getEntityTypeId($entityType);
  646. if (!is_numeric($attributeSetId)) {
  647. $attributeSetId = $this->getDefaultAttributeSetId($entityType);
  648. }
  649. $bind = ['attribute_set_id' => $attributeSetId];
  650. $select = $this->setup->getConnection()->select()->from(
  651. $this->setup->getTable('eav_attribute_group'),
  652. 'attribute_group_id'
  653. )->where(
  654. 'attribute_set_id = :attribute_set_id'
  655. )->order(
  656. ['default_id ' . \Magento\Framework\DB\Select::SQL_DESC, 'sort_order']
  657. )->limit(
  658. 1
  659. );
  660. return $this->setup->getConnection()->fetchOne($select, $bind);
  661. }
  662. /**
  663. * Get number of all attributes in group
  664. *
  665. * @param int|string $entityTypeId
  666. * @param int|string $setId
  667. * @param int|string $groupId
  668. *
  669. * @return string
  670. */
  671. public function getAttributesNumberInGroup($entityTypeId, $setId, $groupId)
  672. {
  673. $select = $this->setup->getConnection()->select()->from(
  674. $this->setup->getTable('eav_entity_attribute'),
  675. ['count' => 'COUNT(*)']
  676. )->where(
  677. 'attribute_group_id = ?',
  678. $this->getAttributeGroupId($entityTypeId, $setId, $groupId)
  679. )->where(
  680. 'entity_type_id = ?',
  681. $entityTypeId
  682. )->where(
  683. 'attribute_set_id = ?',
  684. $setId
  685. );
  686. return $this->setup->getConnection()->fetchOne($select);
  687. }
  688. /******************* ATTRIBUTES *****************/
  689. /**
  690. * Retrieve value from array by key or return default value
  691. *
  692. * @param array $array
  693. * @param string $key
  694. * @param string $default
  695. * @return string
  696. */
  697. private function _getValue($array, $key, $default = null)
  698. {
  699. if (isset($array[$key]) && is_bool($array[$key])) {
  700. $array[$key] = (int)$array[$key];
  701. }
  702. return isset($array[$key]) ? $array[$key] : $default;
  703. }
  704. /**
  705. * Validate attribute data before insert into table
  706. *
  707. * @param array $data
  708. * @return true
  709. * @throws LocalizedException
  710. */
  711. private function _validateAttributeData($data)
  712. {
  713. $minLength = \Magento\Eav\Model\Entity\Attribute::ATTRIBUTE_CODE_MIN_LENGTH;
  714. $maxLength = \Magento\Eav\Model\Entity\Attribute::ATTRIBUTE_CODE_MAX_LENGTH;
  715. $attributeCode = isset($data['attribute_code']) ? $data['attribute_code'] : '';
  716. $isAllowedLength = \Zend_Validate::is(
  717. trim($attributeCode),
  718. 'StringLength',
  719. ['min' => $minLength, 'max' => $maxLength]
  720. );
  721. if (!$isAllowedLength) {
  722. $errorMessage = __(
  723. 'An attribute code must not be less than %1 and more than %2 characters.',
  724. $minLength,
  725. $maxLength
  726. );
  727. throw new LocalizedException($errorMessage);
  728. }
  729. return true;
  730. }
  731. /**
  732. * Add attribute to an entity type
  733. *
  734. * If attribute is system will add to all existing attribute sets
  735. *
  736. * @param string|integer $entityTypeId
  737. * @param string $code
  738. * @param array $attr
  739. * @return $this
  740. */
  741. public function addAttribute($entityTypeId, $code, array $attr)
  742. {
  743. $entityTypeId = $this->getEntityTypeId($entityTypeId);
  744. $data = array_replace(
  745. ['entity_type_id' => $entityTypeId, 'attribute_code' => $code],
  746. $this->attributeMapper->map($attr, $entityTypeId)
  747. );
  748. $this->_validateAttributeData($data);
  749. $sortOrder = isset($attr['sort_order']) ? $attr['sort_order'] : null;
  750. $attributeId = $this->getAttribute($entityTypeId, $code, 'attribute_id');
  751. if ($attributeId) {
  752. $this->updateAttribute($entityTypeId, $attributeId, $data, null, $sortOrder);
  753. } else {
  754. $this->_insertAttribute($data);
  755. }
  756. if (!empty($attr['group']) || empty($attr['user_defined'])) {
  757. $select = $this->setup->getConnection()->select()->from(
  758. $this->setup->getTable('eav_attribute_set')
  759. )->where(
  760. 'entity_type_id = :entity_type_id'
  761. );
  762. $sets = $this->setup->getConnection()->fetchAll($select, ['entity_type_id' => $entityTypeId]);
  763. foreach ($sets as $set) {
  764. if (!empty($attr['group'])) {
  765. $this->addAttributeGroup($entityTypeId, $set['attribute_set_id'], $attr['group']);
  766. $this->addAttributeToSet(
  767. $entityTypeId,
  768. $set['attribute_set_id'],
  769. $attr['group'],
  770. $code,
  771. $sortOrder
  772. );
  773. } else {
  774. $this->addAttributeToSet(
  775. $entityTypeId,
  776. $set['attribute_set_id'],
  777. $this->_generalGroupName,
  778. $code,
  779. $sortOrder
  780. );
  781. }
  782. }
  783. }
  784. if (isset($attr['option']) && is_array($attr['option'])) {
  785. $option = $attr['option'];
  786. $option['attribute_id'] = $this->getAttributeId($entityTypeId, $code);
  787. $this->addAttributeOption($option);
  788. }
  789. return $this;
  790. }
  791. /**
  792. * Add Attribute Option
  793. *
  794. * @param array $option
  795. * @return void
  796. * @throws \Magento\Framework\Exception\LocalizedException
  797. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  798. */
  799. public function addAttributeOption($option)
  800. {
  801. $optionTable = $this->setup->getTable('eav_attribute_option');
  802. $optionValueTable = $this->setup->getTable('eav_attribute_option_value');
  803. if (isset($option['value'])) {
  804. foreach ($option['value'] as $optionId => $values) {
  805. $intOptionId = (int)$optionId;
  806. if (!empty($option['delete'][$optionId])) {
  807. if ($intOptionId) {
  808. $condition = ['option_id =?' => $intOptionId];
  809. $this->setup->getConnection()->delete($optionTable, $condition);
  810. }
  811. continue;
  812. }
  813. if (!$intOptionId) {
  814. $data = [
  815. 'attribute_id' => $option['attribute_id'],
  816. 'sort_order' => isset($option['order'][$optionId]) ? $option['order'][$optionId] : 0,
  817. ];
  818. $this->setup->getConnection()->insert($optionTable, $data);
  819. $intOptionId = $this->setup->getConnection()->lastInsertId($optionTable);
  820. } else {
  821. $data = [
  822. 'sort_order' => isset($option['order'][$optionId]) ? $option['order'][$optionId] : 0,
  823. ];
  824. $this->setup->getConnection()->update(
  825. $optionTable,
  826. $data,
  827. ['option_id=?' => $intOptionId]
  828. );
  829. }
  830. // Default value
  831. if (!isset($values[0])) {
  832. throw new \Magento\Framework\Exception\LocalizedException(
  833. __("The default option isn't defined. Set the option and try again.")
  834. );
  835. }
  836. $condition = ['option_id =?' => $intOptionId];
  837. $this->setup->getConnection()->delete($optionValueTable, $condition);
  838. foreach ($values as $storeId => $value) {
  839. $data = ['option_id' => $intOptionId, 'store_id' => $storeId, 'value' => $value];
  840. $this->setup->getConnection()->insert($optionValueTable, $data);
  841. }
  842. }
  843. } elseif (isset($option['values'])) {
  844. foreach ($option['values'] as $sortOrder => $label) {
  845. // add option
  846. $data = ['attribute_id' => $option['attribute_id'], 'sort_order' => $sortOrder];
  847. $this->setup->getConnection()->insert($optionTable, $data);
  848. $intOptionId = $this->setup->getConnection()->lastInsertId($optionTable);
  849. $data = ['option_id' => $intOptionId, 'store_id' => 0, 'value' => $label];
  850. $this->setup->getConnection()->insert($optionValueTable, $data);
  851. }
  852. }
  853. }
  854. /**
  855. * Update Attribute data and Attribute additional data
  856. *
  857. * @param int|string $entityTypeId
  858. * @param int|string $id
  859. * @param string|array $field
  860. * @param mixed $value
  861. * @param int $sortOrder
  862. * @return $this
  863. */
  864. public function updateAttribute($entityTypeId, $id, $field, $value = null, $sortOrder = null)
  865. {
  866. $this->_updateAttribute($entityTypeId, $id, $field, $value, $sortOrder);
  867. $this->_updateAttributeAdditionalData($entityTypeId, $id, $field, $value);
  868. return $this;
  869. }
  870. /**
  871. * Update Attribute data
  872. *
  873. * @param int|string $entityTypeId
  874. * @param int|string $id
  875. * @param string $field
  876. * @param mixed $value
  877. * @param int $sortOrder
  878. * @return $this
  879. * @throws LocalizedException
  880. */
  881. private function _updateAttribute($entityTypeId, $id, $field, $value = null, $sortOrder = null)
  882. {
  883. if ($sortOrder !== null) {
  884. $this->setup->updateTableRow(
  885. 'eav_entity_attribute',
  886. 'attribute_id',
  887. $this->getAttributeId($entityTypeId, $id),
  888. 'sort_order',
  889. $sortOrder
  890. );
  891. }
  892. $attributeFields = $this->_getAttributeTableFields();
  893. if (is_array($field)) {
  894. $bind = [];
  895. foreach ($field as $k => $v) {
  896. if (isset($attributeFields[$k])) {
  897. $bind[$k] = $this->setup->getConnection()->prepareColumnValue(
  898. $attributeFields[$k],
  899. $v
  900. );
  901. }
  902. }
  903. if (!$bind) {
  904. return $this;
  905. }
  906. $field = $bind;
  907. } else {
  908. if (!isset($attributeFields[$field])) {
  909. return $this;
  910. }
  911. }
  912. $attributeId = $this->getAttributeId($entityTypeId, $id);
  913. if (false === $attributeId) {
  914. throw new LocalizedException(__('Attribute with ID: "%1" does not exist', $id));
  915. }
  916. $this->setup->updateTableRow(
  917. 'eav_attribute',
  918. 'attribute_id',
  919. $attributeId,
  920. $field,
  921. $value,
  922. 'entity_type_id',
  923. $this->getEntityTypeId($entityTypeId)
  924. );
  925. return $this;
  926. }
  927. /**
  928. * Update Attribute Additional data
  929. *
  930. * @param int|string $entityTypeId
  931. * @param int|string $id
  932. * @param string|array $field
  933. * @param mixed $value
  934. * @return $this
  935. * @throws LocalizedException
  936. */
  937. private function _updateAttributeAdditionalData($entityTypeId, $id, $field, $value = null)
  938. {
  939. $additionalTable = $this->getEntityType($entityTypeId, 'additional_attribute_table');
  940. if (!$additionalTable) {
  941. return $this;
  942. }
  943. $additionalTableExists = $this->setup->getConnection()->isTableExists(
  944. $this->setup->getTable($additionalTable)
  945. );
  946. if (!$additionalTableExists) {
  947. return $this;
  948. }
  949. $attributeFields = $this->setup->getConnection()->describeTable(
  950. $this->setup->getTable($additionalTable)
  951. );
  952. if (is_array($field)) {
  953. $bind = [];
  954. foreach ($field as $k => $v) {
  955. if (isset($attributeFields[$k])) {
  956. $bind[$k] = $this->setup->getConnection()->prepareColumnValue(
  957. $attributeFields[$k],
  958. $v
  959. );
  960. }
  961. }
  962. if (!$bind) {
  963. return $this;
  964. }
  965. $field = $bind;
  966. } else {
  967. if (!isset($attributeFields[$field])) {
  968. return $this;
  969. }
  970. }
  971. $attributeId = $this->getAttributeId($entityTypeId, $id);
  972. if (false === $attributeId) {
  973. throw new LocalizedException(__('Attribute with ID: "%1" does not exist', $id));
  974. }
  975. $this->setup->updateTableRow(
  976. $this->setup->getTable($additionalTable),
  977. 'attribute_id',
  978. $this->getAttributeId($entityTypeId, $id),
  979. $field,
  980. $value
  981. );
  982. $attribute = $this->getAttribute($entityTypeId, $id);
  983. $this->updateCachedRow($field, $value, $attribute);
  984. return $this;
  985. }
  986. /**
  987. * Updates cache for the row
  988. *
  989. * @param string|array $field
  990. * @param mixed $value
  991. * @param array $attribute
  992. *
  993. * @return void
  994. */
  995. private function updateCachedRow($field, $value, $attribute)
  996. {
  997. $setupCache = $this->setup->getSetupCache();
  998. $mainTable = $this->setup->getTable('eav_attribute');
  999. if (is_array($field)) {
  1000. $oldRow = $setupCache->has($mainTable, $attribute['entity_type_id'], $attribute['attribute_code']) ?
  1001. $setupCache->get($mainTable, $attribute['entity_type_id'], $attribute['attribute_code']) :
  1002. [];
  1003. $newRowData = array_merge($oldRow, $field);
  1004. $setupCache->setRow(
  1005. $mainTable,
  1006. $attribute['entity_type_id'],
  1007. $attribute['attribute_code'],
  1008. $newRowData
  1009. );
  1010. } else {
  1011. $setupCache->setField(
  1012. $mainTable,
  1013. $attribute['entity_type_id'],
  1014. $attribute['attribute_code'],
  1015. $field,
  1016. $value
  1017. );
  1018. }
  1019. }
  1020. /**
  1021. * Retrieve Attribute Data By Id or Code
  1022. *
  1023. * @param int|string $entityTypeId
  1024. * @param int|string $id
  1025. * @param string $field
  1026. * @return mixed
  1027. */
  1028. public function getAttribute($entityTypeId, $id, $field = null)
  1029. {
  1030. $additionalTable = $this->getEntityType($entityTypeId, 'additional_attribute_table');
  1031. $entityTypeId = $this->getEntityTypeId($entityTypeId);
  1032. $idField = is_numeric($id) ? 'attribute_id' : 'attribute_code';
  1033. if (!$additionalTable) {
  1034. return $this->setup->getTableRow('eav_attribute', $idField, $id, $field, 'entity_type_id', $entityTypeId);
  1035. }
  1036. $mainTable = $this->setup->getTable('eav_attribute');
  1037. $setupCache = $this->setup->getSetupCache();
  1038. if (!$setupCache->has($mainTable, $entityTypeId, $id)) {
  1039. $additionalTable = $this->setup->getTable($additionalTable);
  1040. $bind = ['id' => $id, 'entity_type_id' => $entityTypeId];
  1041. $select = $this->setup->getConnection()->select()->from(
  1042. ['main' => $mainTable]
  1043. )->join(
  1044. ['additional' => $additionalTable],
  1045. 'main.attribute_id = additional.attribute_id'
  1046. )->where(
  1047. "main.{$idField} = :id"
  1048. )->where(
  1049. 'main.entity_type_id = :entity_type_id'
  1050. );
  1051. $row = $this->setup->getConnection()->fetchRow($select, $bind);
  1052. if (!$row) {
  1053. $setupCache->setRow($mainTable, $entityTypeId, $id, []);
  1054. } else {
  1055. $setupCache->setRow($mainTable, $entityTypeId, $row['attribute_id'], $row);
  1056. $setupCache->setRow($mainTable, $entityTypeId, $row['attribute_code'], $row);
  1057. }
  1058. }
  1059. $row = $setupCache->get($mainTable, $entityTypeId, $id);
  1060. if ($field !== null) {
  1061. return isset($row[$field]) ? $row[$field] : false;
  1062. }
  1063. return $row;
  1064. }
  1065. /**
  1066. * Retrieve Attribute Id Data By Id or Code
  1067. *
  1068. * @param int|string $entityTypeId
  1069. * @param int|string $id
  1070. * @return int
  1071. */
  1072. public function getAttributeId($entityTypeId, $id)
  1073. {
  1074. if (!is_numeric($id)) {
  1075. $id = $this->getAttribute($entityTypeId, $id, 'attribute_id');
  1076. }
  1077. if (!is_numeric($id)) {
  1078. return false;
  1079. }
  1080. return $id;
  1081. }
  1082. /**
  1083. * Return table name for eav attribute
  1084. *
  1085. * @param int|string $entityTypeId Entity Type id or Entity Type code
  1086. * @param int|string $id Attribute id or Attribute code
  1087. * @return string
  1088. */
  1089. public function getAttributeTable($entityTypeId, $id)
  1090. {
  1091. $entityKeyName = is_numeric($entityTypeId) ? 'entity_type_id' : 'entity_type_code';
  1092. $attributeKeyName = is_numeric($id) ? 'attribute_id' : 'attribute_code';
  1093. $bind = ['id' => $id, 'entity_type_id' => $entityTypeId];
  1094. $select = $this->setup->getConnection()->select()->from(
  1095. ['entity_type' => $this->setup->getTable('eav_entity_type')],
  1096. ['entity_table']
  1097. )->join(
  1098. ['attribute' => $this->setup->getTable('eav_attribute')],
  1099. 'attribute.entity_type_id = entity_type.entity_type_id',
  1100. ['backend_type']
  1101. )->where(
  1102. "entity_type.{$entityKeyName} = :entity_type_id"
  1103. )->where(
  1104. "attribute.{$attributeKeyName} = :id"
  1105. )->limit(
  1106. 1
  1107. );
  1108. $result = $this->setup->getConnection()->fetchRow($select, $bind);
  1109. if ($result) {
  1110. $table = $this->setup->getTable($result['entity_table']);
  1111. if ($result['backend_type'] != 'static') {
  1112. $table .= '_' . $result['backend_type'];
  1113. }
  1114. return $table;
  1115. }
  1116. return false;
  1117. }
  1118. /**
  1119. * Remove Attribute
  1120. *
  1121. * @param int|string $entityTypeId
  1122. * @param int|string $code
  1123. * @return $this
  1124. */
  1125. public function removeAttribute($entityTypeId, $code)
  1126. {
  1127. $mainTable = $this->setup->getTable('eav_attribute');
  1128. $attribute = $this->getAttribute($entityTypeId, $code);
  1129. if ($attribute) {
  1130. $this->setup->deleteTableRow('eav_attribute', 'attribute_id', $attribute['attribute_id']);
  1131. $setupCache = $this->setup->getSetupCache();
  1132. if ($setupCache->has($mainTable, $attribute['entity_type_id'], $attribute['attribute_code'])) {
  1133. $setupCache->remove($mainTable, $attribute['entity_type_id'], $attribute['attribute_code']);
  1134. }
  1135. }
  1136. return $this;
  1137. }
  1138. /**
  1139. * Retrieve Attribute Sort Order
  1140. *
  1141. * @param int|string $entityTypeId
  1142. * @param int|string $setId
  1143. * @param int|string $groupId
  1144. * @param int $sortOrder
  1145. * @return $this
  1146. */
  1147. public function getAttributeSortOrder($entityTypeId, $setId, $groupId, $sortOrder = null)
  1148. {
  1149. if (!is_numeric($sortOrder)) {
  1150. $bind = ['attribute_group_id' => $this->getAttributeGroupId($entityTypeId, $setId, $groupId)];
  1151. $select = $this->setup->getConnection()->select()->from(
  1152. $this->setup->getTable('eav_entity_attribute'),
  1153. 'MAX(sort_order)'
  1154. )->where(
  1155. 'attribute_group_id = :attribute_group_id'
  1156. );
  1157. $sortOrder = $this->setup->getConnection()->fetchOne($select, $bind) + 1;
  1158. }
  1159. return $sortOrder;
  1160. }
  1161. /**
  1162. * Add Attribute to All Groups on Attribute Set
  1163. *
  1164. * @param int|string $entityTypeId
  1165. * @param int|string $setId
  1166. * @param int|string $groupId
  1167. * @param int|string $attributeId
  1168. * @param int $sortOrder
  1169. * @return $this
  1170. */
  1171. public function addAttributeToSet($entityTypeId, $setId, $groupId, $attributeId, $sortOrder = null)
  1172. {
  1173. $entityTypeId = $this->getEntityTypeId($entityTypeId);
  1174. $setId = $this->getAttributeSetId($entityTypeId, $setId);
  1175. $groupId = $this->getAttributeGroupId($entityTypeId, $setId, $groupId);
  1176. $attributeId = $this->getAttributeId($entityTypeId, $attributeId);
  1177. $table = $this->setup->getTable('eav_entity_attribute');
  1178. $bind = ['attribute_set_id' => $setId, 'attribute_id' => $attributeId];
  1179. $select = $this->setup->getConnection()->select()->from(
  1180. $table
  1181. )->where(
  1182. 'attribute_set_id = :attribute_set_id'
  1183. )->where(
  1184. 'attribute_id = :attribute_id'
  1185. );
  1186. $result = $this->setup->getConnection()->fetchRow($select, $bind);
  1187. if ($result) {
  1188. if ($result['attribute_group_id'] != $groupId) {
  1189. $where = ['entity_attribute_id =?' => $result['entity_attribute_id']];
  1190. $data = ['attribute_group_id' => $groupId];
  1191. $this->setup->getConnection()->update($table, $data, $where);
  1192. }
  1193. } else {
  1194. $data = [
  1195. 'entity_type_id' => $entityTypeId,
  1196. 'attribute_set_id' => $setId,
  1197. 'attribute_group_id' => $groupId,
  1198. 'attribute_id' => $attributeId,
  1199. 'sort_order' => $this->getAttributeSortOrder($entityTypeId, $setId, $groupId, $sortOrder),
  1200. ];
  1201. $this->setup->getConnection()->insert($table, $data);
  1202. }
  1203. return $this;
  1204. }
  1205. /**
  1206. * Add or update attribute to group
  1207. *
  1208. * @param int|string $entityType
  1209. * @param int|string $setId
  1210. * @param int|string $groupId
  1211. * @param int|string $attributeId
  1212. * @param int $sortOrder
  1213. * @return $this
  1214. */
  1215. public function addAttributeToGroup($entityType, $setId, $groupId, $attributeId, $sortOrder = null)
  1216. {
  1217. $entityType = $this->getEntityTypeId($entityType);
  1218. $setId = $this->getAttributeSetId($entityType, $setId);
  1219. $groupId = $this->getAttributeGroupId($entityType, $setId, $groupId);
  1220. $attributeId = $this->getAttributeId($entityType, $attributeId);
  1221. $data = [
  1222. 'entity_type_id' => $entityType,
  1223. 'attribute_set_id' => $setId,
  1224. 'attribute_group_id' => $groupId,
  1225. 'attribute_id' => $attributeId,
  1226. ];
  1227. $bind = ['entity_type_id' => $entityType, 'attribute_set_id' => $setId, 'attribute_id' => $attributeId];
  1228. $select = $this->setup->getConnection()->select()->from(
  1229. $this->setup->getTable('eav_entity_attribute')
  1230. )->where(
  1231. 'entity_type_id = :entity_type_id'
  1232. )->where(
  1233. 'attribute_set_id = :attribute_set_id'
  1234. )->where(
  1235. 'attribute_id = :attribute_id'
  1236. );
  1237. $row = $this->setup->getConnection()->fetchRow($select, $bind);
  1238. if ($row) {
  1239. // update
  1240. if ($sortOrder !== null) {
  1241. $data['sort_order'] = $sortOrder;
  1242. }
  1243. $this->setup->getConnection()->update(
  1244. $this->setup->getTable('eav_entity_attribute'),
  1245. $data,
  1246. $this->setup->getConnection()->quoteInto('entity_attribute_id=?', $row['entity_attribute_id'])
  1247. );
  1248. } else {
  1249. if ($sortOrder === null) {
  1250. $select = $this->setup->getConnection()->select()->from(
  1251. $this->setup->getTable('eav_entity_attribute'),
  1252. 'MAX(sort_order)'
  1253. )->where(
  1254. 'entity_type_id = :entity_type_id'
  1255. )->where(
  1256. 'attribute_set_id = :attribute_set_id'
  1257. )->where(
  1258. 'attribute_id = :attribute_id'
  1259. );
  1260. $sortOrder = $this->setup->getConnection()->fetchOne($select, $bind) + 10;
  1261. }
  1262. $sortOrder = is_numeric($sortOrder) ? $sortOrder : 1;
  1263. $data['sort_order'] = $sortOrder;
  1264. $this->setup->getConnection()->insert(
  1265. $this->setup->getTable('eav_entity_attribute'),
  1266. $data
  1267. );
  1268. }
  1269. return $this;
  1270. }
  1271. /******************* BULK INSTALL *****************/
  1272. /**
  1273. * Gets default entities and attributes
  1274. *
  1275. * @return array
  1276. */
  1277. public function getDefaultEntities()
  1278. {
  1279. return [];
  1280. }
  1281. /**
  1282. * Install entities
  1283. *
  1284. * @param array $entities
  1285. * @return $this
  1286. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  1287. * @SuppressWarnings(PHPMD.NPathComplexity)
  1288. */
  1289. public function installEntities($entities = null)
  1290. {
  1291. $this->cleanCache();
  1292. if ($entities === null) {
  1293. $entities = $this->getDefaultEntities();
  1294. }
  1295. foreach ($entities as $entityName => $entity) {
  1296. $this->addEntityType($entityName, $entity);
  1297. $frontendPrefix = isset($entity['frontend_prefix']) ? $entity['frontend_prefix'] : '';
  1298. $backendPrefix = isset($entity['backend_prefix']) ? $entity['backend_prefix'] : '';
  1299. $sourcePrefix = isset($entity['source_prefix']) ? $entity['source_prefix'] : '';
  1300. if (is_array($entity['attributes']) && !empty($entity['attributes'])) {
  1301. foreach ($entity['attributes'] as $attrCode => $attr) {
  1302. if (!empty($attr['backend'])) {
  1303. if ('_' === $attr['backend']) {
  1304. $attr['backend'] = $backendPrefix;
  1305. } elseif ('_' === $attr['backend'][0]) {
  1306. $attr['backend'] = $backendPrefix . $attr['backend'];
  1307. }
  1308. }
  1309. if (!empty($attr['frontend'])) {
  1310. if ('_' === $attr['frontend']) {
  1311. $attr['frontend'] = $frontendPrefix;
  1312. } elseif ('_' === $attr['frontend'][0]) {
  1313. $attr['frontend'] = $frontendPrefix . $attr['frontend'];
  1314. }
  1315. }
  1316. if (!empty($attr['source'])) {
  1317. if ('_' === $attr['source']) {
  1318. $attr['source'] = $sourcePrefix;
  1319. } elseif ('_' === $attr['source'][0]) {
  1320. $attr['source'] = $sourcePrefix . $attr['source'];
  1321. }
  1322. }
  1323. $this->addAttribute($entityName, $attrCode, $attr);
  1324. }
  1325. }
  1326. $this->setDefaultSetToEntityType($entityName);
  1327. }
  1328. return $this;
  1329. }
  1330. /**
  1331. * Retrieve attribute table fields
  1332. *
  1333. * @return array
  1334. */
  1335. private function _getAttributeTableFields()
  1336. {
  1337. return $this->setup->getConnection()->describeTable(
  1338. $this->setup->getTable('eav_attribute')
  1339. );
  1340. }
  1341. /**
  1342. * Insert attribute and filter data
  1343. *
  1344. * @param array $data
  1345. * @return $this
  1346. */
  1347. private function _insertAttribute(array $data)
  1348. {
  1349. $bind = [];
  1350. $fields = $this->_getAttributeTableFields();
  1351. foreach ($data as $k => $v) {
  1352. if (isset($fields[$k])) {
  1353. $bind[$k] = $this->setup->getConnection()->prepareColumnValue($fields[$k], $v);
  1354. }
  1355. }
  1356. if (!$bind) {
  1357. return $this;
  1358. }
  1359. $this->setup->getConnection()->insert(
  1360. $this->setup->getTable('eav_attribute'),
  1361. $bind
  1362. );
  1363. $attributeId = $this->setup->getConnection()->lastInsertId(
  1364. $this->setup->getTable('eav_attribute')
  1365. );
  1366. $this->_insertAttributeAdditionalData(
  1367. $data['entity_type_id'],
  1368. array_merge(['attribute_id' => $attributeId], $data)
  1369. );
  1370. return $this;
  1371. }
  1372. /**
  1373. * Insert attribute additional data
  1374. *
  1375. * @param int|string $entityTypeId
  1376. * @param array $data
  1377. * @return $this
  1378. */
  1379. private function _insertAttributeAdditionalData($entityTypeId, array $data)
  1380. {
  1381. $additionalTable = $this->getEntityType($entityTypeId, 'additional_attribute_table');
  1382. if (!$additionalTable) {
  1383. return $this;
  1384. }
  1385. $additionalTableExists = $this->setup->getConnection()->isTableExists(
  1386. $this->setup->getTable($additionalTable)
  1387. );
  1388. if ($additionalTable && $additionalTableExists) {
  1389. $bind = [];
  1390. $fields = $this->setup->getConnection()->describeTable(
  1391. $this->setup->getTable($additionalTable)
  1392. );
  1393. foreach ($data as $k => $v) {
  1394. if (isset($fields[$k])) {
  1395. $bind[$k] = $this->setup->getConnection()->prepareColumnValue($fields[$k], $v);
  1396. }
  1397. }
  1398. if (!$bind) {
  1399. return $this;
  1400. }
  1401. $this->setup->getConnection()->insert(
  1402. $this->setup->getTable($additionalTable),
  1403. $bind
  1404. );
  1405. }
  1406. return $this;
  1407. }
  1408. }