PageRenderTime 44ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/station-games/vendor/cakephp/cakephp/src/Database/QueryCompiler.php

https://gitlab.com/ViniciusP/project-games
PHP | 337 lines | 169 code | 23 blank | 145 comment | 21 complexity | d9064d0b3f8dbadfc2c18ff4beecdc21 MD5 | raw file
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. * @link http://cakephp.org CakePHP(tm) Project
  12. * @since 3.0.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Database;
  16. /**
  17. * Responsible for compiling a Query object into its SQL representation
  18. *
  19. * @internal
  20. */
  21. class QueryCompiler
  22. {
  23. /**
  24. * List of sprintf templates that will be used for compiling the SQL for
  25. * this query. There are some clauses that can be built as just as the
  26. * direct concatenation of the internal parts, those are listed here.
  27. *
  28. * @var array
  29. */
  30. protected $_templates = [
  31. 'delete' => 'DELETE',
  32. 'update' => 'UPDATE %s',
  33. 'where' => ' WHERE %s',
  34. 'group' => ' GROUP BY %s ',
  35. 'having' => ' HAVING %s ',
  36. 'order' => ' %s',
  37. 'limit' => ' LIMIT %s',
  38. 'offset' => ' OFFSET %s',
  39. 'epilog' => ' %s'
  40. ];
  41. /**
  42. * The list of query clauses to traverse for generating a SELECT statement
  43. *
  44. * @var array
  45. */
  46. protected $_selectParts = [
  47. 'select', 'from', 'join', 'where', 'group', 'having', 'order', 'limit',
  48. 'offset', 'union', 'epilog'
  49. ];
  50. /**
  51. * The list of query clauses to traverse for generating an UPDATE statement
  52. *
  53. * @var array
  54. */
  55. protected $_updateParts = ['update', 'set', 'where', 'epilog'];
  56. /**
  57. * The list of query clauses to traverse for generating a DELETE statement
  58. *
  59. * @var array
  60. */
  61. protected $_deleteParts = ['delete', 'from', 'where', 'epilog'];
  62. /**
  63. * The list of query clauses to traverse for generating an INSERT statement
  64. *
  65. * @var array
  66. */
  67. protected $_insertParts = ['insert', 'values', 'epilog'];
  68. /**
  69. * Indicate whether or not this query dialect supports ordered unions.
  70. *
  71. * Overridden in subclasses.
  72. *
  73. * @var bool
  74. */
  75. protected $_orderedUnion = true;
  76. /**
  77. * Returns the SQL representation of the provided query after generating
  78. * the placeholders for the bound values using the provided generator
  79. *
  80. * @param \Cake\Database\Query $query The query that is being compiled
  81. * @param \Cake\Database\ValueBinder $generator the placeholder generator to be used in expressions
  82. * @return \Closure
  83. */
  84. public function compile(Query $query, ValueBinder $generator)
  85. {
  86. $sql = '';
  87. $type = $query->type();
  88. $query->traverse(
  89. $this->_sqlCompiler($sql, $query, $generator),
  90. $this->{'_' . $type . 'Parts'}
  91. );
  92. // Propagate bound parameters from sub-queries if the
  93. // placeholders can be found in the SQL statement.
  94. if ($query->valueBinder() !== $generator) {
  95. foreach ($query->valueBinder()->bindings() as $binding) {
  96. $placeholder = ':' . $binding['placeholder'];
  97. if (preg_match('/' . $placeholder . '(?:\W|$)/', $sql) > 0) {
  98. $generator->bind($placeholder, $binding['value'], $binding['type']);
  99. }
  100. }
  101. }
  102. return $sql;
  103. }
  104. /**
  105. * Returns a callable object that can be used to compile a SQL string representation
  106. * of this query.
  107. *
  108. * @param string $sql initial sql string to append to
  109. * @param \Cake\Database\Query $query The query that is being compiled
  110. * @param \Cake\Database\ValueBinder $generator The placeholder and value binder object
  111. * @return \Closure
  112. */
  113. protected function _sqlCompiler(&$sql, $query, $generator)
  114. {
  115. return function ($parts, $name) use (&$sql, $query, $generator) {
  116. if (!count($parts)) {
  117. return;
  118. }
  119. if ($parts instanceof ExpressionInterface) {
  120. $parts = [$parts->sql($generator)];
  121. }
  122. if (isset($this->_templates[$name])) {
  123. $parts = $this->_stringifyExpressions((array)$parts, $generator);
  124. return $sql .= sprintf($this->_templates[$name], implode(', ', $parts));
  125. }
  126. return $sql .= $this->{'_build' . ucfirst($name) . 'Part'}($parts, $query, $generator);
  127. };
  128. }
  129. /**
  130. * Helper function used to build the string representation of a SELECT clause,
  131. * it constructs the field list taking care of aliasing and
  132. * converting expression objects to string. This function also constructs the
  133. * DISTINCT clause for the query.
  134. *
  135. * @param array $parts list of fields to be transformed to string
  136. * @param \Cake\Database\Query $query The query that is being compiled
  137. * @param \Cake\Database\ValueBinder $generator the placeholder generator to be used in expressions
  138. * @return string
  139. */
  140. protected function _buildSelectPart($parts, $query, $generator)
  141. {
  142. $driver = $query->connection()->driver();
  143. $select = 'SELECT %s%s%s';
  144. if ($this->_orderedUnion && $query->clause('union')) {
  145. $select = '(SELECT %s%s%s';
  146. }
  147. $distinct = $query->clause('distinct');
  148. $modifiers = $query->clause('modifier') ?: null;
  149. $normalized = [];
  150. $parts = $this->_stringifyExpressions($parts, $generator);
  151. foreach ($parts as $k => $p) {
  152. if (!is_numeric($k)) {
  153. $p = $p . ' AS ' . $driver->quoteIdentifier($k);
  154. }
  155. $normalized[] = $p;
  156. }
  157. if ($distinct === true) {
  158. $distinct = 'DISTINCT ';
  159. }
  160. if (is_array($distinct)) {
  161. $distinct = $this->_stringifyExpressions($distinct, $generator);
  162. $distinct = sprintf('DISTINCT ON (%s) ', implode(', ', $distinct));
  163. }
  164. if ($modifiers !== null) {
  165. $modifiers = $this->_stringifyExpressions($modifiers, $generator);
  166. $modifiers = implode(' ', $modifiers) . ' ';
  167. }
  168. return sprintf($select, $distinct, $modifiers, implode(', ', $normalized));
  169. }
  170. /**
  171. * Helper function used to build the string representation of a FROM clause,
  172. * it constructs the tables list taking care of aliasing and
  173. * converting expression objects to string.
  174. *
  175. * @param array $parts list of tables to be transformed to string
  176. * @param \Cake\Database\Query $query The query that is being compiled
  177. * @param \Cake\Database\ValueBinder $generator the placeholder generator to be used in expressions
  178. * @return string
  179. */
  180. protected function _buildFromPart($parts, $query, $generator)
  181. {
  182. $select = ' FROM %s';
  183. $normalized = [];
  184. $parts = $this->_stringifyExpressions($parts, $generator);
  185. foreach ($parts as $k => $p) {
  186. if (!is_numeric($k)) {
  187. $p = $p . ' ' . $k;
  188. }
  189. $normalized[] = $p;
  190. }
  191. return sprintf($select, implode(', ', $normalized));
  192. }
  193. /**
  194. * Helper function used to build the string representation of multiple JOIN clauses,
  195. * it constructs the joins list taking care of aliasing and converting
  196. * expression objects to string in both the table to be joined and the conditions
  197. * to be used.
  198. *
  199. * @param array $parts list of joins to be transformed to string
  200. * @param \Cake\Database\Query $query The query that is being compiled
  201. * @param \Cake\Database\ValueBinder $generator the placeholder generator to be used in expressions
  202. * @return string
  203. */
  204. protected function _buildJoinPart($parts, $query, $generator)
  205. {
  206. $joins = '';
  207. foreach ($parts as $join) {
  208. if ($join['table'] instanceof ExpressionInterface) {
  209. $join['table'] = '(' . $join['table']->sql($generator) . ')';
  210. }
  211. $joins .= sprintf(' %s JOIN %s %s', $join['type'], $join['table'], $join['alias']);
  212. if (isset($join['conditions']) && count($join['conditions'])) {
  213. $joins .= sprintf(' ON %s', $join['conditions']->sql($generator));
  214. } else {
  215. $joins .= ' ON 1 = 1';
  216. }
  217. }
  218. return $joins;
  219. }
  220. /**
  221. * Helper function to generate SQL for SET expressions.
  222. *
  223. * @param array $parts List of keys & values to set.
  224. * @param \Cake\Database\Query $query The query that is being compiled
  225. * @param \Cake\Database\ValueBinder $generator the placeholder generator to be used in expressions
  226. * @return string
  227. */
  228. protected function _buildSetPart($parts, $query, $generator)
  229. {
  230. $set = [];
  231. foreach ($parts as $part) {
  232. if ($part instanceof ExpressionInterface) {
  233. $part = $part->sql($generator);
  234. }
  235. if ($part[0] === '(') {
  236. $part = substr($part, 1, -1);
  237. }
  238. $set[] = $part;
  239. }
  240. return ' SET ' . implode('', $set);
  241. }
  242. /**
  243. * Builds the SQL string for all the UNION clauses in this query, when dealing
  244. * with query objects it will also transform them using their configured SQL
  245. * dialect.
  246. *
  247. * @param array $parts list of queries to be operated with UNION
  248. * @param \Cake\Database\Query $query The query that is being compiled
  249. * @param \Cake\Database\ValueBinder $generator the placeholder generator to be used in expressions
  250. * @return string
  251. */
  252. protected function _buildUnionPart($parts, $query, $generator)
  253. {
  254. $parts = array_map(function ($p) use ($generator) {
  255. $p['query'] = $p['query']->sql($generator);
  256. $p['query'] = $p['query'][0] === '(' ? trim($p['query'], '()') : $p['query'];
  257. $prefix = $p['all'] ? 'ALL ' : '';
  258. if ($this->_orderedUnion) {
  259. return "{$prefix}({$p['query']})";
  260. }
  261. return $prefix . $p['query'];
  262. }, $parts);
  263. if ($this->_orderedUnion) {
  264. return sprintf(")\nUNION %s", implode("\nUNION ", $parts));
  265. }
  266. return sprintf("\nUNION %s", implode("\nUNION ", $parts));
  267. }
  268. /**
  269. * Builds the SQL fragment for INSERT INTO.
  270. *
  271. * @param array $parts The insert parts.
  272. * @param \Cake\Database\Query $query The query that is being compiled
  273. * @param \Cake\Database\ValueBinder $generator the placeholder generator to be used in expressions
  274. * @return string SQL fragment.
  275. */
  276. protected function _buildInsertPart($parts, $query, $generator)
  277. {
  278. $table = $parts[0];
  279. $columns = $this->_stringifyExpressions($parts[1], $generator);
  280. return sprintf('INSERT INTO %s (%s)', $table, implode(', ', $columns));
  281. }
  282. /**
  283. * Builds the SQL fragment for INSERT INTO.
  284. *
  285. * @param array $parts The values parts.
  286. * @param \Cake\Database\Query $query The query that is being compiled
  287. * @param \Cake\Database\ValueBinder $generator the placeholder generator to be used in expressions
  288. * @return string SQL fragment.
  289. */
  290. protected function _buildValuesPart($parts, $query, $generator)
  291. {
  292. return implode('', $this->_stringifyExpressions($parts, $generator));
  293. }
  294. /**
  295. * Helper function used to covert ExpressionInterface objects inside an array
  296. * into their string representation.
  297. *
  298. * @param array $expressions list of strings and ExpressionInterface objects
  299. * @param \Cake\Database\ValueBinder $generator the placeholder generator to be used in expressions
  300. * @return array
  301. */
  302. protected function _stringifyExpressions($expressions, $generator)
  303. {
  304. $result = [];
  305. foreach ($expressions as $k => $expression) {
  306. if ($expression instanceof ExpressionInterface) {
  307. $value = $expression->sql($generator);
  308. $expression = '(' . $value . ')';
  309. }
  310. $result[$k] = $expression;
  311. }
  312. return $result;
  313. }
  314. }