grammar.php 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  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 that
  71. // is performing in aggregate look-up, such as during pagination. So we
  72. // will not generate the select clause if an aggregate is present.
  73. if ( ! is_null($query->aggregate)) return;
  74. $select = ($query->distinct) ? 'SELECT DISTINCT ' : 'SELECT ';
  75. return $select.$this->columnize($query->selects);
  76. }
  77. /**
  78. * Compile an aggregating SELECT clause for a query.
  79. *
  80. * @param Query $query
  81. * @return string
  82. */
  83. protected function aggregate(Query $query)
  84. {
  85. $column = $this->wrap($query->aggregate['column']);
  86. return 'SELECT '.$query->aggregate['aggregator'].'('.$column.')';
  87. }
  88. /**
  89. * Compile the FROM clause for a query.
  90. *
  91. * @param Query $query
  92. * @return string
  93. */
  94. protected function from(Query $query)
  95. {
  96. return 'FROM '.$this->wrap_table($query->from);
  97. }
  98. /**
  99. * Compile the JOIN clauses for a query.
  100. *
  101. * @param Query $query
  102. * @return string
  103. */
  104. protected function joins(Query $query)
  105. {
  106. // We need to iterate through each JOIN clause that is attached to the
  107. // query an translate it into SQL. The table and the columns will be
  108. // wrapped in identifiers to avoid naming collisions.
  109. //
  110. // Once all of the JOINs have been compiled, we can concatenate them
  111. // together using a single space, which should give us the complete
  112. // set of joins in valid SQL that can appended to the query.
  113. foreach ($query->joins as $join)
  114. {
  115. $table = $this->wrap_table($join['table']);
  116. $column1 = $this->wrap($join['column1']);
  117. $column2 = $this->wrap($join['column2']);
  118. $sql[] = "{$join['type']} JOIN {$table} ON {$column1} {$join['operator']} {$column2}";
  119. }
  120. return implode(' ', $sql);
  121. }
  122. /**
  123. * Compile the WHERE clause for a query.
  124. *
  125. * @param Query $query
  126. * @return string
  127. */
  128. final protected function wheres(Query $query)
  129. {
  130. if (is_null($query->wheres)) return '';
  131. // Each WHERE clause array has a "type" that is assigned by the query
  132. // builder, and each type has its own compiler function. We will call
  133. // the appropriate compiler for each where clause in the query.
  134. //
  135. // Keeping each particular where clause in its own "compiler" allows
  136. // us to keep the query generation process very granular, making it
  137. // easier to customize derived grammars for other databases.
  138. foreach ($query->wheres as $where)
  139. {
  140. $sql[] = $where['connector'].' '.$this->{$where['type']}($where);
  141. }
  142. if (isset($sql))
  143. {
  144. // We attach the boolean connector to every where segment just
  145. // for convenience. Once we have built the entire clause we'll
  146. // remove the first instance of a connector from the clause.
  147. return 'WHERE '.preg_replace('/AND |OR /', '', implode(' ', $sql), 1);
  148. }
  149. }
  150. /**
  151. * Compile a nested WHERE clause.
  152. *
  153. * @param array $where
  154. * @return string
  155. */
  156. protected function where_nested($where)
  157. {
  158. // To generate a nested WHERE clause, we'll just feed the query
  159. // back into the "wheres" method. Once we have the clause, we
  160. // will strip off the first six characters to get rid of the
  161. // leading WHERE keyword.
  162. return '('.substr($this->wheres($where['query']), 6).')';
  163. }
  164. /**
  165. * Compile a simple WHERE clause.
  166. *
  167. * @param array $where
  168. * @return string
  169. */
  170. protected function where($where)
  171. {
  172. $parameter = $this->parameter($where['value']);
  173. return $this->wrap($where['column']).' '.$where['operator'].' '.$parameter;
  174. }
  175. /**
  176. * Compile a WHERE IN clause.
  177. *
  178. * @param array $where
  179. * @return string
  180. */
  181. protected function where_in($where)
  182. {
  183. $parameters = $this->parameterize($where['values']);
  184. return $this->wrap($where['column']).' IN ('.$parameters.')';
  185. }
  186. /**
  187. * Compile a WHERE NOT IN clause.
  188. *
  189. * @param array $where
  190. * @return string
  191. */
  192. protected function where_not_in($where)
  193. {
  194. $parameters = $this->parameterize($where['values']);
  195. return $this->wrap($where['column']).' NOT IN ('.$parameters.')';
  196. }
  197. /**
  198. * Compile a WHERE NULL clause.
  199. *
  200. * @param array $where
  201. * @return string
  202. */
  203. protected function where_null($where)
  204. {
  205. return $this->wrap($where['column']).' IS NULL';
  206. }
  207. /**
  208. * Compile a WHERE NULL clause.
  209. *
  210. * @param array $where
  211. * @return string
  212. */
  213. protected function where_not_null($where)
  214. {
  215. return $this->wrap($where['column']).' IS NOT NULL';
  216. }
  217. /**
  218. * Compile a raw WHERE clause.
  219. *
  220. * @param array $where
  221. * @return string
  222. */
  223. final protected function where_raw($where)
  224. {
  225. return $where['sql'];
  226. }
  227. /**
  228. * Compile the GROUP BY clause for a query.
  229. *
  230. * @param Query $query
  231. * @return string
  232. */
  233. protected function groupings(Query $query)
  234. {
  235. return 'GROUP BY '.$this->columnize($query->groupings);
  236. }
  237. /**
  238. * Compile the ORDER BY clause for a query.
  239. *
  240. * @param Query $query
  241. * @return string
  242. */
  243. protected function orderings(Query $query)
  244. {
  245. foreach ($query->orderings as $ordering)
  246. {
  247. $direction = strtoupper($ordering['direction']);
  248. $sql[] = $this->wrap($ordering['column']).' '.$direction;
  249. }
  250. return 'ORDER BY '.implode(', ', $sql);
  251. }
  252. /**
  253. * Compile the LIMIT clause for a query.
  254. *
  255. * @param Query $query
  256. * @return string
  257. */
  258. protected function limit(Query $query)
  259. {
  260. return 'LIMIT '.$query->limit;
  261. }
  262. /**
  263. * Compile the OFFSET clause for a query.
  264. *
  265. * @param Query $query
  266. * @return string
  267. */
  268. protected function offset(Query $query)
  269. {
  270. return 'OFFSET '.$query->offset;
  271. }
  272. /**
  273. * Compile a SQL INSERT statment from a Query instance.
  274. *
  275. * This method handles the compilation of single row inserts and batch inserts.
  276. *
  277. * @param Query $query
  278. * @param array $values
  279. * @return string
  280. */
  281. public function insert(Query $query, $values)
  282. {
  283. $table = $this->wrap_table($query->from);
  284. // Force every insert to be treated like a batch insert. This simply makes
  285. // creating the SQL syntax a little easier on us since we can always treat
  286. // the values as if it is an array containing multiple inserts.
  287. if ( ! is_array(reset($values))) $values = array($values);
  288. // Since we only care about the column names, we can pass any of the insert
  289. // arrays into the "columnize" method. The columns should be the same for
  290. // every insert to the table so we can just use the first record.
  291. $columns = $this->columnize(array_keys(reset($values)));
  292. // Build the list of parameter place-holders of values bound to the query.
  293. // Each insert should have the same number of bound paramters, so we can
  294. // just use the first array of values.
  295. $parameters = $this->parameterize(reset($values));
  296. $parameters = implode(', ', array_fill(0, count($values), "($parameters)"));
  297. return "INSERT INTO {$table} ({$columns}) VALUES {$parameters}";
  298. }
  299. /**
  300. * Compile a SQL UPDATE statment from a Query instance.
  301. *
  302. * @param Query $query
  303. * @param array $values
  304. * @return string
  305. */
  306. public function update(Query $query, $values)
  307. {
  308. $table = $this->wrap_table($query->from);
  309. // Each column in the UPDATE statement needs to be wrapped in keyword
  310. // identifiers, and a place-holder needs to be created for each value
  311. // in the array of bindings. Of course, if the value of the binding
  312. // is an expression, the expression string will be injected.
  313. foreach ($values as $column => $value)
  314. {
  315. $columns[] = $this->wrap($column).' = '.$this->parameter($value);
  316. }
  317. $columns = implode(', ', $columns);
  318. // UPDATE statements may be constrained by a WHERE clause, so we'll
  319. // run the entire where compilation process for those contraints.
  320. // This is easily achieved by passing the query to the "wheres"
  321. // method which will call all of the where compilers.
  322. return trim("UPDATE {$table} SET {$columns} ".$this->wheres($query));
  323. }
  324. /**
  325. * Compile a SQL DELETE statment from a Query instance.
  326. *
  327. * @param Query $query
  328. * @return string
  329. */
  330. public function delete(Query $query)
  331. {
  332. $table = $this->wrap_table($query->from);
  333. // Like the UPDATE statement, the DELETE statement is constrained
  334. // by WHERE clauses, so we'll need to run the "wheres" method to
  335. // make the WHERE clauses for the query. The "wheres" method
  336. // encapsulates the logic to create the full WHERE clause.
  337. return trim("DELETE FROM {$table} ".$this->wheres($query));
  338. }
  339. }