Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
AbstractCollection.php
Go to the documentation of this file.
1 <?php
8 
13 
23 abstract class AbstractCollection extends AbstractDb implements SourceProviderInterface
24 {
29 
35  protected $_itemsById = [];
36 
42  protected $_staticFields = [];
43 
49  protected $_entity;
50 
56  protected $_selectEntityTypes = [];
57 
63  protected $_selectAttributes = [];
64 
70  protected $_filterAttributes = [];
71 
77  protected $_joinEntities = [];
78 
84  protected $_joinAttributes = [];
85 
91  protected $_joinFields = [];
92 
98  protected $_castToIntMap = ['validate-digits'];
99 
105  protected $_eventManager = null;
106 
110  protected $_eavConfig;
111 
115  protected $_resource;
116 
121 
125  protected $_resourceHelper;
126 
131 
146  public function __construct(
147  \Magento\Framework\Data\Collection\EntityFactory $entityFactory,
148  \Psr\Log\LoggerInterface $logger,
149  \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
150  \Magento\Framework\Event\ManagerInterface $eventManager,
151  \Magento\Eav\Model\Config $eavConfig,
153  \Magento\Eav\Model\EntityFactory $eavEntityFactory,
154  \Magento\Eav\Model\ResourceModel\Helper $resourceHelper,
155  \Magento\Framework\Validator\UniversalFactory $universalFactory,
156  \Magento\Framework\DB\Adapter\AdapterInterface $connection = null
157  ) {
158  $this->_eventManager = $eventManager;
159  $this->_eavConfig = $eavConfig;
160  $this->_resource = $resource;
161  $this->_eavEntityFactory = $eavEntityFactory;
162  $this->_resourceHelper = $resourceHelper;
163  $this->_universalFactory = $universalFactory;
164  parent::__construct($entityFactory, $logger, $fetchStrategy, $connection);
165  $this->_construct();
166  $this->setConnection($this->getEntity()->getConnection());
167  $this->_prepareStaticFields();
168  $this->_initSelect();
169  }
170 
176  protected function _construct()
177  {
178  }
179 
187  public function getTable($table)
188  {
189  return $this->getResource()->getTable($table);
190  }
191 
197  protected function _prepareStaticFields()
198  {
199  foreach ($this->getEntity()->getDefaultAttributes() as $field) {
200  $this->_staticFields[$field] = $field;
201  }
202  return $this;
203  }
204 
210  protected function _initSelect()
211  {
212  $this->getSelect()->from(['e' => $this->getEntity()->getEntityTable()]);
213  $entity = $this->getEntity();
214  if ($entity->getTypeId() && $entity->getEntityTable() == \Magento\Eav\Model\Entity::DEFAULT_ENTITY_TABLE) {
215  $this->addAttributeToFilter('entity_type_id', $this->getEntity()->getTypeId());
216  }
217  return $this;
218  }
219 
227  protected function _init($model, $entityModel)
228  {
229  $this->setItemObjectClass($model);
230  $entity = $this->_universalFactory->create($entityModel);
231  $this->setEntity($entity);
232 
233  return $this;
234  }
235 
243  public function setEntity($entity)
244  {
245  if ($entity instanceof \Magento\Eav\Model\Entity\AbstractEntity) {
246  $this->_entity = $entity;
247  } elseif (is_string($entity) || $entity instanceof \Magento\Framework\App\Config\Element) {
248  $this->_entity = $this->_eavEntityFactory->create()->setType($entity);
249  } else {
250  throw new LocalizedException(
251  __('The "%1" entity supplied is invalid. Verify the entity and try again.', print_r($entity, 1))
252  );
253  }
254  return $this;
255  }
256 
263  public function getEntity()
264  {
265  if (empty($this->_entity)) {
266  throw new LocalizedException(__('Entity is not initialized'));
267  }
268  return $this->_entity;
269  }
270 
277  public function getResource()
278  {
279  return $this->getEntity();
280  }
281 
288  public function setObject($object = null)
289  {
290  if (is_object($object)) {
291  $this->setItemObjectClass(get_class($object));
292  } else {
293  $this->setItemObjectClass($object);
294  }
295  return $this;
296  }
297 
305  public function addItem(\Magento\Framework\DataObject $object)
306  {
307  if (!$object instanceof $this->_itemObjectClass) {
308  throw new LocalizedException(
309  __("The object wasn't added because it's invalid. To continue, enter a valid object and try again.")
310  );
311  }
312  return parent::addItem($object);
313  }
314 
321  public function getAttribute($attributeCode)
322  {
323  if (isset($this->_joinAttributes[$attributeCode])) {
324  return $this->_joinAttributes[$attributeCode]['attribute'];
325  }
326 
327  return $this->getEntity()->getAttribute($attributeCode);
328  }
329 
348  public function addAttributeToFilter($attribute, $condition = null, $joinType = 'inner')
349  {
350  if ($attribute === null) {
351  $this->getSelect();
352  return $this;
353  }
354 
355  if (is_numeric($attribute)) {
356  $attributeModel = $this->getEntity()->getAttribute($attribute);
357  if (!$attributeModel) {
358  throw new \Magento\Framework\Exception\LocalizedException(
359  __('Invalid attribute identifier for filter (%1)', get_class($attribute))
360  );
361  }
362  $attribute = $attributeModel->getAttributeCode();
363  } elseif ($attribute instanceof \Magento\Eav\Model\Entity\Attribute\AttributeInterface) {
364  $attribute = $attribute->getAttributeCode();
365  }
366 
367  if (is_array($attribute)) {
368  $sqlArr = [];
369  foreach ($attribute as $condition) {
370  $sqlArr[] = $this->_getAttributeConditionSql($condition['attribute'], $condition, $joinType);
371  }
372  $conditionSql = '(' . implode(') OR (', $sqlArr) . ')';
373  } elseif (is_string($attribute)) {
374  if ($condition === null) {
375  $condition = '';
376  }
377  $conditionSql = $this->_getAttributeConditionSql($attribute, $condition, $joinType);
378  }
379 
380  if (!empty($conditionSql)) {
381  $this->getSelect()->where($conditionSql, null, \Magento\Framework\DB\Select::TYPE_CONDITION);
382  $this->invalidateSize();
383  } else {
384  throw new \Magento\Framework\Exception\LocalizedException(
385  __('Invalid attribute identifier for filter (%1)', get_class($attribute))
386  );
387  }
388 
389  return $this;
390  }
391 
400  public function addFieldToFilter($attribute, $condition = null)
401  {
402  return $this->addAttributeToFilter($attribute, $condition);
403  }
404 
412  public function addAttributeToSort($attribute, $dir = self::SORT_ORDER_ASC)
413  {
414  if (isset($this->_joinFields[$attribute])) {
415  $this->getSelect()->order($this->_getAttributeFieldName($attribute) . ' ' . $dir);
416  return $this;
417  }
418  if (isset($this->_staticFields[$attribute])) {
419  $this->getSelect()->order("e.{$attribute} {$dir}");
420  return $this;
421  }
422  if (isset($this->_joinAttributes[$attribute])) {
423  $attrInstance = $this->_joinAttributes[$attribute]['attribute'];
424  $entityField = $this->_getAttributeTableAlias($attribute) . '.' . $attrInstance->getAttributeCode();
425  } else {
426  $attrInstance = $this->getEntity()->getAttribute($attribute);
427  $entityField = 'e.' . $attribute;
428  }
429 
430  if ($attrInstance) {
431  if ($attrInstance->getBackend()->isStatic()) {
432  $orderExpr = $entityField;
433  } else {
434  $this->_addAttributeJoin($attribute, 'left');
435  if (isset($this->_joinAttributes[$attribute]) || isset($this->_joinFields[$attribute])) {
436  $orderExpr = $attribute;
437  } else {
438  $orderExpr = $this->_getAttributeTableAlias($attribute) . '.value';
439  }
440  }
441 
442  if (in_array($attrInstance->getFrontendClass(), $this->_castToIntMap)) {
443  $orderExpr = new \Zend_Db_Expr("CAST({$this->_prepareOrderExpression($orderExpr)} AS SIGNED)");
444  }
445 
446  $orderExpr .= ' ' . $dir;
447  $this->getSelect()->order($orderExpr);
448  }
449  return $this;
450  }
451 
458  protected function _prepareOrderExpression($field)
459  {
460  foreach ($this->getSelect()->getPart(\Magento\Framework\DB\Select::COLUMNS) as $columnEntry) {
461  if ($columnEntry[2] != $field) {
462  continue;
463  }
464  if ($columnEntry[1] instanceof \Zend_Db_Expr) {
465  return $columnEntry[1];
466  }
467  }
468  return $field;
469  }
470 
481  public function addAttributeToSelect($attribute, $joinType = false)
482  {
483  if (is_array($attribute)) {
484  foreach ($attribute as $a) {
485  $this->addAttributeToSelect($a, $joinType);
486  }
487  return $this;
488  }
489  if ($joinType !== false && !$this->getEntity()->getAttribute($attribute)->isStatic()) {
490  $this->_addAttributeJoin($attribute, $joinType);
491  } elseif ('*' === $attribute) {
492  $entity = clone $this->getEntity();
493  $attributes = $entity->loadAllAttributes()->getAttributesByCode();
494  foreach ($attributes as $attrCode => $attr) {
495  $this->_selectAttributes[$attrCode] = $attr->getId();
496  }
497  } else {
498  if (isset($this->_joinAttributes[$attribute])) {
499  $attrInstance = $this->_joinAttributes[$attribute]['attribute'];
500  } else {
501  $attrInstance = $this->_eavConfig->getAttribute($this->getEntity()->getType(), $attribute);
502  }
503  if (empty($attrInstance)) {
504  throw new LocalizedException(
505  __(
506  'The "%1" attribute requested is invalid. Verify the attribute and try again.',
507  (string)$attribute
508  )
509  );
510  }
511  $this->_selectAttributes[$attrInstance->getAttributeCode()] = $attrInstance->getId();
512  }
513  return $this;
514  }
515 
525  {
526  $this->_selectEntityTypes[$entityType] = ['prefix' => $prefix];
527  return $this;
528  }
529 
536  public function addStaticField($field)
537  {
538  if (!isset($this->_staticFields[$field])) {
539  $this->_staticFields[$field] = $field;
540  }
541  return $this;
542  }
543 
558  public function addExpressionAttributeToSelect($alias, $expression, $attribute)
559  {
560  // validate alias
561  if (isset($this->_joinFields[$alias])) {
562  throw new LocalizedException(__('Joint field or attribute expression with this alias is already declared'));
563  }
564  if (!is_array($attribute)) {
566  }
567 
568  $fullExpression = $expression;
569  // Replacing multiple attributes
570  foreach ($attribute as $attributeItem) {
571  if (isset($this->_staticFields[$attributeItem])) {
572  $attrField = sprintf('e.%s', $attributeItem);
573  } else {
574  $attributeInstance = $this->getAttribute($attributeItem);
575 
576  if ($attributeInstance->getBackend()->isStatic()) {
577  $attrField = 'e.' . $attributeItem;
578  } else {
579  $this->_addAttributeJoin($attributeItem, 'left');
580  $attrField = $this->_getAttributeFieldName($attributeItem);
581  }
582  }
583 
584  $fullExpression = str_replace('{{attribute}}', $attrField, $fullExpression);
585  $fullExpression = str_replace('{{' . $attributeItem . '}}', $attrField, $fullExpression);
586  }
587 
588  $this->getSelect()->columns([$alias => $fullExpression]);
589 
590  $this->_joinFields[$alias] = ['table' => false, 'field' => $fullExpression];
591 
592  return $this;
593  }
594 
601  public function groupByAttribute($attribute)
602  {
603  if (is_array($attribute)) {
604  foreach ($attribute as $attributeItem) {
605  $this->groupByAttribute($attributeItem);
606  }
607  } else {
608  if (isset($this->_joinFields[$attribute])) {
609  $this->getSelect()->group($this->_getAttributeFieldName($attribute));
610  return $this;
611  }
612 
613  if (isset($this->_staticFields[$attribute])) {
614  $this->getSelect()->group(sprintf('e.%s', $attribute));
615  return $this;
616  }
617 
618  if (isset($this->_joinAttributes[$attribute])) {
619  $attrInstance = $this->_joinAttributes[$attribute]['attribute'];
620  $entityField = $this->_getAttributeTableAlias($attribute) . '.' . $attrInstance->getAttributeCode();
621  } else {
622  $attrInstance = $this->getEntity()->getAttribute($attribute);
623  $entityField = 'e.' . $attribute;
624  }
625 
626  if ($attrInstance->getBackend()->isStatic()) {
627  $this->getSelect()->group($entityField);
628  } else {
629  $this->_addAttributeJoin($attribute);
630  $this->getSelect()->group($this->_getAttributeTableAlias($attribute) . '.value');
631  }
632  }
633 
634  return $this;
635  }
636 
662  public function joinAttribute($alias, $attribute, $bind, $filter = null, $joinType = 'inner', $storeId = null)
663  {
664  // validate alias
665  if (isset($this->_joinAttributes[$alias])) {
666  throw new LocalizedException(__('Invalid alias, already exists in joint attributes'));
667  }
668 
669  $bindAttribute = null;
670  // validate bind attribute
671  if (is_string($bind)) {
672  $bindAttribute = $this->getAttribute($bind);
673  }
674 
675  if (!$bindAttribute || !$bindAttribute->isStatic() && !$bindAttribute->getId()) {
676  throw new LocalizedException(__('The foreign key is invalid. Verify the foreign key and try again.'));
677  }
678 
679  // try to explode combined entity/attribute if supplied
680  if (is_string($attribute)) {
681  $attrArr = explode('/', $attribute);
682  if (isset($attrArr[1])) {
683  $entity = $attrArr[0];
684  $attribute = $attrArr[1];
685  }
686  }
687 
688  // validate entity
689  if (empty($entity) && $attribute instanceof \Magento\Eav\Model\Entity\Attribute\AbstractAttribute) {
690  $entity = $attribute->getEntity();
691  } elseif (is_string($entity)) {
692  // retrieve cached entity if possible
693  if (isset($this->_joinEntities[$entity])) {
694  $entity = $this->_joinEntities[$entity];
695  } else {
696  $entity = $this->_eavEntityFactory->create()->setType($attrArr[0]);
697  }
698  }
699  if (!$entity || !$entity->getTypeId()) {
700  throw new LocalizedException(__('The entity type is invalid. Verify the entity type and try again.'));
701  }
702 
703  // cache entity
704  if (!isset($this->_joinEntities[$entity->getType()])) {
705  $this->_joinEntities[$entity->getType()] = $entity;
706  }
707 
708  // validate attribute
709  if (is_string($attribute)) {
710  $attribute = $entity->getAttribute($attribute);
711  }
712  if (!$attribute) {
713  throw new LocalizedException(__('The attribute type is invalid. Verify the attribute type and try again.'));
714  }
715 
716  if (empty($filter)) {
717  $filter = $entity->getLinkField();
718  }
719 
720  // add joined attribute
721  $this->_joinAttributes[$alias] = [
722  'bind' => $bind,
723  'bindAttribute' => $bindAttribute,
724  'attribute' => $attribute,
725  'filter' => $filter,
726  'store_id' => $storeId,
727  ];
728 
729  $this->_addAttributeJoin($alias, $joinType);
730 
731  return $this;
732  }
733 
750  public function joinField($alias, $table, $field, $bind, $cond = null, $joinType = 'inner')
751  {
752  // validate alias
753  if (isset($this->_joinFields[$alias])) {
754  throw new LocalizedException(__('A joined field with this alias is already declared.'));
755  }
756 
757  $table = $this->_resource->getTableName($table);
758  $tableAlias = $this->_getAttributeTableAlias($alias);
759 
760  // validate bind
761  list($pKey, $fKey) = explode('=', $bind);
762  $pKey = $this->getSelect()->getConnection()->quoteColumnAs(trim($pKey), null);
763  $bindCond = $tableAlias . '.' . trim($pKey) . '=' . $this->_getAttributeFieldName(trim($fKey));
764 
765  // process join type
766  switch ($joinType) {
767  case 'left':
768  $joinMethod = 'joinLeft';
769  break;
770  default:
771  $joinMethod = 'join';
772  break;
773  }
774  $condArr = [$bindCond];
775 
776  // add where condition if needed
777  if ($cond !== null) {
778  if (is_array($cond)) {
779  foreach ($cond as $key => $value) {
780  $condArr[] = $this->_getConditionSql($tableAlias . '.' . $key, $value);
781  }
782  } else {
783  $condArr[] = str_replace('{{table}}', $tableAlias, $cond);
784  }
785  }
786  $cond = '(' . implode(') AND (', $condArr) . ')';
787 
788  // join table
789  $this->getSelect()->{$joinMethod}(
790  [$tableAlias => $table],
791  $cond,
792  $field ? [$alias => $field] : []
793  );
794 
795  // save joined attribute
796  $this->_joinFields[$alias] = ['table' => $tableAlias, 'field' => $field];
797 
798  return $this;
799  }
800 
813  public function joinTable($table, $bind, $fields = null, $cond = null, $joinType = 'inner')
814  {
815  $tableAlias = null;
816  if (is_array($table)) {
817  list($tableAlias, $tableName) = [key($table), current($table)];
818  } else {
819  $tableName = $table;
820  }
821 
822  $tableName = $this->_resource->getTableName($tableName);
823  if (empty($tableAlias)) {
824  $tableAlias = $tableName;
825  }
826 
827  // validate fields and aliases
828  if (!$fields) {
829  throw new LocalizedException(__('Invalid joint fields'));
830  }
831  foreach ($fields as $alias => $field) {
832  if (isset($this->_joinFields[$alias])) {
833  throw new LocalizedException(__('A joint field with a "%1" alias is already declared.', $alias));
834  }
835  $this->_joinFields[$alias] = ['table' => $tableAlias, 'field' => $field];
836  }
837 
838  // validate bind
839  list($pKey, $fKey) = explode('=', $bind);
840  $bindCond = $tableAlias . '.' . $pKey . '=' . $this->_getAttributeFieldName($fKey);
841 
842  // process join type
843  switch ($joinType) {
844  case 'left':
845  $joinMethod = 'joinLeft';
846  break;
847 
848  default:
849  $joinMethod = 'join';
850  }
851  $condArr = [$bindCond];
852 
853  // add where condition if needed
854  if ($cond !== null) {
855  if (is_array($cond)) {
856  foreach ($cond as $key => $value) {
857  $condArr[] = $this->_getConditionSql($tableAlias . '.' . $key, $value);
858  }
859  } else {
860  $condArr[] = str_replace('{{table}}', $tableAlias, $cond);
861  }
862  }
863  $cond = '(' . implode(') AND (', $condArr) . ')';
864 
865  // join table
866  $this->getSelect()->{$joinMethod}([$tableAlias => $tableName], $cond, $fields);
867 
868  return $this;
869  }
870 
877  public function removeAttributeToSelect($attribute = null)
878  {
879  if ($attribute === null) {
880  $this->_selectAttributes = [];
881  } else {
882  unset($this->_selectAttributes[$attribute]);
883  }
884  return $this;
885  }
886 
895  public function setPage($pageNum, $pageSize)
896  {
897  $this->setCurPage($pageNum)->setPageSize($pageSize);
898  return $this;
899  }
900 
908  public function load($printQuery = false, $logQuery = false)
909  {
910  if ($this->isLoaded()) {
911  return $this;
912  }
913  \Magento\Framework\Profiler::start('EAV:load_collection');
914 
915  \Magento\Framework\Profiler::start('before_load');
916  $this->_eventManager->dispatch('eav_collection_abstract_load_before', ['collection' => $this]);
917  $this->_beforeLoad();
918  \Magento\Framework\Profiler::stop('before_load');
919 
920  $this->_renderFilters();
921  $this->_renderOrders();
922 
923  \Magento\Framework\Profiler::start('load_entities');
924  $this->_loadEntities($printQuery, $logQuery);
925  \Magento\Framework\Profiler::stop('load_entities');
926  \Magento\Framework\Profiler::start('load_attributes');
927  $this->_loadAttributes($printQuery, $logQuery);
928  \Magento\Framework\Profiler::stop('load_attributes');
929 
930  \Magento\Framework\Profiler::start('set_orig_data');
931  foreach ($this->_items as $item) {
932  $item->setOrigData();
933  $this->beforeAddLoadedItem($item);
934  $item->setDataChanges(false);
935  }
936  \Magento\Framework\Profiler::stop('set_orig_data');
937 
938  $this->_setIsLoaded();
939  \Magento\Framework\Profiler::start('after_load');
940  $this->_afterLoad();
941  \Magento\Framework\Profiler::stop('after_load');
942 
943  \Magento\Framework\Profiler::stop('EAV:load_collection');
944  return $this;
945  }
946 
954  protected function _getAllIdsSelect($limit = null, $offset = null)
955  {
956  $idsSelect = clone $this->getSelect();
957  $idsSelect->reset(\Magento\Framework\DB\Select::ORDER);
958  $idsSelect->reset(\Magento\Framework\DB\Select::LIMIT_COUNT);
959  $idsSelect->reset(\Magento\Framework\DB\Select::LIMIT_OFFSET);
960  $idsSelect->reset(\Magento\Framework\DB\Select::COLUMNS);
961  $idsSelect->columns('e.' . $this->getEntity()->getIdFieldName());
962  $idsSelect->limit($limit, $offset);
963 
964  return $idsSelect;
965  }
966 
974  public function getAllIds($limit = null, $offset = null)
975  {
976  return $this->getConnection()->fetchCol($this->_getAllIdsSelect($limit, $offset), $this->_bindParams);
977  }
978 
984  public function getAllIdsSql()
985  {
986  $idsSelect = clone $this->getSelect();
987  $idsSelect->reset(\Magento\Framework\DB\Select::ORDER);
988  $idsSelect->reset(\Magento\Framework\DB\Select::LIMIT_COUNT);
989  $idsSelect->reset(\Magento\Framework\DB\Select::LIMIT_OFFSET);
990  $idsSelect->reset(\Magento\Framework\DB\Select::COLUMNS);
991  $idsSelect->reset(\Magento\Framework\DB\Select::GROUP);
992  $idsSelect->columns('e.' . $this->getEntity()->getIdFieldName());
993 
994  return $idsSelect;
995  }
996 
1004  public function save()
1005  {
1006  foreach ($this->getItems() as $item) {
1007  $item->save();
1008  }
1009  return $this;
1010  }
1011 
1019  public function delete()
1020  {
1021  foreach ($this->getItems() as $key => $item) {
1022  $this->getEntity()->delete($item);
1023  unset($this->_items[$key]);
1024  }
1025  return $this;
1026  }
1027 
1036  public function importFromArray($arr)
1037  {
1038  $entityIdField = $this->getEntity()->getLinkField();
1039  foreach ($arr as $row) {
1040  $entityId = $row[$entityIdField];
1041  if (!isset($this->_items[$entityId])) {
1042  $this->_items[$entityId] = $this->getNewEmptyItem();
1043  $this->_items[$entityId]->setData($row);
1044  } else {
1045  $this->_items[$entityId]->addData($row);
1046  }
1047  }
1048  return $this;
1049  }
1050 
1056  public function exportToArray()
1057  {
1058  $result = [];
1059  $entityIdField = $this->getEntity()->getLinkField();
1060  foreach ($this->getItems() as $item) {
1061  $result[$item->getData($entityIdField)] = $item->getData();
1062  }
1063  return $result;
1064  }
1065 
1072  public function getRowIdFieldName()
1073  {
1074  return $this->getIdFieldName();
1075  }
1076 
1082  public function getIdFieldName()
1083  {
1084  if ($this->_idFieldName === null) {
1085  $this->_setIdFieldName($this->getEntity()->getIdFieldName());
1086  }
1087 
1088  return $this->_idFieldName;
1089  }
1090 
1097  public function setRowIdFieldName($fieldName)
1098  {
1099  return $this->_setIdFieldName($fieldName);
1100  }
1101 
1110  public function _loadEntities($printQuery = false, $logQuery = false)
1111  {
1112  $this->getEntity();
1113 
1114  if ($this->_pageSize) {
1115  $this->getSelect()->limitPage($this->getCurPage(), $this->_pageSize);
1116  }
1117 
1118  $this->printLogQuery($printQuery, $logQuery);
1119 
1120  try {
1125  $query = $this->getSelect();
1126  $rows = $this->_fetchAll($query);
1127  } catch (\Exception $e) {
1128  $this->printLogQuery(false, true, $query);
1129  throw $e;
1130  }
1131 
1132  foreach ($rows as $value) {
1133  $object = $this->getNewEmptyItem()->setData($value);
1134  $this->addItem($object);
1135  if (isset($this->_itemsById[$object->getId()])) {
1136  $this->_itemsById[$object->getId()][] = $object;
1137  } else {
1138  $this->_itemsById[$object->getId()] = [$object];
1139  }
1140  }
1141 
1142  return $this;
1143  }
1144 
1157  public function _loadAttributes($printQuery = false, $logQuery = false)
1158  {
1159  if (empty($this->_items) || empty($this->_itemsById) || empty($this->_selectAttributes)) {
1160  return $this;
1161  }
1162 
1163  $entity = $this->getEntity();
1164 
1165  $tableAttributes = [];
1166  $attributeTypes = [];
1167  foreach ($this->_selectAttributes as $attributeCode => $attributeId) {
1168  if (!$attributeId) {
1169  continue;
1170  }
1171  $attribute = $this->_eavConfig->getAttribute($entity->getType(), $attributeCode);
1172  if ($attribute && !$attribute->isStatic()) {
1173  $tableAttributes[$attribute->getBackendTable()][] = $attributeId;
1174  if (!isset($attributeTypes[$attribute->getBackendTable()])) {
1175  $attributeTypes[$attribute->getBackendTable()] = $attribute->getBackendType();
1176  }
1177  }
1178  }
1179 
1180  $selects = [];
1181  foreach ($tableAttributes as $table => $attributes) {
1182  $select = $this->_getLoadAttributesSelect($table, $attributes);
1183  $selects[$attributeTypes[$table]][] = $this->_addLoadAttributesSelectValues(
1184  $select,
1185  $table,
1186  $attributeTypes[$table]
1187  );
1188  }
1189  $selectGroups = $this->_resourceHelper->getLoadAttributesSelectGroups($selects);
1190  foreach ($selectGroups as $selects) {
1191  if (!empty($selects)) {
1192  try {
1193  if (is_array($selects)) {
1194  $select = implode(' UNION ALL ', $selects);
1195  } else {
1196  $select = $selects;
1197  }
1198  $values = $this->getConnection()->fetchAll($select);
1199  } catch (\Exception $e) {
1200  $this->printLogQuery(true, true, $select);
1201  throw $e;
1202  }
1203 
1204  foreach ($values as $value) {
1205  $this->_setItemAttributeValue($value);
1206  }
1207  }
1208  }
1209 
1210  return $this;
1211  }
1212 
1220  protected function _getLoadAttributesSelect($table, $attributeIds = [])
1221  {
1222  if (empty($attributeIds)) {
1223  $attributeIds = $this->_selectAttributes;
1224  }
1225  $entity = $this->getEntity();
1226  $linkField = $entity->getLinkField();
1227  $select = $this->getConnection()->select()
1228  ->from(
1229  ['e' => $this->getEntity()->getEntityTable()],
1230  ['entity_id']
1231  )
1232  ->join(
1233  ['t_d' => $table],
1234  "e.{$linkField} = t_d.{$linkField}",
1235  ['t_d.attribute_id']
1236  )->where(
1237  " e.entity_id IN (?)",
1238  array_keys($this->_itemsById)
1239  )->where(
1240  't_d.attribute_id IN (?)',
1241  $attributeIds
1242  );
1243 
1244  if ($entity->getEntityTable() == \Magento\Eav\Model\Entity::DEFAULT_ENTITY_TABLE && $entity->getTypeId()) {
1245  $select->where(
1246  'entity_type_id =?',
1247  $entity->getTypeId()
1248  );
1249  }
1250  return $select;
1251  }
1252 
1264  {
1265  $select->columns(['value' => 't_d.value']);
1266  return $select;
1267  }
1268 
1278  protected function _setItemAttributeValue($valueInfo)
1279  {
1280  $entityIdField = $this->getEntity()->getEntityIdField();
1281  $entityId = $valueInfo[$entityIdField];
1282  if (!isset($this->_itemsById[$entityId])) {
1283  throw new LocalizedException(
1284  __('A header row is missing for an attribute. Verify the header row and try again.')
1285  );
1286  }
1287  $attributeCode = array_search($valueInfo['attribute_id'], $this->_selectAttributes);
1288  if (!$attributeCode) {
1289  $attribute = $this->_eavConfig->getAttribute(
1290  $this->getEntity()->getType(),
1291  $valueInfo['attribute_id']
1292  );
1293  $attributeCode = $attribute->getAttributeCode();
1294  }
1295 
1296  foreach ($this->_itemsById[$entityId] as $object) {
1297  $object->setData($attributeCode, $valueInfo['value']);
1298  }
1299 
1300  return $this;
1301  }
1302 
1310  {
1311  return $this->getConnection()->getTableName(self::ATTRIBUTE_TABLE_ALIAS_PREFIX . $attributeCode);
1312  }
1313 
1322  {
1324  if (isset($this->_joinAttributes[$attributeCode]['condition_alias'])) {
1325  return $this->_joinAttributes[$attributeCode]['condition_alias'];
1326  }
1327  if (isset($this->_staticFields[$attributeCode])) {
1328  return sprintf('e.%s', $attributeCode);
1329  }
1330  if (isset($this->_joinFields[$attributeCode])) {
1331  $attr = $this->_joinFields[$attributeCode];
1332  return $attr['table'] ? $attr['table'] . '.' . $attr['field'] : $attr['field'];
1333  }
1334 
1335  $attribute = $this->getAttribute($attributeCode);
1336  if (!$attribute) {
1337  throw new LocalizedException(
1338  __('The "%1" attribute name is invalid. Reset the name and try again.', $attributeCode)
1339  );
1340  }
1341 
1342  if ($attribute->isStatic()) {
1343  if (isset($this->_joinAttributes[$attributeCode])) {
1344  $fieldName = $this->_getAttributeTableAlias($attributeCode) . '.' . $attributeCode;
1345  } else {
1346  $fieldName = 'e.' . $attributeCode;
1347  }
1348  } else {
1349  $fieldName = $this->_getAttributeTableAlias($attributeCode) . '.value';
1350  }
1351 
1352  return $fieldName;
1353  }
1354 
1364  protected function _addAttributeJoin($attributeCode, $joinType = 'inner')
1365  {
1366  if (!empty($this->_filterAttributes[$attributeCode])) {
1367  return $this;
1368  }
1369 
1370  $connection = $this->getConnection();
1371 
1372  $attrTable = $this->_getAttributeTableAlias($attributeCode);
1373  if (isset($this->_joinAttributes[$attributeCode])) {
1374  $attribute = $this->_joinAttributes[$attributeCode]['attribute'];
1375  $fkName = $this->_joinAttributes[$attributeCode]['bind'];
1376  $fkAttribute = $this->_joinAttributes[$attributeCode]['bindAttribute'];
1377  $fkTable = $this->_getAttributeTableAlias($fkName);
1378 
1379  if ($fkAttribute->getBackend()->isStatic()) {
1380  if (isset($this->_joinAttributes[$fkName])) {
1381  $fKey = $fkTable . '.' . $fkAttribute->getAttributeCode();
1382  } else {
1383  $fKey = 'e.' . $fkAttribute->getAttributeCode();
1384  }
1385  } else {
1386  $this->_addAttributeJoin($fkAttribute->getAttributeCode(), $joinType);
1387  $fKey = $fkTable . '.value';
1388  }
1389  $pKey = $attrTable . '.' . $this->_joinAttributes[$attributeCode]['filter'];
1390  } else {
1391  $entity = $this->getEntity();
1392  $fKey = 'e.' . $this->getEntityPkName($entity);
1393  $pKey = $attrTable . '.' . $this->getEntityPkName($entity);
1394  $attribute = $entity->getAttribute($attributeCode);
1395  }
1396 
1397  if (!$attribute) {
1398  throw new LocalizedException(
1399  __('The "%1" attribute name is invalid. Reset the name and try again.', $attributeCode)
1400  );
1401  }
1402 
1403  if ($attribute->getBackend()->isStatic()) {
1404  $attrFieldName = $attrTable . '.' . $attribute->getAttributeCode();
1405  } else {
1406  $attrFieldName = $attrTable . '.value';
1407  }
1408 
1409  $fKey = $connection->quoteColumnAs($fKey, null);
1410  $pKey = $connection->quoteColumnAs($pKey, null);
1411 
1412  $condArr = ["{$pKey} = {$fKey}"];
1413  if (!$attribute->getBackend()->isStatic()) {
1414  $condArr[] = $this->getConnection()->quoteInto(
1415  $connection->quoteColumnAs("{$attrTable}.attribute_id", null) . ' = ?',
1416  $attribute->getId()
1417  );
1418  }
1419 
1423  $joinMethod = $joinType == 'left' ? 'joinLeft' : 'join';
1424 
1425  $this->_joinAttributeToSelect($joinMethod, $attribute, $attrTable, $condArr, $attributeCode, $attrFieldName);
1426 
1427  $this->removeAttributeToSelect($attributeCode);
1428  $this->_filterAttributes[$attributeCode] = $attribute->getId();
1429 
1433  $this->_joinFields[$attributeCode] = ['table' => '', 'field' => $attrFieldName];
1434 
1435  return $this;
1436  }
1437 
1445  protected function getEntityPkName(\Magento\Eav\Model\Entity\AbstractEntity $entity)
1446  {
1447  return $entity->getEntityIdField();
1448  }
1449 
1461  protected function _joinAttributeToSelect($method, $attribute, $tableAlias, $condition, $fieldCode, $fieldAlias)
1462  {
1463  $this->getSelect()->{$method}(
1464  [$tableAlias => $attribute->getBackend()->getTable()],
1465  '(' . implode(') AND (', $condition) . ')',
1466  [$fieldCode => $fieldAlias]
1467  );
1468  return $this;
1469  }
1470 
1481  protected function _getAttributeConditionSql($attribute, $condition, $joinType = 'inner')
1482  {
1483  if (isset($this->_joinFields[$attribute])) {
1484  return $this->_getConditionSql($this->_getAttributeFieldName($attribute), $condition);
1485  }
1486  if (isset($this->_staticFields[$attribute])) {
1487  return $this->_getConditionSql($this->getConnection()->quoteIdentifier('e.' . $attribute), $condition);
1488  }
1489  // process linked attribute
1490  if (isset($this->_joinAttributes[$attribute])) {
1491  $entity = $this->getAttribute($attribute)->getEntity();
1492  } else {
1493  $entity = $this->getEntity();
1494  }
1495 
1496  if ($entity->isAttributeStatic($attribute)) {
1497  $conditionSql = $this->_getConditionSql(
1498  $this->getConnection()->quoteIdentifier('e.' . $attribute),
1499  $condition
1500  );
1501  } else {
1502  if (isset($condition['null'])) {
1503  $joinType = 'left';
1504  }
1505 
1506  $this->_addAttributeJoin($attribute, $joinType);
1507  if (isset($this->_joinAttributes[$attribute]['condition_alias'])) {
1508  $field = $this->_joinAttributes[$attribute]['condition_alias'];
1509  } else {
1510  $field = $this->_getAttributeTableAlias($attribute) . '.value';
1511  }
1512  $conditionSql = $this->_getConditionSql($field, $condition);
1513  }
1514 
1515  return $conditionSql;
1516  }
1517 
1527  public function setOrder($attribute, $dir = self::SORT_ORDER_ASC)
1528  {
1529  if (is_array($attribute)) {
1530  foreach ($attribute as $attr) {
1531  parent::setOrder($attr, $dir);
1532  }
1533  return $this;
1534  }
1535  return parent::setOrder($attribute, $dir);
1536  }
1537 
1544  public function toArray($arrAttributes = [])
1545  {
1546  $arr = [];
1547  foreach ($this->getItems() as $key => $item) {
1548  $arr[$key] = $item->toArray($arrAttributes);
1549  }
1550  return $arr;
1551  }
1552 
1558  protected function _renderOrders()
1559  {
1560  if (!$this->_isOrdersRendered) {
1561  foreach ($this->_orders as $attribute => $direction) {
1562  $this->addAttributeToSort($attribute, $direction);
1563  }
1564  $this->_isOrdersRendered = true;
1565  }
1566  return $this;
1567  }
1568 
1575  protected function _afterLoad()
1576  {
1577  return $this;
1578  }
1579 
1585  protected function _reset()
1586  {
1587  parent::_reset();
1588 
1589  $this->_selectEntityTypes = [];
1590  $this->_selectAttributes = [];
1591  $this->_filterAttributes = [];
1592  $this->_joinEntities = [];
1593  $this->_joinAttributes = [];
1594  $this->_joinFields = [];
1595 
1596  return $this;
1597  }
1598 
1605  public function isAttributeAdded($attributeCode) : bool
1606  {
1607  return isset($this->_selectAttributes[$attributeCode]);
1608  }
1609 
1616  public function getLoadedIds()
1617  {
1618  return array_keys($this->_items);
1619  }
1620 
1626  public function clear()
1627  {
1628  $this->_itemsById = [];
1629  return parent::clear();
1630  }
1631 
1637  public function removeAllItems()
1638  {
1639  $this->_itemsById = [];
1640  return parent::removeAllItems();
1641  }
1642 
1649  public function removeItemByKey($key)
1650  {
1651  if (isset($this->_items[$key])) {
1652  unset($this->_itemsById[$this->_items[$key]->getId()]);
1653  }
1654  return parent::removeItemByKey($key);
1655  }
1656 
1664  public function getMainTable()
1665  {
1666  return $this->getSelect()->getPart(Select::FROM)['e']['tableName'];
1667  }
1668 
1679  public function addFieldToSelect($field, $alias = null)
1680  {
1681  return $this->addAttributeToSelect($field);
1682  }
1683 
1691  public function removeFieldFromSelect($field)
1692  {
1693  return $this->removeAttributeToSelect($field);
1694  }
1695 
1702  public function removeAllFieldsFromSelect()
1703  {
1704  return $this->removeAttributeToSelect();
1705  }
1706 
1714  private function invalidateSize(): void
1715  {
1716  $this->_totalRecords = null;
1717  }
1718 }
$tableName
Definition: trigger.php:13
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
$attr
Definition: text.phtml:8
$fields
Definition: details.phtml:14
$values
Definition: options.phtml:88
__()
Definition: __.php:13
$resource
Definition: bulk.php:12
$logger
joinField($alias, $table, $field, $bind, $cond=null, $joinType='inner')
$type
Definition: item.phtml:13
joinAttribute($alias, $attribute, $bind, $filter=null, $joinType='inner', $storeId=null)
getEntityPkName(\Magento\Eav\Model\Entity\AbstractEntity $entity)
__construct(\Magento\Framework\Data\Collection\EntityFactory $entityFactory, \Psr\Log\LoggerInterface $logger, \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, \Magento\Framework\Event\ManagerInterface $eventManager, \Magento\Eav\Model\Config $eavConfig, \Magento\Framework\App\ResourceConnection $resource, \Magento\Eav\Model\EntityFactory $eavEntityFactory, \Magento\Eav\Model\ResourceModel\Helper $resourceHelper, \Magento\Framework\Validator\UniversalFactory $universalFactory, \Magento\Framework\DB\Adapter\AdapterInterface $connection=null)
setConnection(\Magento\Framework\DB\Adapter\AdapterInterface $conn)
Definition: AbstractDb.php:184
_getAttributeConditionSql($attribute, $condition, $joinType='inner')
joinTable($table, $bind, $fields=null, $cond=null, $joinType='inner')
$prefix
Definition: name.phtml:25
$value
Definition: gender.phtml:16
_joinAttributeToSelect($method, $attribute, $tableAlias, $condition, $fieldCode, $fieldAlias)
const COLUMNS
Definition: Select.php:48
$attributeCode
Definition: extend.phtml:12
addAttributeToSort($attribute, $dir=self::SORT_ORDER_ASC)
$entity
Definition: element.phtml:22
$attributes
Definition: matrix.phtml:13
$method
Definition: info.phtml:13
addExpressionAttributeToSelect($alias, $expression, $attribute)
if(!trim($html)) $alias
Definition: details.phtml:20
addAttributeToFilter($attribute, $condition=null, $joinType='inner')
$connection
Definition: bulk.php:13
$table
Definition: trigger.php:14