PageRenderTime 41ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Illuminate/Database/Connection.php

https://github.com/guilex/framework
PHP | 775 lines | 294 code | 102 blank | 379 comment | 9 complexity | 7601c81cbc4da214b3590a72d0f0c9bd MD5 | raw file
  1. <?php namespace Illuminate\Database;
  2. use PDO;
  3. use Closure;
  4. use DateTime;
  5. use Illuminate\Database\Query\Processors\Processor;
  6. class Connection implements ConnectionInterface {
  7. /**
  8. * The active PDO connection.
  9. *
  10. * @var PDO
  11. */
  12. protected $pdo;
  13. /**
  14. * The query grammar implementation.
  15. *
  16. * @var Illuminate\Database\Query\Grammars\Grammar
  17. */
  18. protected $queryGrammar;
  19. /**
  20. * The schema grammar implementation.
  21. *
  22. * @var Illuminate\Database\Schema\Grammars\Grammar
  23. */
  24. protected $schemaGrammar;
  25. /**
  26. * The query post processor implementation.
  27. *
  28. * @var Illuminate\Database\Query\Processors\Processor
  29. */
  30. protected $postProcessor;
  31. /**
  32. * The event dispatcher instance.
  33. *
  34. * @var Illuminate\Events\Dispatcher
  35. */
  36. protected $events;
  37. /**
  38. * The paginator environment instance.
  39. *
  40. * @var Illuminate\Pagination\Paginator
  41. */
  42. protected $paginator;
  43. /**
  44. * The default fetch mode of the connection.
  45. *
  46. * @var int
  47. */
  48. protected $fetchMode = PDO::FETCH_ASSOC;
  49. /**
  50. * All of the queries run against the connection.
  51. *
  52. * @var array
  53. */
  54. protected $queryLog = array();
  55. /**
  56. * Indicates if the connection is in a "dry run".
  57. *
  58. * @var bool
  59. */
  60. protected $pretending = false;
  61. /**
  62. * The name of the connected database.
  63. *
  64. * @var string
  65. */
  66. protected $database;
  67. /**
  68. * The table prefix for the connection.
  69. *
  70. * @var string
  71. */
  72. protected $tablePrefix = '';
  73. /**
  74. * The database connection configuration options.
  75. *
  76. * @var string
  77. */
  78. protected $config = array();
  79. /**
  80. * Create a new database connection instance.
  81. *
  82. * @param PDO $pdo
  83. * @param string $database
  84. * @param string $tablePrefix
  85. * @param array $config
  86. * @return void
  87. */
  88. public function __construct(PDO $pdo, $database = '', $tablePrefix = '', array $config = array())
  89. {
  90. $this->pdo = $pdo;
  91. // First we will setup the default properties. We keep track of the DB
  92. // name we are connected to since it is needed when some reflective
  93. // type commands are run such as checking whether a table exists.
  94. $this->database = $database;
  95. $this->tablePrefix = $tablePrefix;
  96. $this->config = $config;
  97. // We need to initialize a query grammar and the query post processors
  98. // which are both very important parts of the database abstractions
  99. // so will initialize them to their default value to get started.
  100. $this->useDefaultQueryGrammar();
  101. $this->useDefaultPostProcessor();
  102. }
  103. /**
  104. * Set the query grammar to the default implementation.
  105. *
  106. * @return void
  107. */
  108. public function useDefaultQueryGrammar()
  109. {
  110. $this->queryGrammar = $this->getDefaultQueryGrammar();
  111. }
  112. /**
  113. * Get the default query grammar instance.
  114. *
  115. * @return Illuminate\Database\Query\Grammars\Grammar
  116. */
  117. protected function getDefaultQueryGrammar()
  118. {
  119. return new Query\Grammars\Grammar;
  120. }
  121. /**
  122. * Set the schema grammar to the default implementation.
  123. *
  124. * @return void
  125. */
  126. public function useDefaultSchemaGrammar()
  127. {
  128. $this->schemaGrammar = $this->getDefaultSchemaGrammar();
  129. }
  130. /**
  131. * Get the default schema grammar instance.
  132. *
  133. * @return Illuminate\Database\Schema\Grammars\Grammar
  134. */
  135. protected function getDefaultSchemaGrammar() {}
  136. /**
  137. * Set the query post processor to the default implementation.
  138. *
  139. * @return void
  140. */
  141. public function useDefaultPostProcessor()
  142. {
  143. $this->postProcessor = $this->getDefaultPostProcessor();
  144. }
  145. /**
  146. * Get the default post processor instance.
  147. *
  148. * @return Illuminate\Database\Query\Processors\Processor
  149. */
  150. protected function getDefaultPostProcessor()
  151. {
  152. return new Query\Processors\Processor;
  153. }
  154. /**
  155. * Get a schema builder instance for the connection.
  156. *
  157. * @return Illuminate\Database\Schema\Builder
  158. */
  159. public function getSchemaBuilder()
  160. {
  161. if (is_null($this->schemaGrammar)) { $this->useDefaultSchemaGrammar(); }
  162. return new Schema\Builder($this);
  163. }
  164. /**
  165. * Begin a fluent query against a database table.
  166. *
  167. * @param string $table
  168. * @return Illuminate\Database\Query\Builder
  169. */
  170. public function table($table)
  171. {
  172. $processor = $this->getPostProcessor();
  173. $query = new Query\Builder($this, $this->getQueryGrammar(), $processor);
  174. return $query->from($table);
  175. }
  176. /**
  177. * Get a new raw query expression.
  178. *
  179. * @param mixed $value
  180. * @return Illuminate\Database\Query\Expression
  181. */
  182. public function raw($value)
  183. {
  184. return new Query\Expression($value);
  185. }
  186. /**
  187. * Run a select statement and return a single result.
  188. *
  189. * @param string $query
  190. * @param array $bindings
  191. * @return mixed
  192. */
  193. public function selectOne($query, $bindings = array())
  194. {
  195. $records = $this->select($query, $bindings);
  196. return count($records) > 0 ? reset($records) : null;
  197. }
  198. /**
  199. * Run a select statement against the database.
  200. *
  201. * @param string $query
  202. * @param array $bindings
  203. * @return array
  204. */
  205. public function select($query, $bindings = array())
  206. {
  207. return $this->run($query, $bindings, function($me, $query, $bindings)
  208. {
  209. if ($me->pretending()) return array();
  210. // For select statements, we'll simply execute the query and return an array
  211. // of the database result set. Each element in the array will be a single
  212. // row from the database table, and will either be an array or objects.
  213. $statement = $me->getPdo()->prepare($query);
  214. $statement->execute($me->prepareBindings($bindings));
  215. return $statement->fetchAll($me->getFetchMode());
  216. });
  217. }
  218. /**
  219. * Run an insert statement against the database.
  220. *
  221. * @param string $query
  222. * @param array $bindings
  223. * @return bool
  224. */
  225. public function insert($query, $bindings = array())
  226. {
  227. return $this->statement($query, $bindings);
  228. }
  229. /**
  230. * Run an update statement against the database.
  231. *
  232. * @param string $query
  233. * @param array $bindings
  234. * @return int
  235. */
  236. public function update($query, $bindings = array())
  237. {
  238. return $this->affectingStatement($query, $bindings);
  239. }
  240. /**
  241. * Run a delete statement against the database.
  242. *
  243. * @param string $query
  244. * @param array $bindings
  245. * @return int
  246. */
  247. public function delete($query, $bindings = array())
  248. {
  249. return $this->affectingStatement($query, $bindings);
  250. }
  251. /**
  252. * Execute an SQL statement and return the boolean result.
  253. *
  254. * @param string $query
  255. * @param array $bindings
  256. * @return bool
  257. */
  258. public function statement($query, $bindings = array())
  259. {
  260. return $this->run($query, $bindings, function($me, $query, $bindings)
  261. {
  262. if ($me->pretending()) return true;
  263. $bindings = $me->prepareBindings($bindings);
  264. return $me->getPdo()->prepare($query)->execute($bindings);
  265. });
  266. }
  267. /**
  268. * Run an SQL statement and get the number of rows affected.
  269. *
  270. * @param string $query
  271. * @param array $bindings
  272. * @return int
  273. */
  274. public function affectingStatement($query, $bindings = array())
  275. {
  276. return $this->run($query, $bindings, function($me, $query, $bindings)
  277. {
  278. if ($me->pretending()) return 0;
  279. // For update or delete statements, we want to get the number of rows affected
  280. // by the statement and return that back to the developer. We'll first need
  281. // to execute the statement and then we'll use PDO to fetch the affected.
  282. $statement = $me->getPdo()->prepare($query);
  283. $statement->execute($me->prepareBindings($bindings));
  284. return $statement->rowCount();
  285. });
  286. }
  287. /**
  288. * Run a raw, unprepared query against the PDO connection.
  289. *
  290. * @param string $query
  291. * @return bool
  292. */
  293. public function unprepared($query)
  294. {
  295. return $this->run($query, array(), function($me, $query, $bindings)
  296. {
  297. if ($me->pretending()) return true;
  298. return (bool) $me->getPdo()->exec($query);
  299. });
  300. }
  301. /**
  302. * Prepare the query bindings for execution.
  303. *
  304. * @param array $bindings
  305. * @return array
  306. */
  307. public function prepareBindings(array $bindings)
  308. {
  309. $grammar = $this->getQueryGrammar();
  310. foreach ($bindings as $key => $value)
  311. {
  312. // We need to transform all instances of the DateTime class into an actual
  313. // date string. Each query grammar maintains its own date string format
  314. // so we'll just ask the grammar for the format to get from the date.
  315. if ($value instanceof DateTime)
  316. {
  317. $bindings[$key] = $value->format($grammar->getDateFormat());
  318. }
  319. elseif ($value === false)
  320. {
  321. $bindings[$key] = 0;
  322. }
  323. }
  324. return $bindings;
  325. }
  326. /**
  327. * Execute a Closure within a transaction.
  328. *
  329. * @param Closure $callback
  330. * @return mixed
  331. */
  332. public function transaction(Closure $callback)
  333. {
  334. $this->pdo->beginTransaction();
  335. // We'll simply execute the given callback within a try / catch block
  336. // and if we catch any exception we can rollback the transaction
  337. // so that none of the changes are persisted to the database.
  338. try
  339. {
  340. $result = $callback($this);
  341. $this->pdo->commit();
  342. }
  343. // If we catch an exception, we will roll back so nothing gets messed
  344. // up in the database. Then we'll re-throw the exception so it can
  345. // be handled how the developer sees fit for their applications.
  346. catch (\Exception $e)
  347. {
  348. $this->pdo->rollBack();
  349. throw $e;
  350. }
  351. return $result;
  352. }
  353. /**
  354. * Execute the given callback in "dry run" mode.
  355. *
  356. * @param Closure $callback
  357. * @return array
  358. */
  359. public function pretend(Closure $callback)
  360. {
  361. $this->pretending = true;
  362. $this->queryLog = array();
  363. // Basically to make the database connection "pretend", we will just return
  364. // the default values for all the query methods, then we will return an
  365. // array of queries that were "executed" within the Closure callback.
  366. $callback($this);
  367. $this->pretending = false;
  368. return $this->queryLog;
  369. }
  370. /**
  371. * Run a SQL statement and log its execution context.
  372. *
  373. * @param string $query
  374. * @param array $bindings
  375. * @param Closure $callback
  376. * @return mixed
  377. */
  378. protected function run($query, $bindings, Closure $callback)
  379. {
  380. $start = microtime(true);
  381. // To execute the statement, we'll simply call the callback, which will actually
  382. // run the SQL against the PDO connection. Then we can calculate the time it
  383. // took to execute and log the query SQL, bindings and time in our memory.
  384. try
  385. {
  386. $result = $callback($this, $query, $bindings);
  387. }
  388. catch (\Exception $e)
  389. {
  390. $this->handleQueryException($e, $query, $bindings);
  391. }
  392. // Once we have run the query we will calculate the time that it took to run and
  393. // then log the query, bindings, and execution time so we will report them on
  394. // the event that the developer needs them. We'll log time in milliseconds.
  395. $time = number_format((microtime(true) - $start) * 1000, 2);
  396. $this->logQuery($query, $bindings, $time);
  397. return $result;
  398. }
  399. /**
  400. * Handle an exception that occurred during a query.
  401. *
  402. * @param Exception $e
  403. * @param string $query
  404. * @param array $bindings
  405. * @return void
  406. */
  407. protected function handleQueryException(\Exception $e, $query, $bindings)
  408. {
  409. $bindings = var_export($bindings, true);
  410. $message = $e->getMessage()." (SQL: {$query}) (Bindings: {$bindings})";
  411. throw new \Exception($message, 0);
  412. }
  413. /**
  414. * Log a query in the connection's query log.
  415. *
  416. * @param string $query
  417. * @param array $bindings
  418. * @param $time
  419. * @return void
  420. */
  421. public function logQuery($query, $bindings, $time = null)
  422. {
  423. if (isset($this->events))
  424. {
  425. $this->events->fire('illuminate.query', array($query, $bindings, $time));
  426. }
  427. $this->queryLog[] = compact('query', 'bindings', 'time');
  428. }
  429. /**
  430. * Register a database query listener with the connection.
  431. *
  432. * @param Closure $callback
  433. * @return void
  434. */
  435. public function listen(Closure $callback)
  436. {
  437. if (isset($this->events))
  438. {
  439. $this->events->listen('illuminate.query', $callback);
  440. }
  441. }
  442. /**
  443. * Get the currently used PDO connection.
  444. *
  445. * @return PDO
  446. */
  447. public function getPdo()
  448. {
  449. return $this->pdo;
  450. }
  451. /**
  452. * Get the database connection name.
  453. *
  454. * @return string|null
  455. */
  456. public function getName()
  457. {
  458. return $this->getConfig('name');
  459. }
  460. /**
  461. * Get an option from the configuration options.
  462. *
  463. * @param string $option
  464. * @return mixed
  465. */
  466. public function getConfig($option)
  467. {
  468. return array_get($this->config, $option);
  469. }
  470. /**
  471. * Get the PDO driver name.
  472. *
  473. * @return string
  474. */
  475. public function getDriverName()
  476. {
  477. return $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME);
  478. }
  479. /**
  480. * Get the query grammar used by the connection.
  481. *
  482. * @return Illuminate\Database\Query\Grammars\Grammar
  483. */
  484. public function getQueryGrammar()
  485. {
  486. return $this->queryGrammar;
  487. }
  488. /**
  489. * Set the query grammar used by the connection.
  490. *
  491. * @param Illuminate\Database\Query\Grammars\Grammar
  492. * @return void
  493. */
  494. public function setQueryGrammar(Query\Grammars\Grammar $grammar)
  495. {
  496. $this->queryGrammar = $grammar;
  497. }
  498. /**
  499. * Get the schema grammar used by the connection.
  500. *
  501. * @return Illuminate\Database\Query\Grammars\Grammar
  502. */
  503. public function getSchemaGrammar()
  504. {
  505. return $this->schemaGrammar;
  506. }
  507. /**
  508. * Set the schema grammar used by the connection.
  509. *
  510. * @param Illuminate\Database\Schema\Grammars\Grammar
  511. * @return void
  512. */
  513. public function setSchemaGrammar(Schema\Grammars\Grammar $grammar)
  514. {
  515. $this->schemaGrammar = $grammar;
  516. }
  517. /**
  518. * Get the query post processor used by the connection.
  519. *
  520. * @return Illuminate\Database\Query\Processors\Processor
  521. */
  522. public function getPostProcessor()
  523. {
  524. return $this->postProcessor;
  525. }
  526. /**
  527. * Set the query post processor used by the connection.
  528. *
  529. * @param Illuminate\Database\Query\Processors\Processor
  530. * @return void
  531. */
  532. public function setPostProcessor(Processor $processor)
  533. {
  534. $this->postProcessor = $processor;
  535. }
  536. /**
  537. * Get the event dispatcher used by the connection.
  538. *
  539. * @return Illuminate\Events\Dispatcher
  540. */
  541. public function getEventDispatcher()
  542. {
  543. return $this->events;
  544. }
  545. /**
  546. * Set the event dispatcher instance on the connection.
  547. *
  548. * @param Illuminate\Events\Dispatcher
  549. * @return void
  550. */
  551. public function setEventDispatcher(\Illuminate\Events\Dispatcher $events)
  552. {
  553. $this->events = $events;
  554. }
  555. /**
  556. * Get the paginator environment instance.
  557. *
  558. * @return Illuminate\Pagination\Environment
  559. */
  560. public function getPaginator()
  561. {
  562. if ($this->paginator instanceof Closure)
  563. {
  564. $this->paginator = call_user_func($this->paginator);
  565. }
  566. return $this->paginator;
  567. }
  568. /**
  569. * Set the pagination environment instance.
  570. *
  571. * @param Illuminate\Pagination\Environment|Closure $paginator
  572. * @return void
  573. */
  574. public function setPaginator($paginator)
  575. {
  576. $this->paginator = $paginator;
  577. }
  578. /**
  579. * Determine if the connection in a "dry run".
  580. *
  581. * @return bool
  582. */
  583. public function pretending()
  584. {
  585. return $this->pretending === true;
  586. }
  587. /**
  588. * Get the default fetch mode for the connection.
  589. *
  590. * @return int
  591. */
  592. public function getFetchMode()
  593. {
  594. return $this->fetchMode;
  595. }
  596. /**
  597. * Set the default fetch mode for the connection.
  598. *
  599. * @param int $fetchMode
  600. * @return int
  601. */
  602. public function setFetchMode($fetchMode)
  603. {
  604. $this->fetchMode = $fetchMode;
  605. }
  606. /**
  607. * Get the connection query log.
  608. *
  609. * @return array
  610. */
  611. public function getQueryLog()
  612. {
  613. return $this->queryLog;
  614. }
  615. /**
  616. * Clear the query log.
  617. *
  618. * @return void
  619. */
  620. public function flushQueryLog()
  621. {
  622. $this->queryLog = array();
  623. }
  624. /**
  625. * Get the name of the connected database.
  626. *
  627. * @return string
  628. */
  629. public function getDatabaseName()
  630. {
  631. return $this->database;
  632. }
  633. /**
  634. * Set the name of the connected database.
  635. *
  636. * @param string $database
  637. * @return string
  638. */
  639. public function setDatabaseName($database)
  640. {
  641. $this->database = $database;
  642. }
  643. /**
  644. * Get the table prefix for the connection.
  645. *
  646. * @return string
  647. */
  648. public function getTablePrefix()
  649. {
  650. return $this->tablePrefix;
  651. }
  652. /**
  653. * Set the table prefix in use by the connection.
  654. *
  655. * @param string $prefix
  656. * @return void
  657. */
  658. public function setTablePrefix($prefix)
  659. {
  660. $this->tablePrefix = $prefix;
  661. }
  662. /**
  663. * Set the table prefix and return the grammar.
  664. *
  665. * @param Illuminate\Database\Grammar $grammar
  666. * @return Illuminate\Database\Grammar
  667. */
  668. public function withTablePrefix(Grammar $grammar)
  669. {
  670. $grammar->setTablePrefix($this->tablePrefix);
  671. return $grammar;
  672. }
  673. }