PageRenderTime 30ms CodeModel.GetById 0ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/magento/module-catalog/Model/Indexer/Category/Flat/AbstractAction.php

https://gitlab.com/yousafsyed/easternglamor
PHP | 450 lines | 360 code | 22 blank | 68 comment | 7 complexity | 690606fc9509e4802134c393d588e9be MD5 | raw file
  1. <?php
  2. /**
  3. * Copyright © 2016 Magento. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. // @codingStandardsIgnoreFile
  7. namespace Magento\Catalog\Model\Indexer\Category\Flat;
  8. use Magento\Framework\App\ResourceConnection;
  9. class AbstractAction
  10. {
  11. /**
  12. * Suffix for table to show it is temporary
  13. */
  14. const TEMPORARY_TABLE_SUFFIX = '_tmp';
  15. /**
  16. * Attribute codes
  17. *
  18. * @var array
  19. */
  20. protected $attributeCodes;
  21. /**
  22. * @var Resource
  23. */
  24. protected $resource;
  25. /**
  26. * @var \Magento\Store\Model\StoreManagerInterface
  27. */
  28. protected $storeManager;
  29. /**
  30. * Catalog resource helper
  31. *
  32. * @var \Magento\Catalog\Model\ResourceModel\Helper
  33. */
  34. protected $resourceHelper;
  35. /**
  36. * Flat columns
  37. *
  38. * @var array
  39. */
  40. protected $columns = [];
  41. /**
  42. * @var \Magento\Framework\DB\Adapter\AdapterInterface
  43. */
  44. protected $connection;
  45. /**
  46. * @param ResourceConnection $resource
  47. * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  48. * @param \Magento\Catalog\Model\ResourceModel\Helper $resourceHelper
  49. */
  50. public function __construct(
  51. ResourceConnection $resource,
  52. \Magento\Store\Model\StoreManagerInterface $storeManager,
  53. \Magento\Catalog\Model\ResourceModel\Helper $resourceHelper
  54. ) {
  55. $this->resource = $resource;
  56. $this->connection = $resource->getConnection();
  57. $this->storeManager = $storeManager;
  58. $this->resourceHelper = $resourceHelper;
  59. $this->columns = array_merge($this->getStaticColumns(), $this->getEavColumns());
  60. }
  61. /**
  62. * Add suffix to table name to show it is temporary
  63. *
  64. * @param string $tableName
  65. * @return string
  66. */
  67. protected function addTemporaryTableSuffix($tableName)
  68. {
  69. return $tableName . self::TEMPORARY_TABLE_SUFFIX;
  70. }
  71. /**
  72. * Retrieve list of columns for flat structure
  73. *
  74. * @return array
  75. */
  76. public function getColumns()
  77. {
  78. return $this->columns;
  79. }
  80. /**
  81. * Return name of table for given $storeId.
  82. *
  83. * @param integer $storeId
  84. * @return string
  85. */
  86. public function getMainStoreTable($storeId = \Magento\Store\Model\Store::DEFAULT_STORE_ID)
  87. {
  88. if (is_string($storeId)) {
  89. $storeId = intval($storeId);
  90. }
  91. $suffix = sprintf('store_%d', $storeId);
  92. $table = $this->connection->getTableName($this->getTableName('catalog_category_flat_' . $suffix));
  93. return $table;
  94. }
  95. /**
  96. * Return structure for flat catalog table
  97. *
  98. * @param string $tableName
  99. * @return \Magento\Framework\DB\Ddl\Table
  100. */
  101. protected function getFlatTableStructure($tableName)
  102. {
  103. $table = $this->connection->newTable(
  104. $tableName
  105. )->setComment(
  106. sprintf("Catalog Category Flat", $tableName)
  107. );
  108. //Adding columns
  109. foreach ($this->getColumns() as $fieldName => $fieldProp) {
  110. $default = $fieldProp['default'];
  111. if ($fieldProp['type'][0] == \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP && $default == 'CURRENT_TIMESTAMP') {
  112. $default = \Magento\Framework\DB\Ddl\Table::TIMESTAMP_INIT;
  113. }
  114. $table->addColumn(
  115. $fieldName,
  116. $fieldProp['type'][0],
  117. $fieldProp['type'][1],
  118. [
  119. 'nullable' => $fieldProp['nullable'],
  120. 'unsigned' => $fieldProp['unsigned'],
  121. 'default' => $default,
  122. 'primary' => isset($fieldProp['primary']) ? $fieldProp['primary'] : false
  123. ],
  124. $fieldProp['comment'] != '' ? $fieldProp['comment'] : ucwords(str_replace('_', ' ', $fieldName))
  125. );
  126. }
  127. // Adding indexes
  128. $table->addIndex(
  129. $this->connection->getIndexName($tableName, ['entity_id']),
  130. ['entity_id'],
  131. ['type' => 'primary']
  132. );
  133. $table->addIndex(
  134. $this->connection->getIndexName($tableName, ['store_id']),
  135. ['store_id'],
  136. ['type' => 'index']
  137. );
  138. $table->addIndex(
  139. $this->connection->getIndexName($tableName, ['path']),
  140. ['path'],
  141. ['type' => 'index']
  142. );
  143. $table->addIndex(
  144. $this->connection->getIndexName($tableName, ['level']),
  145. ['level'],
  146. ['type' => 'index']
  147. );
  148. return $table;
  149. }
  150. /**
  151. * Return array of static columns
  152. *
  153. * @return array
  154. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  155. */
  156. protected function getStaticColumns()
  157. {
  158. $columns = [];
  159. $columnsToSkip = ['entity_type_id', 'attribute_set_id'];
  160. $describe = $this->connection->describeTable(
  161. $this->connection->getTableName($this->getTableName('catalog_category_entity'))
  162. );
  163. foreach ($describe as $column) {
  164. if (in_array($column['COLUMN_NAME'], $columnsToSkip)) {
  165. continue;
  166. }
  167. $isUnsigned = '';
  168. $options = null;
  169. $ddlType = $this->resourceHelper->getDdlTypeByColumnType($column['DATA_TYPE']);
  170. $column['DEFAULT'] = trim($column['DEFAULT'], "' ");
  171. switch ($ddlType) {
  172. case \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT:
  173. case \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER:
  174. case \Magento\Framework\DB\Ddl\Table::TYPE_BIGINT:
  175. $isUnsigned = (bool)$column['UNSIGNED'];
  176. if ($column['DEFAULT'] === '') {
  177. $column['DEFAULT'] = null;
  178. }
  179. $options = null;
  180. if ($column['SCALE'] > 0) {
  181. $ddlType = \Magento\Framework\DB\Ddl\Table::TYPE_DECIMAL;
  182. } else {
  183. break;
  184. }
  185. // fall-through intentional
  186. case \Magento\Framework\DB\Ddl\Table::TYPE_DECIMAL:
  187. $options = $column['PRECISION'] . ',' . $column['SCALE'];
  188. $isUnsigned = null;
  189. if ($column['DEFAULT'] === '') {
  190. $column['DEFAULT'] = null;
  191. }
  192. break;
  193. case \Magento\Framework\DB\Ddl\Table::TYPE_TEXT:
  194. $options = $column['LENGTH'];
  195. $isUnsigned = null;
  196. break;
  197. case \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP:
  198. $options = null;
  199. $isUnsigned = null;
  200. break;
  201. case \Magento\Framework\DB\Ddl\Table::TYPE_DATETIME:
  202. $isUnsigned = null;
  203. break;
  204. }
  205. $columns[$column['COLUMN_NAME']] = [
  206. 'type' => [$ddlType, $options],
  207. 'unsigned' => $isUnsigned,
  208. 'nullable' => $column['NULLABLE'],
  209. 'default' => $column['DEFAULT'] === null ? false : $column['DEFAULT'],
  210. 'comment' => $column['COLUMN_NAME'],
  211. ];
  212. }
  213. $columns['store_id'] = [
  214. 'type' => [\Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, 5],
  215. 'unsigned' => true,
  216. 'nullable' => false,
  217. 'default' => '0',
  218. 'comment' => 'Store Id',
  219. ];
  220. return $columns;
  221. }
  222. /**
  223. * Return array of eav columns, skip attribute with static type
  224. *
  225. * @return array
  226. */
  227. protected function getEavColumns()
  228. {
  229. $columns = [];
  230. foreach ($this->getAttributes() as $attribute) {
  231. if ($attribute['backend_type'] == 'static') {
  232. continue;
  233. }
  234. $columns[$attribute['attribute_code']] = [];
  235. switch ($attribute['backend_type']) {
  236. case 'varchar':
  237. $columns[$attribute['attribute_code']] = [
  238. 'type' => [\Magento\Framework\DB\Ddl\Table::TYPE_TEXT, 255],
  239. 'unsigned' => null,
  240. 'nullable' => true,
  241. 'default' => null,
  242. 'comment' => (string)$attribute['frontend_label'],
  243. ];
  244. break;
  245. case 'int':
  246. $columns[$attribute['attribute_code']] = [
  247. 'type' => [\Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null],
  248. 'unsigned' => null,
  249. 'nullable' => true,
  250. 'default' => null,
  251. 'comment' => (string)$attribute['frontend_label'],
  252. ];
  253. break;
  254. case 'text':
  255. $columns[$attribute['attribute_code']] = [
  256. 'type' => [\Magento\Framework\DB\Ddl\Table::TYPE_TEXT, '64k'],
  257. 'unsigned' => null,
  258. 'nullable' => true,
  259. 'default' => null,
  260. 'comment' => (string)$attribute['frontend_label'],
  261. ];
  262. break;
  263. case 'datetime':
  264. $columns[$attribute['attribute_code']] = [
  265. 'type' => [\Magento\Framework\DB\Ddl\Table::TYPE_DATETIME, null],
  266. 'unsigned' => null,
  267. 'nullable' => true,
  268. 'default' => null,
  269. 'comment' => (string)$attribute['frontend_label'],
  270. ];
  271. break;
  272. case 'decimal':
  273. $columns[$attribute['attribute_code']] = [
  274. 'type' => [\Magento\Framework\DB\Ddl\Table::TYPE_DECIMAL, '12,4'],
  275. 'unsigned' => null,
  276. 'nullable' => true,
  277. 'default' => null,
  278. 'comment' => (string)$attribute['frontend_label'],
  279. ];
  280. break;
  281. }
  282. }
  283. return $columns;
  284. }
  285. /**
  286. * Return array of attribute codes for entity type 'catalog_category'
  287. *
  288. * @return array
  289. */
  290. protected function getAttributes()
  291. {
  292. if ($this->attributeCodes === null) {
  293. $select = $this->connection->select()->from(
  294. $this->connection->getTableName($this->getTableName('eav_entity_type')),
  295. []
  296. )->join(
  297. $this->connection->getTableName($this->getTableName('eav_attribute')),
  298. $this->connection->getTableName(
  299. $this->getTableName('eav_attribute')
  300. ) . '.entity_type_id = ' . $this->connection->getTableName(
  301. $this->getTableName('eav_entity_type')
  302. ) . '.entity_type_id',
  303. $this->connection->getTableName($this->getTableName('eav_attribute')) . '.*'
  304. )->where(
  305. $this->connection->getTableName(
  306. $this->getTableName('eav_entity_type')
  307. ) . '.entity_type_code = ?',
  308. \Magento\Catalog\Model\Category::ENTITY
  309. );
  310. $this->attributeCodes = [];
  311. foreach ($this->connection->fetchAll($select) as $attribute) {
  312. $this->attributeCodes[$attribute['attribute_id']] = $attribute;
  313. }
  314. }
  315. return $this->attributeCodes;
  316. }
  317. /**
  318. * Return attribute values for given entities and store
  319. *
  320. * @param array $entityIds
  321. * @param integer $storeId
  322. * @return array
  323. */
  324. protected function getAttributeValues($entityIds, $storeId)
  325. {
  326. if (!is_array($entityIds)) {
  327. $entityIds = [$entityIds];
  328. }
  329. $values = [];
  330. foreach ($entityIds as $entityId) {
  331. $values[$entityId] = [];
  332. }
  333. $attributes = $this->getAttributes();
  334. $attributesType = ['varchar', 'int', 'decimal', 'text', 'datetime'];
  335. foreach ($attributesType as $type) {
  336. foreach ($this->getAttributeTypeValues($type, $entityIds, $storeId) as $row) {
  337. if (isset($row['entity_id']) && isset($row['attribute_id'])) {
  338. $attributeId = $row['attribute_id'];
  339. if (isset($attributes[$attributeId])) {
  340. $attributeCode = $attributes[$attributeId]['attribute_code'];
  341. $values[$row['entity_id']][$attributeCode] = $row['value'];
  342. }
  343. }
  344. }
  345. }
  346. return $values;
  347. }
  348. /**
  349. * Return attribute values for given entities and store of specific attribute type
  350. *
  351. * @param string $type
  352. * @param array $entityIds
  353. * @param integer $storeId
  354. * @return array
  355. */
  356. protected function getAttributeTypeValues($type, $entityIds, $storeId)
  357. {
  358. $select = $this->connection->select()->from(
  359. [
  360. 'def' => $this->connection->getTableName($this->getTableName('catalog_category_entity_' . $type)),
  361. ],
  362. ['entity_id', 'attribute_id']
  363. )->joinLeft(
  364. [
  365. 'store' => $this->connection->getTableName(
  366. $this->getTableName('catalog_category_entity_' . $type)
  367. ),
  368. ],
  369. 'store.entity_id = def.entity_id AND store.attribute_id = def.attribute_id ' .
  370. 'AND store.store_id = ' .
  371. $storeId,
  372. [
  373. 'value' => $this->connection->getCheckSql(
  374. 'store.value_id > 0',
  375. $this->connection->quoteIdentifier('store.value'),
  376. $this->connection->quoteIdentifier('def.value')
  377. )
  378. ]
  379. )->where(
  380. 'def.entity_id IN (?)',
  381. $entityIds
  382. )->where(
  383. 'def.store_id IN (?)',
  384. [\Magento\Store\Model\Store::DEFAULT_STORE_ID, $storeId]
  385. );
  386. return $this->connection->fetchAll($select);
  387. }
  388. /**
  389. * Prepare array of column and columnValue pairs
  390. *
  391. * @param array $data
  392. * @return array
  393. */
  394. protected function prepareValuesToInsert($data)
  395. {
  396. $values = [];
  397. foreach (array_keys($this->getColumns()) as $column) {
  398. if (isset($data[$column])) {
  399. $values[$column] = $data[$column];
  400. } else {
  401. $values[$column] = null;
  402. }
  403. }
  404. return $values;
  405. }
  406. /**
  407. * Get table name
  408. *
  409. * @param string $name
  410. * @return string
  411. */
  412. protected function getTableName($name)
  413. {
  414. return $this->resource->getTableName($name);
  415. }
  416. }