1: <?php namespace Laravel\Database;
2:
3: use PDO, PDOStatement, Laravel\Config, Laravel\Event;
4:
5: class Connection {
6:
7: /**
8: * The raw PDO connection instance.
9: *
10: * @var PDO
11: */
12: public $pdo;
13:
14: /**
15: * The connection configuration array.
16: *
17: * @var array
18: */
19: public $config;
20:
21: /**
22: * The query grammar instance for the connection.
23: *
24: * @var Query\Grammars\Grammar
25: */
26: protected $grammar;
27:
28: /**
29: * All of the queries that have been executed on all connections.
30: *
31: * @var array
32: */
33: public static $queries = array();
34:
35: /**
36: * Create a new database connection instance.
37: *
38: * @param PDO $pdo
39: * @param array $config
40: * @return void
41: */
42: public function __construct(PDO $pdo, $config)
43: {
44: $this->pdo = $pdo;
45: $this->config = $config;
46: }
47:
48: /**
49: * Begin a fluent query against a table.
50: *
51: * <code>
52: * // Start a fluent query against the "users" table
53: * $query = DB::connection()->table('users');
54: *
55: * // Start a fluent query against the "users" table and get all the users
56: * $users = DB::connection()->table('users')->get();
57: * </code>
58: *
59: * @param string $table
60: * @return Query
61: */
62: public function table($table)
63: {
64: return new Query($this, $this->grammar(), $table);
65: }
66:
67: /**
68: * Create a new query grammar for the connection.
69: *
70: * @return Query\Grammars\Grammar
71: */
72: protected function grammar()
73: {
74: if (isset($this->grammar)) return $this->grammar;
75:
76: if (isset(\Laravel\Database::$registrar[$this->driver()]))
77: {
78: $resolver = \Laravel\Database::$registrar[$this->driver()]['query'];
79: return $this->grammar = $resolver($this);
80: }
81:
82: switch ($this->driver())
83: {
84: case 'mysql':
85: return $this->grammar = new Query\Grammars\MySQL($this);
86:
87: case 'sqlite':
88: return $this->grammar = new Query\Grammars\SQLite($this);
89:
90: case 'sqlsrv':
91: return $this->grammar = new Query\Grammars\SQLServer($this);
92:
93: case 'pgsql':
94: return $this->grammar = new Query\Grammars\Postgres($this);
95:
96: default:
97: return $this->grammar = new Query\Grammars\Grammar($this);
98: }
99: }
100:
101: /**
102: * Execute a callback wrapped in a database transaction.
103: *
104: * @param callback $callback
105: * @return bool
106: */
107: public function transaction($callback)
108: {
109: $this->pdo->beginTransaction();
110:
111: // After beginning the database transaction, we will call the callback
112: // so that it can do its database work. If an exception occurs we'll
113: // rollback the transaction and re-throw back to the developer.
114: try
115: {
116: call_user_func($callback);
117: }
118: catch (\Exception $e)
119: {
120: $this->pdo->rollBack();
121:
122: throw $e;
123: }
124:
125: return $this->pdo->commit();
126: }
127:
128: /**
129: * Execute a SQL query against the connection and return a single column result.
130: *
131: * <code>
132: * // Get the total number of rows on a table
133: * $count = DB::connection()->only('select count(*) from users');
134: *
135: * // Get the sum of payment amounts from a table
136: * $sum = DB::connection()->only('select sum(amount) from payments')
137: * </code>
138: *
139: * @param string $sql
140: * @param array $bindings
141: * @return mixed
142: */
143: public function only($sql, $bindings = array())
144: {
145: $results = (array) $this->first($sql, $bindings);
146:
147: return reset($results);
148: }
149:
150: /**
151: * Execute a SQL query against the connection and return the first result.
152: *
153: * <code>
154: * // Execute a query against the database connection
155: * $user = DB::connection()->first('select * from users');
156: *
157: * // Execute a query with bound parameters
158: * $user = DB::connection()->first('select * from users where id = ?', array($id));
159: * </code>
160: *
161: * @param string $sql
162: * @param array $bindings
163: * @return object
164: */
165: public function first($sql, $bindings = array())
166: {
167: if (count($results = $this->query($sql, $bindings)) > 0)
168: {
169: return $results[0];
170: }
171: }
172:
173: /**
174: * Execute a SQL query and return an array of StdClass objects.
175: *
176: * @param string $sql
177: * @param array $bindings
178: * @return array
179: */
180: public function query($sql, $bindings = array())
181: {
182: $sql = trim($sql);
183:
184: list($statement, $result) = $this->execute($sql, $bindings);
185:
186: // The result we return depends on the type of query executed against the
187: // database. On SELECT clauses, we will return the result set, for update
188: // and deletes we will return the affected row count.
189: if (stripos($sql, 'select') === 0 || stripos($sql, 'show') === 0)
190: {
191: return $this->fetch($statement, Config::get('database.fetch'));
192: }
193: elseif (stripos($sql, 'update') === 0 or stripos($sql, 'delete') === 0)
194: {
195: return $statement->rowCount();
196: }
197: // For insert statements that use the "returning" clause, which is allowed
198: // by database systems such as Postgres, we need to actually return the
199: // real query result so the consumer can get the ID.
200: elseif (stripos($sql, 'insert') === 0 and stripos($sql, ') returning') !== false)
201: {
202: return $this->fetch($statement, Config::get('database.fetch'));
203: }
204: else
205: {
206: return $result;
207: }
208: }
209:
210: /**
211: * Execute a SQL query against the connection.
212: *
213: * The PDO statement and boolean result will be returned in an array.
214: *
215: * @param string $sql
216: * @param array $bindings
217: * @return array
218: */
219: protected function execute($sql, $bindings = array())
220: {
221: $bindings = (array) $bindings;
222:
223: // Since expressions are injected into the query as strings, we need to
224: // remove them from the array of bindings. After we have removed them,
225: // we'll reset the array so there are not gaps within the keys.
226: $bindings = array_filter($bindings, function($binding)
227: {
228: return ! $binding instanceof Expression;
229: });
230:
231: $bindings = array_values($bindings);
232:
233: $sql = $this->grammar()->shortcut($sql, $bindings);
234:
235: // Next we need to translate all DateTime bindings to their date-time
236: // strings that are compatible with the database. Each grammar may
237: // define it's own date-time format according to its needs.
238: $datetime = $this->grammar()->datetime;
239:
240: for ($i = 0; $i < count($bindings); $i++)
241: {
242: if ($bindings[$i] instanceof \DateTime)
243: {
244: $bindings[$i] = $bindings[$i]->format($datetime);
245: }
246: }
247:
248: // Each database operation is wrapped in a try / catch so we can wrap
249: // any database exceptions in our custom exception class, which will
250: // set the message to include the SQL and query bindings.
251: try
252: {
253: $statement = $this->pdo->prepare($sql);
254:
255: $start = microtime(true);
256:
257: $result = $statement->execute($bindings);
258: }
259: // If an exception occurs, we'll pass it into our custom exception
260: // and set the message to include the SQL and query bindings so
261: // debugging is much easier on the developer.
262: catch (\Exception $exception)
263: {
264: $exception = new Exception($sql, $bindings, $exception);
265:
266: throw $exception;
267: }
268:
269: // Once we have executed the query, we log the SQL, bindings, and
270: // execution time in a static array that is accessed by all of
271: // the connections actively being used by the application.
272: if (Config::get('database.profile'))
273: {
274: $this->log($sql, $bindings, $start);
275: }
276:
277: return array($statement, $result);
278: }
279:
280: /**
281: * Fetch all of the rows for a given statement.
282: *
283: * @param PDOStatement $statement
284: * @param int $style
285: * @return array
286: */
287: protected function fetch($statement, $style)
288: {
289: // If the fetch style is "class", we'll hydrate an array of PHP
290: // stdClass objects as generic containers for the query rows,
291: // otherwise we'll just use the fetch style value.
292: if ($style === PDO::FETCH_CLASS)
293: {
294: return $statement->fetchAll(PDO::FETCH_CLASS, 'stdClass');
295: }
296: else
297: {
298: return $statement->fetchAll($style);
299: }
300: }
301:
302: /**
303: * Log the query and fire the core query event.
304: *
305: * @param string $sql
306: * @param array $bindings
307: * @param int $start
308: * @return void
309: */
310: protected function log($sql, $bindings, $start)
311: {
312: $time = (microtime(true) - $start) * 1000;
313:
314: Event::fire('laravel.query', array($sql, $bindings, $time));
315:
316: static::$queries[] = compact('sql', 'bindings', 'time');
317: }
318:
319: /**
320: * Get the driver name for the database connection.
321: *
322: * @return string
323: */
324: public function driver()
325: {
326: return $this->config['driver'];
327: }
328:
329: /**
330: * Magic Method for dynamically beginning queries on database tables.
331: */
332: public function __call($method, $parameters)
333: {
334: return $this->table($method);
335: }
336:
337: }
338: