Helper.php 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. <?php
  2. /**
  3. * DB helper class for MySql Magento DB Adapter
  4. *
  5. * Copyright © Magento, Inc. All rights reserved.
  6. * See COPYING.txt for license details.
  7. */
  8. namespace Magento\Framework\DB;
  9. /**
  10. * DataBase Helper
  11. */
  12. class Helper extends \Magento\Framework\DB\Helper\AbstractHelper
  13. {
  14. /**
  15. * Returns array of quoted orders with direction
  16. *
  17. * @param \Magento\Framework\DB\Select $select
  18. * @param bool $autoReset
  19. * @return array
  20. */
  21. protected function _prepareOrder(\Magento\Framework\DB\Select $select, $autoReset = false)
  22. {
  23. $selectOrders = $select->getPart(\Magento\Framework\DB\Select::ORDER);
  24. if (!$selectOrders) {
  25. return [];
  26. }
  27. $orders = [];
  28. foreach ($selectOrders as $term) {
  29. if (is_array($term)) {
  30. if (!is_numeric($term[0])) {
  31. $orders[] = sprintf('%s %s', $this->getConnection()->quoteIdentifier($term[0], true), $term[1]);
  32. }
  33. } else {
  34. if (!is_numeric($term)) {
  35. $orders[] = $this->getConnection()->quoteIdentifier($term, true);
  36. }
  37. }
  38. }
  39. if ($autoReset) {
  40. $select->reset(\Magento\Framework\DB\Select::ORDER);
  41. }
  42. return $orders;
  43. }
  44. /**
  45. * Truncate alias name from field.
  46. *
  47. * Result string depends from second optional argument $reverse
  48. * which can be true if you need the first part of the field.
  49. * Field can be with 'dot' delimiter.
  50. *
  51. * @param string $field
  52. * @param bool $reverse OPTIONAL
  53. * @return string
  54. */
  55. protected function _truncateAliasName($field, $reverse = false)
  56. {
  57. $string = $field;
  58. if (!is_numeric($field) && (strpos($field, '.') !== false)) {
  59. $size = strpos($field, '.');
  60. if ($reverse) {
  61. $string = substr($field, 0, $size);
  62. } else {
  63. $string = substr($field, $size + 1);
  64. }
  65. }
  66. return $string;
  67. }
  68. /**
  69. * Returns quoted group by fields
  70. *
  71. * @param \Magento\Framework\DB\Select $select
  72. * @param bool $autoReset
  73. * @return array
  74. */
  75. protected function _prepareGroup(\Magento\Framework\DB\Select $select, $autoReset = false)
  76. {
  77. $selectGroups = $select->getPart(\Magento\Framework\DB\Select::GROUP);
  78. if (!$selectGroups) {
  79. return [];
  80. }
  81. $groups = [];
  82. foreach ($selectGroups as $term) {
  83. $groups[] = $this->getConnection()->quoteIdentifier($term, true);
  84. }
  85. if ($autoReset) {
  86. $select->reset(\Magento\Framework\DB\Select::GROUP);
  87. }
  88. return $groups;
  89. }
  90. /**
  91. * Prepare and returns having array
  92. *
  93. * @param \Magento\Framework\DB\Select $select
  94. * @param bool $autoReset
  95. * @return array
  96. * @throws \Zend_Db_Exception
  97. */
  98. protected function _prepareHaving(\Magento\Framework\DB\Select $select, $autoReset = false)
  99. {
  100. $selectHavings = $select->getPart(\Magento\Framework\DB\Select::HAVING);
  101. if (!$selectHavings) {
  102. return [];
  103. }
  104. $havings = [];
  105. $columns = $select->getPart(\Magento\Framework\DB\Select::COLUMNS);
  106. foreach ($columns as $columnEntry) {
  107. $correlationName = (string)$columnEntry[1];
  108. $column = $columnEntry[2];
  109. foreach ($selectHavings as $having) {
  110. /**
  111. * Looking for column expression in the having clause
  112. */
  113. if (strpos($having, $correlationName) !== false) {
  114. if (is_string($column)) {
  115. /**
  116. * Replace column expression to column alias in having clause
  117. */
  118. $havings[] = str_replace($correlationName, $column, $having);
  119. } else {
  120. throw new \Zend_Db_Exception(
  121. sprintf("Can't prepare expression without column alias: '%s'", $correlationName)
  122. );
  123. }
  124. }
  125. }
  126. }
  127. if ($autoReset) {
  128. $select->reset(\Magento\Framework\DB\Select::HAVING);
  129. }
  130. return $havings;
  131. }
  132. /**
  133. * Assemble limit
  134. *
  135. * @param string $query
  136. * @param int $limitCount
  137. * @param int $limitOffset
  138. * @param array $columnList
  139. * @return string
  140. */
  141. protected function _assembleLimit($query, $limitCount, $limitOffset, $columnList = [])
  142. {
  143. if ($limitCount !== null) {
  144. $limitCount = (int)$limitCount;
  145. if ($limitCount <= 0) {
  146. //throw new \Exception("LIMIT argument count={$limitCount} is not valid");
  147. }
  148. $limitOffset = (int)$limitOffset;
  149. if ($limitOffset < 0) {
  150. //throw new \Exception("LIMIT argument offset={$limitOffset} is not valid");
  151. }
  152. if ($limitOffset + $limitCount != $limitOffset + 1) {
  153. $columns = [];
  154. foreach ($columnList as $columnEntry) {
  155. $columns[] = $columnEntry[2] ? $columnEntry[2] : $columnEntry[1];
  156. }
  157. $query = sprintf('%s LIMIT %s, %s', $query, $limitCount, $limitOffset);
  158. }
  159. }
  160. return $query;
  161. }
  162. /**
  163. * Prepare select column list
  164. *
  165. * @param \Magento\Framework\DB\Select $select
  166. * @param string|null $groupByCondition OPTIONAL
  167. * @return mixed|array
  168. * @throws \Zend_Db_Exception
  169. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  170. * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  171. */
  172. public function prepareColumnsList(\Magento\Framework\DB\Select $select, $groupByCondition = null)
  173. {
  174. if (!count($select->getPart(\Magento\Framework\DB\Select::FROM))) {
  175. return $select->getPart(\Magento\Framework\DB\Select::COLUMNS);
  176. }
  177. $columns = $select->getPart(\Magento\Framework\DB\Select::COLUMNS);
  178. $tables = $select->getPart(\Magento\Framework\DB\Select::FROM);
  179. $preparedColumns = [];
  180. foreach ($columns as $columnEntry) {
  181. list($correlationName, $column, $alias) = $columnEntry;
  182. if ($column instanceof \Zend_Db_Expr) {
  183. if ($alias !== null) {
  184. if (preg_match('/(^|[^a-zA-Z_])^(SELECT)?(SUM|MIN|MAX|AVG|COUNT)\s*\(/i', $column)) {
  185. $column = new \Zend_Db_Expr($column);
  186. }
  187. $preparedColumns[strtoupper($alias)] = [null, $column, $alias];
  188. } else {
  189. throw new \Zend_Db_Exception("Can't prepare expression without alias");
  190. }
  191. } else {
  192. if ($column == \Magento\Framework\DB\Select::SQL_WILDCARD) {
  193. if ($tables[$correlationName]['tableName'] instanceof \Zend_Db_Expr) {
  194. throw new \Zend_Db_Exception(
  195. "Can't prepare expression when tableName is instance of \Zend_Db_Expr"
  196. );
  197. }
  198. $tableColumns = $this->getConnection()->describeTable($tables[$correlationName]['tableName']);
  199. foreach (array_keys($tableColumns) as $col) {
  200. $preparedColumns[strtoupper($col)] = [$correlationName, $col, null];
  201. }
  202. } else {
  203. $columnKey = $alias === null ? $column : $alias;
  204. $preparedColumns[strtoupper($columnKey)] = [$correlationName, $column, $alias];
  205. }
  206. }
  207. }
  208. return $preparedColumns;
  209. }
  210. /**
  211. * Add prepared column group_concat expression
  212. *
  213. * @param \Magento\Framework\DB\Select $select
  214. * @param string $fieldAlias Field alias which will be added with column group_concat expression
  215. * @param string $fields
  216. * @param string $groupConcatDelimiter
  217. * @param string $fieldsDelimiter
  218. * @param string $additionalWhere
  219. * @return \Magento\Framework\DB\Select
  220. */
  221. public function addGroupConcatColumn(
  222. $select,
  223. $fieldAlias,
  224. $fields,
  225. $groupConcatDelimiter = ',',
  226. $fieldsDelimiter = '',
  227. $additionalWhere = ''
  228. ) {
  229. if (is_array($fields)) {
  230. $fieldExpr = $this->getConnection()->getConcatSql($fields, $fieldsDelimiter);
  231. } else {
  232. $fieldExpr = $fields;
  233. }
  234. if ($additionalWhere) {
  235. $fieldExpr = $this->getConnection()->getCheckSql($additionalWhere, $fieldExpr, "''");
  236. }
  237. $separator = '';
  238. if ($groupConcatDelimiter) {
  239. $separator = sprintf(" SEPARATOR '%s'", $groupConcatDelimiter);
  240. }
  241. $select->columns([$fieldAlias => new \Zend_Db_Expr(sprintf('GROUP_CONCAT(%s%s)', $fieldExpr, $separator))]);
  242. return $select;
  243. }
  244. /**
  245. * Returns expression of days passed from $startDate to $endDate
  246. *
  247. * @param string|\Zend_Db_Expr $startDate
  248. * @param string|\Zend_Db_Expr $endDate
  249. * @return \Zend_Db_Expr
  250. */
  251. public function getDateDiff($startDate, $endDate)
  252. {
  253. $dateDiff = '(TO_DAYS(' . $endDate . ') - TO_DAYS(' . $startDate . '))';
  254. return new \Zend_Db_Expr($dateDiff);
  255. }
  256. /**
  257. * Escapes and quotes LIKE value.
  258. * Stating escape symbol in expression is not required, because we use standard MySQL escape symbol.
  259. * For options and escaping see escapeLikeValue().
  260. *
  261. * @param string $value
  262. * @param array $options
  263. * @return \Zend_Db_Expr
  264. *
  265. * @see escapeLikeValue()
  266. */
  267. public function addLikeEscape($value, $options = [])
  268. {
  269. $value = $this->escapeLikeValue($value, $options);
  270. return new \Zend_Db_Expr($this->getConnection()->quote($value));
  271. }
  272. }