grammar.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. <?php namespace Laravel\Database\Query\Grammars;
  2. use Laravel\Database\Query;
  3. use Laravel\Database\Expression;
  4. class Grammar extends \Laravel\Database\Grammar {
  5. /**
  6. * All of the query componenets in the order they should be built.
  7. *
  8. * @var array
  9. */
  10. protected $components = array(
  11. 'aggregate', 'selects', 'from', 'joins', 'wheres',
  12. 'groupings', 'orderings', 'limit', 'offset',
  13. );
  14. /**
  15. * Compile a SQL SELECT statement from a Query instance.
  16. *
  17. * @param Query $query
  18. * @return string
  19. */
  20. public function select(Query $query)
  21. {
  22. return $this->concatenate($this->components($query));
  23. }
  24. /**
  25. * Generate the SQL for every component of the query.
  26. *
  27. * @param Query $query
  28. * @return array
  29. */
  30. final protected function components($query)
  31. {
  32. // Each portion of the statement is compiled by a function corresponding
  33. // to an item in the components array. This lets us to keep the creation
  34. // of the query very granular, and allows for the flexible customization
  35. // of the query building process by each database system's grammar.
  36. //
  37. // Note that each component also corresponds to a public property on the
  38. // query instance, allowing us to pass the appropriate data into each of
  39. // the compiler functions.
  40. foreach ($this->components as $component)
  41. {
  42. if ( ! is_null($query->$component))
  43. {
  44. $sql[$component] = call_user_func(array($this, $component), $query);
  45. }
  46. }
  47. return (array) $sql;
  48. }
  49. /**
  50. * Concatenate an array of SQL segments, removing those that are empty.
  51. *
  52. * @param array $components
  53. * @return string
  54. */
  55. final protected function concatenate($components)
  56. {
  57. return implode(' ', array_filter($components, function($value)
  58. {
  59. return (string) $value !== '';
  60. }));
  61. }
  62. /**
  63. * Compile the SELECT clause for a query.
  64. *
  65. * @param Query $query
  66. * @return string
  67. */
  68. protected function selects(Query $query)
  69. {
  70. // Sometimes developers may set a "select" clause on the same query
  71. // that is performing in aggregate look-up, like during pagination.
  72. // So we will not generate the select clause if an aggregate is
  73. // present so the aggregates work.
  74. if ( ! is_null($query->aggregate)) return;
  75. $select = ($query->distinct) ? 'SELECT DISTINCT ' : 'SELECT ';
  76. return $select.$this->columnize($query->selects);
  77. }
  78. /**
  79. * Compile an aggregating SELECT clause for a query.
  80. *
  81. * @param Query $query
  82. * @return string
  83. */
  84. protected function aggregate(Query $query)
  85. {
  86. $column = $this->columnize($query->aggregate['columns']);
  87. if ($query->distinct and $column !== '*') $column = 'DISTINCT '.$column;
  88. return 'SELECT '.$query->aggregate['aggregator'].'('.$column.')';
  89. }
  90. /**
  91. * Compile the FROM clause for a query.
  92. *
  93. * @param Query $query
  94. * @return string
  95. */
  96. protected function from(Query $query)
  97. {
  98. return 'FROM '.$this->wrap_table($query->from);
  99. }
  100. /**
  101. * Compile the JOIN clauses for a query.
  102. *
  103. * @param Query $query
  104. * @return string
  105. */
  106. protected function joins(Query $query)
  107. {
  108. // We need to iterate through each JOIN clause that is attached to the
  109. // query an translate it into SQL. The table and the columns will be
  110. // wrapped in identifiers to avoid naming collisions.
  111. //
  112. // Once all of the JOINs have been compiled, we can concatenate them
  113. // together using a single space, which should give us the complete
  114. // set of joins in valid SQL that can appended to the query.
  115. foreach ($query->joins as $join)
  116. {
  117. $table = $this->wrap_table($join['table']);
  118. $column1 = $this->wrap($join['column1']);
  119. $column2 = $this->wrap($join['column2']);
  120. $sql[] = "{$join['type']} JOIN {$table} ON {$column1} {$join['operator']} {$column2}";
  121. }
  122. return implode(' ', $sql);
  123. }
  124. /**
  125. * Compile the WHERE clause for a query.
  126. *
  127. * @param Query $query
  128. * @return string
  129. */
  130. final protected function wheres(Query $query)
  131. {
  132. if (is_null($query->wheres)) return '';
  133. // Each WHERE clause array has a "type" that is assigned by the query
  134. // builder, and each type has its own compiler function. We will call
  135. // the appropriate compiler for each where clause in the query.
  136. //
  137. // Keeping each particular where clause in its own "compiler" allows
  138. // us to keep the query generation process very granular, making it
  139. // easier to customize derived grammars for other databases.
  140. foreach ($query->wheres as $where)
  141. {
  142. $sql[] = $where['connector'].' '.$this->{$where['type']}($where);
  143. }
  144. if (isset($sql))
  145. {
  146. // We attach the boolean connector to every where segment just
  147. // for convenience. Once we have built the entire clause we'll
  148. // remove the first instance of a connector from the clause.
  149. return 'WHERE '.preg_replace('/AND |OR /', '', implode(' ', $sql), 1);
  150. }
  151. }
  152. /**
  153. * Compile a nested WHERE clause.
  154. *
  155. * @param array $where
  156. * @return string
  157. */
  158. protected function where_nested($where)
  159. {
  160. // To generate a nested WHERE clause, we'll just feed the query
  161. // back into the "wheres" method. Once we have the clause, we
  162. // will strip off the first six characters to get rid of the
  163. // leading WHERE keyword.
  164. return '('.substr($this->wheres($where['query']), 6).')';
  165. }
  166. /**
  167. * Compile a simple WHERE clause.
  168. *
  169. * @param array $where
  170. * @return string
  171. */
  172. protected function where($where)
  173. {
  174. $parameter = $this->parameter($where['value']);
  175. return $this->wrap($where['column']).' '.$where['operator'].' '.$parameter;
  176. }
  177. /**
  178. * Compile a WHERE IN clause.
  179. *
  180. * @param array $where
  181. * @return string
  182. */
  183. protected function where_in($where)
  184. {
  185. $parameters = $this->parameterize($where['values']);
  186. return $this->wrap($where['column']).' IN ('.$parameters.')';
  187. }
  188. /**
  189. * Compile a WHERE NOT IN clause.
  190. *
  191. * @param array $where
  192. * @return string
  193. */
  194. protected function where_not_in($where)
  195. {
  196. $parameters = $this->parameterize($where['values']);
  197. return $this->wrap($where['column']).' NOT IN ('.$parameters.')';
  198. }
  199. /**
  200. * Compile a WHERE NULL clause.
  201. *
  202. * @param array $where
  203. * @return string
  204. */
  205. protected function where_null($where)
  206. {
  207. return $this->wrap($where['column']).' IS NULL';
  208. }
  209. /**
  210. * Compile a WHERE NULL clause.
  211. *
  212. * @param array $where
  213. * @return string
  214. */
  215. protected function where_not_null($where)
  216. {
  217. return $this->wrap($where['column']).' IS NOT NULL';
  218. }
  219. /**
  220. * Compile a raw WHERE clause.
  221. *
  222. * @param array $where
  223. * @return string
  224. */
  225. final protected function where_raw($where)
  226. {
  227. return $where['sql'];
  228. }
  229. /**
  230. * Compile the GROUP BY clause for a query.
  231. *
  232. * @param Query $query
  233. * @return string
  234. */
  235. protected function groupings(Query $query)
  236. {
  237. return 'GROUP BY '.$this->columnize($query->groupings);
  238. }
  239. /**
  240. * Compile the ORDER BY clause for a query.
  241. *
  242. * @param Query $query
  243. * @return string
  244. */
  245. protected function orderings(Query $query)
  246. {
  247. foreach ($query->orderings as $ordering)
  248. {
  249. $direction = strtoupper($ordering['direction']);
  250. $sql[] = $this->wrap($ordering['column']).' '.$direction;
  251. }
  252. return 'ORDER BY '.implode(', ', $sql);
  253. }
  254. /**
  255. * Compile the LIMIT clause for a query.
  256. *
  257. * @param Query $query
  258. * @return string
  259. */
  260. protected function limit(Query $query)
  261. {
  262. return 'LIMIT '.$query->limit;
  263. }
  264. /**
  265. * Compile the OFFSET clause for a query.
  266. *
  267. * @param Query $query
  268. * @return string
  269. */
  270. protected function offset(Query $query)
  271. {
  272. return 'OFFSET '.$query->offset;
  273. }
  274. /**
  275. * Compile a SQL INSERT statment from a Query instance.
  276. *
  277. * This method handles the compilation of single row inserts and batch inserts.
  278. *
  279. * @param Query $query
  280. * @param array $values
  281. * @return string
  282. */
  283. public function insert(Query $query, $values)
  284. {
  285. $table = $this->wrap_table($query->from);
  286. // Force every insert to be treated like a batch insert. This simply makes
  287. // creating the SQL syntax a little easier on us since we can always treat
  288. // the values as if it is an array containing multiple inserts.
  289. if ( ! is_array(reset($values))) $values = array($values);
  290. // Since we only care about the column names, we can pass any of the insert
  291. // arrays into the "columnize" method. The columns should be the same for
  292. // every insert to the table so we can just use the first record.
  293. $columns = $this->columnize(array_keys(reset($values)));
  294. // Build the list of parameter place-holders of values bound to the query.
  295. // Each insert should have the same number of bound paramters, so we can
  296. // just use the first array of values.
  297. $parameters = $this->parameterize(reset($values));
  298. $parameters = implode(', ', array_fill(0, count($values), "($parameters)"));
  299. return "INSERT INTO {$table} ({$columns}) VALUES {$parameters}";
  300. }
  301. /**
  302. * Compile a SQL UPDATE statment from a Query instance.
  303. *
  304. * @param Query $query
  305. * @param array $values
  306. * @return string
  307. */
  308. public function update(Query $query, $values)
  309. {
  310. $table = $this->wrap_table($query->from);
  311. // Each column in the UPDATE statement needs to be wrapped in keyword
  312. // identifiers, and a place-holder needs to be created for each value
  313. // in the array of bindings. Of course, if the value of the binding
  314. // is an expression, the expression string will be injected.
  315. foreach ($values as $column => $value)
  316. {
  317. $columns[] = $this->wrap($column).' = '.$this->parameter($value);
  318. }
  319. $columns = implode(', ', $columns);
  320. // UPDATE statements may be constrained by a WHERE clause, so we'll
  321. // run the entire where compilation process for those contraints.
  322. // This is easily achieved by passing the query to the "wheres"
  323. // method which will call all of the where compilers.
  324. return trim("UPDATE {$table} SET {$columns} ".$this->wheres($query));
  325. }
  326. /**
  327. * Compile a SQL DELETE statment from a Query instance.
  328. *
  329. * @param Query $query
  330. * @return string
  331. */
  332. public function delete(Query $query)
  333. {
  334. $table = $this->wrap_table($query->from);
  335. // Like the UPDATE statement, the DELETE statement is constrained
  336. // by WHERE clauses, so we'll need to run the "wheres" method to
  337. // make the WHERE clauses for the query.
  338. return trim("DELETE FROM {$table} ".$this->wheres($query));
  339. }
  340. /**
  341. * Transform an SQL short-cuts into real SQL for PDO.
  342. *
  343. * @param string $sql
  344. * @param array $bindings
  345. * @return string
  346. */
  347. public function shortcut($sql, $bindings)
  348. {
  349. // Laravel provides an easy short-cut notation for writing raw
  350. // WHERE IN statements. If (...) is in the query, it will be
  351. // replaced with the correct number of parameters based on
  352. // the bindings for the query.
  353. if (strpos($sql, '(...)') !== false)
  354. {
  355. for ($i = 0; $i < count($bindings); $i++)
  356. {
  357. // If the binding is an array, we can just assume it's
  358. // used to fill a "where in" condition, so we'll just
  359. // replace the next place-holder in the query.
  360. if (is_array($bindings[$i]))
  361. {
  362. $parameters = $this->parameterize($bindings[$i]);
  363. $sql = preg_replace('~\(\.\.\.\)~', "({$parameters})", $sql, 1);
  364. }
  365. }
  366. }
  367. return trim($sql);
  368. }
  369. }