Collection.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Eav\Model\ResourceModel\Entity\Attribute;
  7. use Magento\Eav\Model\Entity\Type;
  8. /**
  9. * EAV attribute resource collection
  10. *
  11. * @api
  12. * @author Magento Core Team <core@magentocommerce.com>
  13. * @since 100.0.2
  14. */
  15. class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
  16. {
  17. /**
  18. * Add attribute set info flag
  19. *
  20. * @var bool
  21. */
  22. protected $_addSetInfoFlag = false;
  23. /**
  24. * @var \Magento\Eav\Model\Config
  25. */
  26. protected $eavConfig;
  27. /**
  28. * @param \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory
  29. * @param \Psr\Log\LoggerInterface $logger
  30. * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
  31. * @param \Magento\Framework\Event\ManagerInterface $eventManager
  32. * @param \Magento\Eav\Model\Config $eavConfig
  33. * @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
  34. * @param \Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource
  35. * @codeCoverageIgnore
  36. */
  37. public function __construct(
  38. \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory,
  39. \Psr\Log\LoggerInterface $logger,
  40. \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
  41. \Magento\Framework\Event\ManagerInterface $eventManager,
  42. \Magento\Eav\Model\Config $eavConfig,
  43. \Magento\Framework\DB\Adapter\AdapterInterface $connection = null,
  44. \Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource = null
  45. ) {
  46. $this->eavConfig = $eavConfig;
  47. parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $connection, $resource);
  48. }
  49. /**
  50. * Resource model initialization
  51. *
  52. * @return void
  53. * @codeCoverageIgnore
  54. */
  55. protected function _construct()
  56. {
  57. $this->_init(
  58. \Magento\Eav\Model\Entity\Attribute::class,
  59. \Magento\Eav\Model\ResourceModel\Entity\Attribute::class
  60. );
  61. }
  62. /**
  63. * Return array of fields to load attribute values
  64. *
  65. * @return string[]
  66. * @codeCoverageIgnore
  67. */
  68. protected function _getLoadDataFields()
  69. {
  70. return [
  71. 'attribute_id',
  72. 'entity_type_id',
  73. 'attribute_code',
  74. 'attribute_model',
  75. 'backend_model',
  76. 'backend_type',
  77. 'backend_table',
  78. 'frontend_input',
  79. 'source_model'
  80. ];
  81. }
  82. /**
  83. * Specify select columns which are used for load attribute values
  84. *
  85. * @return $this
  86. */
  87. public function useLoadDataFields()
  88. {
  89. $this->getSelect()->reset(\Magento\Framework\DB\Select::COLUMNS);
  90. $this->getSelect()->columns($this->_getLoadDataFields());
  91. return $this;
  92. }
  93. /**
  94. * Specify attribute entity type filter
  95. *
  96. * @param Type|int $type
  97. * @return $this
  98. */
  99. public function setEntityTypeFilter($type)
  100. {
  101. if ($type instanceof Type) {
  102. $additionalTable = $type->getAdditionalAttributeTable();
  103. $id = $type->getId();
  104. } else {
  105. $additionalTable = $this->getResource()->getAdditionalAttributeTable($type);
  106. $id = $type;
  107. }
  108. $this->addFieldToFilter('main_table.entity_type_id', $id);
  109. if ($additionalTable) {
  110. $this->join(
  111. ['additional_table' => $additionalTable],
  112. 'additional_table.attribute_id = main_table.attribute_id'
  113. );
  114. }
  115. return $this;
  116. }
  117. /**
  118. * Specify attribute set filter
  119. *
  120. * @param int $setId
  121. * @return $this
  122. */
  123. public function setAttributeSetFilter($setId)
  124. {
  125. if (is_array($setId)) {
  126. if (!empty($setId)) {
  127. $this->join(
  128. ['entity_attribute' => $this->getTable('eav_entity_attribute')],
  129. 'entity_attribute.attribute_id = main_table.attribute_id',
  130. 'attribute_id'
  131. );
  132. $this->addFieldToFilter('entity_attribute.attribute_set_id', ['in' => $setId]);
  133. $this->addAttributeGrouping();
  134. }
  135. } elseif ($setId) {
  136. $this->join(
  137. ['entity_attribute' => $this->getTable('eav_entity_attribute')],
  138. 'entity_attribute.attribute_id = main_table.attribute_id'
  139. );
  140. $this->addFieldToFilter('entity_attribute.attribute_set_id', $setId);
  141. $this->setOrder('entity_attribute.sort_order', self::SORT_ORDER_ASC);
  142. }
  143. return $this;
  144. }
  145. /**
  146. * Add attribute set filter to collection based on attribute set name and corresponding entity type.
  147. *
  148. * @param string $attributeSetName
  149. * @param string $entityTypeCode
  150. * @return void
  151. */
  152. public function setAttributeSetFilterBySetName($attributeSetName, $entityTypeCode)
  153. {
  154. //@codeCoverageIgnoreStart
  155. $entityTypeId = $this->eavConfig->getEntityType($entityTypeCode)->getId();
  156. $this->join(
  157. ['entity_attribute' => $this->getTable('eav_entity_attribute')],
  158. 'entity_attribute.attribute_id = main_table.attribute_id'
  159. );
  160. $this->join(
  161. ['attribute_set' => $this->getTable('eav_attribute_set')],
  162. 'attribute_set.attribute_set_id = entity_attribute.attribute_set_id',
  163. []
  164. );
  165. $this->addFieldToFilter('attribute_set.entity_type_id', $entityTypeId);
  166. $this->addFieldToFilter('attribute_set.attribute_set_name', $attributeSetName);
  167. $this->setOrder('entity_attribute.sort_order', self::SORT_ORDER_ASC);
  168. //@codeCoverageIgnoreEnd
  169. }
  170. /**
  171. * Specify multiple attribute sets filter
  172. * Result will be ordered by sort_order
  173. *
  174. * @param array $setIds
  175. * @return $this
  176. */
  177. public function setAttributeSetsFilter(array $setIds)
  178. {
  179. $this->getSelect()->distinct(true);
  180. $this->join(
  181. ['entity_attribute' => $this->getTable('eav_entity_attribute')],
  182. 'entity_attribute.attribute_id = main_table.attribute_id',
  183. 'attribute_id'
  184. );
  185. $this->addFieldToFilter('entity_attribute.attribute_set_id', ['in' => $setIds]);
  186. $this->setOrder('sort_order', self::SORT_ORDER_ASC);
  187. return $this;
  188. }
  189. /**
  190. * Filter for selecting of attributes that is in all sets
  191. *
  192. * @param int[] $setIds
  193. * @return $this
  194. */
  195. public function setInAllAttributeSetsFilter(array $setIds)
  196. {
  197. if (!empty($setIds)) {
  198. $this->getSelect()
  199. ->join(
  200. ['entity_attribute' => $this->getTable('eav_entity_attribute')],
  201. 'entity_attribute.attribute_id = main_table.attribute_id',
  202. ['count' => new \Zend_Db_Expr('COUNT(*)')]
  203. )
  204. ->where(
  205. 'entity_attribute.attribute_set_id IN (?)',
  206. $setIds
  207. )
  208. ->group('entity_attribute.attribute_id')
  209. ->having(new \Zend_Db_Expr('COUNT(*)') . ' = ' . count($setIds));
  210. }
  211. //$this->getSelect()->distinct(true);
  212. $this->setOrder('is_user_defined', self::SORT_ORDER_ASC);
  213. return $this;
  214. }
  215. /**
  216. * Exclude attributes filter
  217. *
  218. * @param array $attributes
  219. * @return $this
  220. */
  221. public function setAttributesExcludeFilter($attributes)
  222. {
  223. return $this->addFieldToFilter('main_table.attribute_id', ['nin' => $attributes]);
  224. }
  225. /**
  226. * Specify exclude attribute set filter
  227. *
  228. * @param int $setId
  229. * @return $this
  230. */
  231. public function setExcludeSetFilter($setId)
  232. {
  233. $existsSelect = $this->getConnection()->select()->from(
  234. ['entity_attribute' => $this->getTable('eav_entity_attribute')]
  235. )->where(
  236. 'entity_attribute.attribute_set_id = ?',
  237. $setId
  238. );
  239. $this->getSelect()->order('attribute_id ' . self::SORT_ORDER_DESC);
  240. $this->getSelect()->exists($existsSelect, 'entity_attribute.attribute_id = main_table.attribute_id', false);
  241. return $this;
  242. }
  243. /**
  244. * Filter by attribute group id
  245. *
  246. * @param int $groupId
  247. * @return $this
  248. */
  249. public function setAttributeGroupFilter($groupId)
  250. {
  251. $this->join(
  252. ['entity_attribute' => $this->getTable('eav_entity_attribute')],
  253. 'entity_attribute.attribute_id = main_table.attribute_id'
  254. );
  255. $this->addFieldToFilter('entity_attribute.attribute_group_id', $groupId);
  256. $this->setOrder('sort_order', self::SORT_ORDER_ASC);
  257. return $this;
  258. }
  259. /**
  260. * Declare group by attribute id condition for collection select
  261. *
  262. * @return $this
  263. * @codeCoverageIgnore
  264. */
  265. public function addAttributeGrouping()
  266. {
  267. $this->getSelect()->group('main_table.attribute_id');
  268. return $this;
  269. }
  270. /**
  271. * Specify "is_unique" filter as true
  272. *
  273. * @return $this
  274. * @codeCoverageIgnore
  275. */
  276. public function addIsUniqueFilter()
  277. {
  278. return $this->addFieldToFilter('is_unique', ['gt' => 0]);
  279. }
  280. /**
  281. * Specify "is_unique" filter as false
  282. *
  283. * @return $this
  284. * @codeCoverageIgnore
  285. */
  286. public function addIsNotUniqueFilter()
  287. {
  288. return $this->addFieldToFilter('is_unique', 0);
  289. }
  290. /**
  291. * Specify filter to select just attributes with options
  292. *
  293. * @return $this
  294. */
  295. public function addHasOptionsFilter()
  296. {
  297. $connection = $this->getConnection();
  298. $orWhere = implode(
  299. ' OR ',
  300. [
  301. $connection->quoteInto('(main_table.frontend_input = ? AND ao.option_id > 0)', 'select'),
  302. $connection->quoteInto('(main_table.frontend_input <> ?)', 'select'),
  303. '(main_table.is_user_defined = 0)'
  304. ]
  305. );
  306. $this->getSelect()->joinLeft(
  307. ['ao' => $this->getTable('eav_attribute_option')],
  308. 'ao.attribute_id = main_table.attribute_id',
  309. 'option_id'
  310. )->group(
  311. 'main_table.attribute_id'
  312. )->where(
  313. $orWhere
  314. );
  315. return $this;
  316. }
  317. /**
  318. * Apply filter by attribute frontend input type
  319. *
  320. * @param string $frontendInputType
  321. * @return $this
  322. * @codeCoverageIgnore
  323. */
  324. public function setFrontendInputTypeFilter($frontendInputType)
  325. {
  326. return $this->addFieldToFilter('frontend_input', $frontendInputType);
  327. }
  328. /**
  329. * Flag for adding information about attributes sets to result
  330. *
  331. * @param bool $flag
  332. * @return $this
  333. * @codeCoverageIgnore
  334. */
  335. public function addSetInfo($flag = true)
  336. {
  337. $this->_addSetInfoFlag = (bool)$flag;
  338. return $this;
  339. }
  340. /**
  341. * Ad information about attribute sets to collection result data
  342. *
  343. * @return $this
  344. */
  345. protected function _addSetInfo()
  346. {
  347. if ($this->_addSetInfoFlag) {
  348. $attributeIds = [];
  349. foreach ($this->_data as &$dataItem) {
  350. $attributeIds[] = $dataItem['attribute_id'];
  351. }
  352. $attributeToSetInfo = [];
  353. $connection = $this->getConnection();
  354. if (count($attributeIds) > 0) {
  355. $select = $connection->select()->from(
  356. ['entity' => $this->getTable('eav_entity_attribute')],
  357. ['attribute_id', 'attribute_set_id', 'attribute_group_id', 'sort_order']
  358. )->joinLeft(
  359. ['attribute_group' => $this->getTable('eav_attribute_group')],
  360. 'entity.attribute_group_id = attribute_group.attribute_group_id',
  361. ['group_sort_order' => 'sort_order']
  362. )->where(
  363. 'attribute_id IN (?)',
  364. $attributeIds
  365. );
  366. $result = $connection->fetchAll($select);
  367. foreach ($result as $row) {
  368. $data = [
  369. 'group_id' => $row['attribute_group_id'],
  370. 'group_sort' => $row['group_sort_order'],
  371. 'sort' => $row['sort_order'],
  372. ];
  373. $attributeToSetInfo[$row['attribute_id']][$row['attribute_set_id']] = $data;
  374. }
  375. }
  376. foreach ($this->_data as &$attributeData) {
  377. $setInfo = [];
  378. if (isset($attributeToSetInfo[$attributeData['attribute_id']])) {
  379. $setInfo = $attributeToSetInfo[$attributeData['attribute_id']];
  380. }
  381. $attributeData['attribute_set_info'] = $setInfo;
  382. }
  383. unset($attributeToSetInfo);
  384. unset($attributeIds);
  385. }
  386. return $this;
  387. }
  388. /**
  389. * Ad information about attribute sets to collection result data
  390. *
  391. * @return \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
  392. */
  393. protected function _afterLoadData()
  394. {
  395. $this->_addSetInfo();
  396. return parent::_afterLoadData();
  397. }
  398. /**
  399. * Specify collection attribute codes filter
  400. *
  401. * @param string|array $code
  402. * @return $this
  403. */
  404. public function setCodeFilter($code)
  405. {
  406. if (empty($code)) {
  407. return $this;
  408. }
  409. if (!is_array($code)) {
  410. $code = [$code];
  411. }
  412. return $this->addFieldToFilter('attribute_code', ['in' => $code]);
  413. }
  414. /**
  415. * Add store label to attribute by specified store id
  416. *
  417. * @param int $storeId
  418. * @return $this
  419. */
  420. public function addStoreLabel($storeId)
  421. {
  422. $connection = $this->getConnection();
  423. $joinExpression = $connection->quoteInto(
  424. 'al.attribute_id = main_table.attribute_id AND al.store_id = ?',
  425. (int)$storeId
  426. );
  427. $this->getSelect()->joinLeft(
  428. ['al' => $this->getTable('eav_attribute_label')],
  429. $joinExpression,
  430. ['store_label' => $connection->getIfNullSql('al.value', 'main_table.frontend_label')]
  431. );
  432. return $this;
  433. }
  434. /**
  435. * {@inheritdoc}
  436. */
  437. public function getSelectCountSql()
  438. {
  439. $countSelect = parent::getSelectCountSql();
  440. $countSelect->reset(\Magento\Framework\DB\Select::COLUMNS);
  441. $countSelect->columns('COUNT(DISTINCT main_table.attribute_id)');
  442. return $countSelect;
  443. }
  444. /**
  445. * Join table to collection select
  446. *
  447. * @param string $table
  448. * @param string $cond
  449. * @param string $cols
  450. * @return $this
  451. * @since 100.1.0
  452. */
  453. public function joinLeft($table, $cond, $cols = '*')
  454. {
  455. if (is_array($table)) {
  456. foreach ($table as $k => $v) {
  457. $alias = $k;
  458. $table = $v;
  459. break;
  460. }
  461. } else {
  462. $alias = $table;
  463. }
  464. if (!isset($this->_joinedTables[$alias])) {
  465. $this->getSelect()->joinLeft([$alias => $this->getTable($table)], $cond, $cols);
  466. $this->_joinedTables[$alias] = true;
  467. }
  468. return $this;
  469. }
  470. }