grammar.php 11 KB

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