Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
AbstractDb.php
Go to the documentation of this file.
1 <?php
7 
14 use Psr\Log\LoggerInterface as Logger;
15 
24 {
30  protected $_conn;
31 
37  protected $_select;
38 
46  protected $_idFieldName;
47 
53  protected $_bindParams = [];
54 
61  protected $_data = null;
62 
68  protected $_map = null;
69 
75  protected $_fetchStmt = null;
76 
82  protected $_isOrdersRendered = false;
83 
87  protected $_logger;
88 
92  private $_fetchStrategy;
93 
100 
107  public function __construct(
108  EntityFactoryInterface $entityFactory,
109  Logger $logger,
110  FetchStrategyInterface $fetchStrategy,
111  \Magento\Framework\DB\Adapter\AdapterInterface $connection = null
112  ) {
113  parent::__construct($entityFactory);
114  $this->_fetchStrategy = $fetchStrategy;
115  if ($connection !== null) {
116  $this->setConnection($connection);
117  }
118  $this->_logger = $logger;
119  }
120 
126  abstract public function getResource();
127 
135  public function addBindParam($name, $value)
136  {
137  $this->_bindParams[$name] = $value;
138  return $this;
139  }
140 
147  protected function _setIdFieldName($fieldName)
148  {
149  $this->_idFieldName = $fieldName;
150  return $this;
151  }
152 
158  public function getIdFieldName()
159  {
160  return $this->_idFieldName;
161  }
162 
169  protected function _getItemId(\Magento\Framework\DataObject $item)
170  {
171  if ($field = $this->getIdFieldName()) {
172  return $item->getData($field);
173  }
174  return parent::_getItemId($item);
175  }
176 
184  public function setConnection(\Magento\Framework\DB\Adapter\AdapterInterface $conn)
185  {
186  $this->_conn = $conn;
187  $this->_select = $this->_conn->select();
188  $this->_isOrdersRendered = false;
189  return $this;
190  }
191 
197  public function getSelect()
198  {
199  return $this->_select;
200  }
201 
207  public function getConnection()
208  {
209  return $this->_conn;
210  }
211 
217  public function getSize()
218  {
219  if ($this->_totalRecords === null) {
220  $sql = $this->getSelectCountSql();
221  $this->_totalRecords = $this->getConnection()->fetchOne($sql, $this->_bindParams);
222  }
223  return (int)$this->_totalRecords;
224  }
225 
231  public function getSelectCountSql()
232  {
233  $this->_renderFilters();
234 
235  $countSelect = clone $this->getSelect();
236  $countSelect->reset(\Magento\Framework\DB\Select::ORDER);
237  $countSelect->reset(\Magento\Framework\DB\Select::LIMIT_COUNT);
238  $countSelect->reset(\Magento\Framework\DB\Select::LIMIT_OFFSET);
239  $countSelect->reset(\Magento\Framework\DB\Select::COLUMNS);
240 
241  $part = $this->getSelect()->getPart(\Magento\Framework\DB\Select::GROUP);
242  if (!is_array($part) || !count($part)) {
243  $countSelect->columns(new \Zend_Db_Expr('COUNT(*)'));
244  return $countSelect;
245  }
246 
247  $countSelect->reset(\Magento\Framework\DB\Select::GROUP);
248  $group = $this->getSelect()->getPart(\Magento\Framework\DB\Select::GROUP);
249  $countSelect->columns(new \Zend_Db_Expr(("COUNT(DISTINCT ".implode(", ", $group).")")));
250  return $countSelect;
251  }
252 
259  public function getSelectSql($stringMode = false)
260  {
261  if ($stringMode) {
262  return $this->_select->__toString();
263  }
264  return $this->_select;
265  }
266 
274  public function setOrder($field, $direction = self::SORT_ORDER_DESC)
275  {
276  return $this->_setOrder($field, $direction);
277  }
278 
286  public function addOrder($field, $direction = self::SORT_ORDER_DESC)
287  {
288  return $this->_setOrder($field, $direction);
289  }
290 
298  public function unshiftOrder($field, $direction = self::SORT_ORDER_DESC)
299  {
300  return $this->_setOrder($field, $direction, true);
301  }
302 
311  private function _setOrder($field, $direction, $unshift = false)
312  {
313  $this->_isOrdersRendered = false;
314  $field = (string)$this->_getMappedField($field);
315  $direction = strtoupper($direction) == self::SORT_ORDER_ASC ? self::SORT_ORDER_ASC : self::SORT_ORDER_DESC;
316 
317  unset($this->_orders[$field]);
318  // avoid ordering by the same field twice
319  if ($unshift) {
320  $orders = [$field => $direction];
321  foreach ($this->_orders as $key => $dir) {
322  $orders[$key] = $dir;
323  }
324  $this->_orders = $orders;
325  } else {
326  $this->_orders[$field] = $direction;
327  }
328  return $this;
329  }
330 
336  protected function _renderFilters()
337  {
338  if ($this->_isFiltersRendered) {
339  return $this;
340  }
341 
342  $this->_renderFiltersBefore();
343 
344  foreach ($this->_filters as $filter) {
345  switch ($filter['type']) {
346  case 'or':
347  $condition = $this->_conn->quoteInto($filter['field'] . '=?', $filter['value']);
348  $this->_select->orWhere($condition);
349  break;
350  case 'string':
351  $this->_select->where($filter['value']);
352  break;
353  case 'public':
354  $field = $this->_getMappedField($filter['field']);
355  $condition = $filter['value'];
356  $this->_select->where($this->_getConditionSql($field, $condition), null, Select::TYPE_CONDITION);
357  break;
358  default:
359  $condition = $this->_conn->quoteInto($filter['field'] . '=?', $filter['value']);
360  $this->_select->where($condition);
361  }
362  }
363  $this->_isFiltersRendered = true;
364  return $this;
365  }
366 
372  protected function _renderFiltersBefore()
373  {
374  }
375 
385  public function addFieldToFilter($field, $condition = null)
386  {
387  if (is_array($field)) {
388  $conditions = [];
389  foreach ($field as $key => $value) {
390  $conditions[] = $this->_translateCondition($value, isset($condition[$key]) ? $condition[$key] : null);
391  }
392 
393  $resultCondition = '(' . implode(') ' . \Magento\Framework\DB\Select::SQL_OR . ' (', $conditions) . ')';
394  } else {
395  $resultCondition = $this->_translateCondition($field, $condition);
396  }
397 
398  $this->_select->where($resultCondition, null, Select::TYPE_CONDITION);
399 
400  return $this;
401  }
402 
410  protected function _translateCondition($field, $condition)
411  {
412  $field = $this->_getMappedField($field);
413  return $this->_getConditionSql($this->getConnection()->quoteIdentifier($field), $condition);
414  }
415 
422  protected function _getMappedField($field)
423  {
424  $mapper = $this->_getMapper();
425 
426  if (isset($mapper['fields'][$field])) {
427  $mappedField = $mapper['fields'][$field];
428  } else {
429  $mappedField = $field;
430  }
431 
432  return $mappedField;
433  }
434 
440  protected function _getMapper()
441  {
442  if (isset($this->_map)) {
443  return $this->_map;
444  } else {
445  return false;
446  }
447  }
448 
480  protected function _getConditionSql($fieldName, $condition)
481  {
482  return $this->getConnection()->prepareSqlCondition($fieldName, $condition);
483  }
484 
491  protected function _getConditionFieldName($fieldName)
492  {
493  return $fieldName;
494  }
495 
501  protected function _renderOrders()
502  {
503  if (!$this->_isOrdersRendered) {
504  foreach ($this->_orders as $field => $direction) {
505  $this->_select->order(new \Zend_Db_Expr($field . ' ' . $direction));
506  }
507  $this->_isOrdersRendered = true;
508  }
509 
510  return $this;
511  }
512 
518  protected function _renderLimit()
519  {
520  if ($this->_pageSize) {
521  $this->_select->limitPage($this->getCurPage(), $this->_pageSize);
522  }
523 
524  return $this;
525  }
526 
533  public function distinct($flag)
534  {
535  $this->_select->distinct($flag);
536  return $this;
537  }
538 
544  protected function _beforeLoad()
545  {
546  return $this;
547  }
548 
556  public function load($printQuery = false, $logQuery = false)
557  {
558  if ($this->isLoaded()) {
559  return $this;
560  }
561 
562  return $this->loadWithFilter($printQuery, $logQuery);
563  }
564 
572  public function loadWithFilter($printQuery = false, $logQuery = false)
573  {
574  $this->_beforeLoad();
575  $this->_renderFilters()->_renderOrders()->_renderLimit();
576  $this->printLogQuery($printQuery, $logQuery);
577  $data = $this->getData();
578  $this->resetData();
579  if (is_array($data)) {
580  foreach ($data as $row) {
581  $item = $this->getNewEmptyItem();
582  if ($this->getIdFieldName()) {
583  $item->setIdFieldName($this->getIdFieldName());
584  }
585  $item->addData($row);
586  $this->beforeAddLoadedItem($item);
587  $this->addItem($item);
588  }
589  }
590  $this->_setIsLoaded();
591  $this->_afterLoad();
592  return $this;
593  }
594 
601  protected function beforeAddLoadedItem(\Magento\Framework\DataObject $item)
602  {
603  return $item;
604  }
605 
613  public function fetchItem()
614  {
615  if (null === $this->_fetchStmt) {
616  $this->_renderOrders()->_renderLimit();
617 
618  $this->_fetchStmt = $this->getConnection()->query($this->getSelect());
619  }
620  $data = $this->_fetchStmt->fetch();
621  if (!empty($data) && is_array($data)) {
622  $item = $this->getNewEmptyItem();
623  if ($this->getIdFieldName()) {
624  $item->setIdFieldName($this->getIdFieldName());
625  }
626  $item->setData($data);
627 
628  return $item;
629  }
630  return false;
631  }
632 
641  protected function _toOptionArray($valueField = null, $labelField = 'name', $additional = [])
642  {
643  if ($valueField === null) {
644  $valueField = $this->getIdFieldName();
645  }
646  return parent::_toOptionArray($valueField, $labelField, $additional);
647  }
648 
656  protected function _toOptionHash($valueField = null, $labelField = 'name')
657  {
658  if ($valueField === null) {
659  $valueField = $this->getIdFieldName();
660  }
661  return parent::_toOptionHash($valueField, $labelField);
662  }
663 
669  public function getData()
670  {
671  if ($this->_data === null) {
672  $this->_renderFilters()->_renderOrders()->_renderLimit();
673  $select = $this->getSelect();
674  $this->_data = $this->_fetchAll($select);
675  $this->_afterLoadData();
676  }
677  return $this->_data;
678  }
679 
685  protected function _afterLoadData()
686  {
687  return $this;
688  }
689 
695  public function resetData()
696  {
697  $this->_data = null;
698  return $this;
699  }
700 
706  protected function _afterLoad()
707  {
708  return $this;
709  }
710 
718  public function loadData($printQuery = false, $logQuery = false)
719  {
720  return $this->load($printQuery, $logQuery);
721  }
722 
731  public function printLogQuery($printQuery = false, $logQuery = false, $sql = null)
732  {
733  if ($printQuery || $this->getFlag('print_query')) {
734  echo $sql === null ? $this->getSelect()->__toString() : $sql;
735  }
736 
737  if ($logQuery || $this->getFlag('log_query')) {
738  $this->_logQuery($sql);
739  }
740  return $this;
741  }
742 
749  protected function _logQuery($sql)
750  {
751  $this->_logger->info($sql === null ? $this->getSelect()->__toString() : $sql);
752  }
753 
759  protected function _reset()
760  {
761  $this->getSelect()->reset();
762  $this->_initSelect();
763  $this->_setIsLoaded(false);
764  $this->_items = [];
765  $this->_data = null;
766  $this->extensionAttributesJoinProcessor = null;
767  return $this;
768  }
769 
776  protected function _fetchAll(Select $select)
777  {
778  $data = $this->_fetchStrategy->fetchAll($select, $this->_bindParams);
779  if ($this->extensionAttributesJoinProcessor) {
780  foreach ($data as $key => $dataItem) {
781  $data[$key] = $this->extensionAttributesJoinProcessor->extractExtensionAttributes(
782  $this->_itemObjectClass,
783  $dataItem
784  );
785  }
786  }
787  return $data;
788  }
789 
798  public function addFilterToMap($filter, $alias, $group = 'fields')
799  {
800  if ($this->_map === null) {
801  $this->_map = [$group => []];
802  } elseif (empty($this->_map[$group])) {
803  $this->_map[$group] = [];
804  }
805  $this->_map[$group][$filter] = $alias;
806 
807  return $this;
808  }
809 
815  public function __clone()
816  {
817  if (is_object($this->_select)) {
818  $this->_select = clone $this->_select;
819  }
820  }
821 
827  protected function _initSelect()
828  {
829  // no implementation, should be overridden in children classes
830  }
831 
839  public function joinExtensionAttribute(
840  JoinDataInterface $join,
842  ) {
843  $selectFrom = $this->getSelect()->getPart(\Magento\Framework\DB\Select::FROM);
844  $joinRequired = !isset($selectFrom[$join->getReferenceTableAlias()]);
845  if ($joinRequired) {
846  $joinOn = $this->getMainTableAlias() . '.' . $join->getJoinField()
847  . ' = ' . $join->getReferenceTableAlias() . '.' . $join->getReferenceField();
848  $this->getSelect()->joinLeft(
849  [$join->getReferenceTableAlias() => $this->getResource()->getTable($join->getReferenceTable())],
850  $joinOn,
851  []
852  );
853  }
854  $columns = [];
855  foreach ($join->getSelectFields() as $selectField) {
856  $fieldWIthDbPrefix = $selectField[JoinDataInterface::SELECT_FIELD_WITH_DB_PREFIX];
857  $columns[$selectField[JoinDataInterface::SELECT_FIELD_INTERNAL_ALIAS]] = $fieldWIthDbPrefix;
858  $this->addFilterToMap($selectField[JoinDataInterface::SELECT_FIELD_EXTERNAL_ALIAS], $fieldWIthDbPrefix);
859  }
860  $this->getSelect()->columns($columns);
861  $this->extensionAttributesJoinProcessor = $extensionAttributesJoinProcessor;
862  return $this;
863  }
864 
870  public function getItemObjectClass()
871  {
873  }
874 
881  private function getMainTableAlias()
882  {
883  foreach ($this->getSelect()->getPart(\Magento\Framework\DB\Select::FROM) as $tableAlias => $tableMetadata) {
884  if ($tableMetadata['joinType'] == 'from') {
885  return $tableAlias;
886  }
887  }
888  throw new \LogicException("Main table cannot be identified.");
889  }
890 
895  public function __sleep()
896  {
897  return array_diff(
898  parent::__sleep(),
899  ['_fetchStrategy', '_logger', '_conn', 'extensionAttributesJoinProcessor']
900  );
901  }
902 
907  public function __wakeup()
908  {
911  $this->_logger = $objectManager->get(Logger::class);
912  $this->_fetchStrategy = $objectManager->get(FetchStrategyInterface::class);
913  $this->_conn = $objectManager->get(ResourceConnection::class)->getConnection();
914  }
915 }
addFilterToMap($filter, $alias, $group='fields')
Definition: AbstractDb.php:798
const ORDER
Definition: Select.php:54
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
addFieldToFilter($field, $condition=null)
Definition: AbstractDb.php:385
printLogQuery($printQuery=false, $logQuery=false, $sql=null)
Definition: AbstractDb.php:731
_toOptionArray($valueField=null, $labelField='name', $additional=[])
Definition: AbstractDb.php:641
$objectManager
Definition: bootstrap.php:17
$group
Definition: sections.phtml:16
unshiftOrder($field, $direction=self::SORT_ORDER_DESC)
Definition: AbstractDb.php:298
$logger
const FROM
Definition: Select.php:49
$columns
Definition: default.phtml:15
setConnection(\Magento\Framework\DB\Adapter\AdapterInterface $conn)
Definition: AbstractDb.php:184
loadData($printQuery=false, $logQuery=false)
Definition: AbstractDb.php:718
$value
Definition: gender.phtml:16
loadWithFilter($printQuery=false, $logQuery=false)
Definition: AbstractDb.php:572
const COLUMNS
Definition: Select.php:48
const LIMIT_OFFSET
Definition: Select.php:56
_getItemId(\Magento\Framework\DataObject $item)
Definition: AbstractDb.php:169
const GROUP
Definition: Select.php:52
load($printQuery=false, $logQuery=false)
Definition: AbstractDb.php:556
__construct(EntityFactoryInterface $entityFactory, Logger $logger, FetchStrategyInterface $fetchStrategy, \Magento\Framework\DB\Adapter\AdapterInterface $connection=null)
Definition: AbstractDb.php:107
addOrder($field, $direction=self::SORT_ORDER_DESC)
Definition: AbstractDb.php:286
setOrder($field, $direction=self::SORT_ORDER_DESC)
Definition: AbstractDb.php:274
joinExtensionAttribute(JoinDataInterface $join, JoinProcessorInterface $extensionAttributesJoinProcessor)
Definition: AbstractDb.php:839
if(!trim($html)) $alias
Definition: details.phtml:20
$connection
Definition: bulk.php:13
_toOptionHash($valueField=null, $labelField='name')
Definition: AbstractDb.php:656
beforeAddLoadedItem(\Magento\Framework\DataObject $item)
Definition: AbstractDb.php:601
const LIMIT_COUNT
Definition: Select.php:55
addItem(\Magento\Framework\DataObject $item)
Definition: Collection.php:399
const SQL_OR
Definition: Select.php:79
if(!isset($_GET['name'])) $name
Definition: log.php:14