Generator.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\DB\Query;
  7. use Magento\Framework\Exception\LocalizedException;
  8. /**
  9. * Query generator
  10. */
  11. class Generator
  12. {
  13. /**
  14. * @var \Magento\Framework\DB\Query\BatchIteratorFactory
  15. */
  16. private $iteratorFactory;
  17. /**
  18. * @var \Magento\Framework\DB\Query\BatchRangeIteratorFactory
  19. */
  20. private $rangeIteratorFactory;
  21. /**
  22. * Initialize dependencies.
  23. *
  24. * @param BatchIteratorFactory $iteratorFactory
  25. * @param BatchRangeIteratorFactory $rangeIteratorFactory
  26. */
  27. public function __construct(
  28. BatchIteratorFactory $iteratorFactory,
  29. BatchRangeIteratorFactory $rangeIteratorFactory = null
  30. ) {
  31. $this->iteratorFactory = $iteratorFactory;
  32. $this->rangeIteratorFactory = $rangeIteratorFactory ?: \Magento\Framework\App\ObjectManager::getInstance()
  33. ->get(\Magento\Framework\DB\Query\BatchRangeIteratorFactory::class);
  34. }
  35. /**
  36. * Generate select query list with predefined items count in each select item
  37. *
  38. * Generates select parameters - batchSize, correlationName, rangeField, rangeFieldAlias
  39. * to obtain instance of iterator. The behavior of the iterator will depend on the parameters passed to it.
  40. * For example: by default for $batchStrategy parameter used
  41. * \Magento\Framework\DB\Query\BatchIteratorInterface::UNIQUE_FIELD_ITERATOR. This parameter is determine, what
  42. * instance of Iterator will be returned.
  43. *
  44. * Other params:
  45. * select - represents the select object, that should be passed into Iterator.
  46. * batchSize - sets the number of items in select.
  47. * correlationName - is the base table involved in the select.
  48. * rangeField - this is the basic field which used to split select.
  49. * rangeFieldAlias - alias of range field.
  50. *
  51. * @see \Magento\Framework\DB\Query\BatchIteratorInterface
  52. * @param string $rangeField - Field which is used for the range mechanism in select
  53. * @param \Magento\Framework\DB\Select $select
  54. * @param int $batchSize - Determines on how many parts will be divided
  55. * the number of values in the select.
  56. * @param string $batchStrategy It determines which strategy is chosen
  57. * @return BatchIteratorInterface
  58. * @throws LocalizedException Throws if incorrect "FROM" part in \Select exists
  59. */
  60. public function generate(
  61. $rangeField,
  62. \Magento\Framework\DB\Select $select,
  63. $batchSize = 100,
  64. $batchStrategy = \Magento\Framework\DB\Query\BatchIteratorInterface::UNIQUE_FIELD_ITERATOR
  65. ) {
  66. if ($batchStrategy == \Magento\Framework\DB\Query\BatchIteratorInterface::NON_UNIQUE_FIELD_ITERATOR) {
  67. return $this->generateByRange($rangeField, $select, $batchSize);
  68. }
  69. $fromSelect = $select->getPart(\Magento\Framework\DB\Select::FROM);
  70. if (empty($fromSelect)) {
  71. throw new LocalizedException(
  72. new \Magento\Framework\Phrase(
  73. 'The select object must have the correct "FROM" part. Verify and try again.'
  74. )
  75. );
  76. }
  77. $fieldCorrelationName = '';
  78. foreach ($fromSelect as $correlationName => $fromPart) {
  79. if ($fromPart['joinType'] == \Magento\Framework\DB\Select::FROM) {
  80. $fieldCorrelationName = $correlationName;
  81. break;
  82. }
  83. }
  84. $columns = $select->getPart(\Magento\Framework\DB\Select::COLUMNS);
  85. /**
  86. * Calculate $rangeField alias
  87. */
  88. $rangeFieldAlias = $rangeField;
  89. foreach ($columns as $column) {
  90. list($table, $columnName, $alias) = $column;
  91. if ($table == $fieldCorrelationName && $columnName == $rangeField) {
  92. $rangeFieldAlias = $alias ?: $rangeField;
  93. break;
  94. }
  95. }
  96. return $this->iteratorFactory->create(
  97. [
  98. 'select' => $select,
  99. 'batchSize' => $batchSize,
  100. 'correlationName' => $fieldCorrelationName,
  101. 'rangeField' => $rangeField,
  102. 'rangeFieldAlias' => $rangeFieldAlias
  103. ]
  104. );
  105. }
  106. /**
  107. * Generate select query list with predefined items count in each select item.
  108. *
  109. * Generates select parameters - batchSize, correlationName, rangeField, rangeFieldAlias
  110. * to obtain instance of BatchRangeIterator.
  111. *
  112. * Other params:
  113. * select - represents the select object, that should be passed into Iterator.
  114. * batchSize - sets the number of items in select.
  115. * correlationName - is the base table involved in the select.
  116. * rangeField - this is the basic field which used to split select.
  117. * rangeFieldAlias - alias of range field.
  118. *
  119. * @see BatchRangeIterator
  120. * @param string $rangeField - Field which is used for the range mechanism in select
  121. * @param \Magento\Framework\DB\Select $select
  122. * @param int $batchSize
  123. * @return BatchIteratorInterface
  124. * @throws LocalizedException Throws if incorrect "FROM" part in \Select exists
  125. * @see \Magento\Framework\DB\Query\Generator
  126. * @deprecated 100.1.8 This is a temporary solution which is made due to the fact that we
  127. * can't change method generate() in version 2.1 due to a backwards incompatibility.
  128. * In 2.2 version need to use original method generate() with additional parameter.
  129. */
  130. public function generateByRange(
  131. $rangeField,
  132. \Magento\Framework\DB\Select $select,
  133. $batchSize = 100
  134. ) {
  135. $fromSelect = $select->getPart(\Magento\Framework\DB\Select::FROM);
  136. if (empty($fromSelect)) {
  137. throw new LocalizedException(
  138. new \Magento\Framework\Phrase(
  139. 'The select object must have the correct "FROM" part. Verify and try again.'
  140. )
  141. );
  142. }
  143. $fieldCorrelationName = '';
  144. foreach ($fromSelect as $correlationName => $fromPart) {
  145. if ($fromPart['joinType'] == \Magento\Framework\DB\Select::FROM) {
  146. $fieldCorrelationName = $correlationName;
  147. break;
  148. }
  149. }
  150. $columns = $select->getPart(\Magento\Framework\DB\Select::COLUMNS);
  151. /**
  152. * Calculate $rangeField alias
  153. */
  154. $rangeFieldAlias = $rangeField;
  155. foreach ($columns as $column) {
  156. list($table, $columnName, $alias) = $column;
  157. if ($table == $fieldCorrelationName && $columnName == $rangeField) {
  158. $rangeFieldAlias = $alias ?: $rangeField;
  159. break;
  160. }
  161. }
  162. return $this->rangeIteratorFactory->create(
  163. [
  164. 'select' => $select,
  165. 'batchSize' => $batchSize,
  166. 'correlationName' => $fieldCorrelationName,
  167. 'rangeField' => $rangeField,
  168. 'rangeFieldAlias' => $rangeFieldAlias,
  169. ]
  170. );
  171. }
  172. }