PageRenderTime 30ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/sPHPf/vendors/RedBean/Driver/PDO.php

http://github.com/alrik11es/sPHPf
PHP | 474 lines | 179 code | 45 blank | 250 comment | 27 complexity | 5c547dbb42ed1590c43e79eaef6d280f MD5 | raw file
  1. <?php
  2. /**
  3. * PDO Driver
  4. * @file RedBean/PDO.php
  5. * @description PDO Driver
  6. * This Driver implements the RedBean Driver API
  7. * @author Gabor de Mooij and the RedBeanPHP Community, Desfrenes
  8. * @license BSD/GPLv2
  9. *
  10. *
  11. * (c) copyright Desfrenes & Gabor de Mooij and the RedBeanPHP community
  12. * This source file is subject to the BSD/GPLv2 License that is bundled
  13. * with this source code in the file license.txt.
  14. *
  15. */
  16. class RedBean_Driver_PDO implements RedBean_Driver {
  17. /**
  18. * Contains database DSN for connecting to database.
  19. * @var string
  20. */
  21. protected $dsn;
  22. /**
  23. * Whether we are in debugging mode or not.
  24. * @var boolean
  25. */
  26. protected $debug = false;
  27. /**
  28. * Holds an instance of ILogger implementation.
  29. * @var RedBean_ILogger
  30. */
  31. protected $logger = NULL;
  32. /**
  33. * Holds the PDO instance.
  34. * @var PDO
  35. */
  36. protected $pdo;
  37. /**
  38. * Holds integer number of affected rows from latest query
  39. * if driver supports this feature.
  40. * @var integer
  41. */
  42. protected $affected_rows;
  43. /**
  44. * Holds result resource.
  45. * @var integer
  46. */
  47. protected $rs;
  48. /**
  49. * Contains arbitrary connection data.
  50. * @var array
  51. */
  52. protected $connectInfo = array();
  53. /**
  54. * Whether you want to use classic String Only binding -
  55. * backward compatibility.
  56. * @var bool
  57. */
  58. public $flagUseStringOnlyBinding = false;
  59. /**
  60. * Whether we are currently connected or not.
  61. * This flag is being used to delay the connection until necessary.
  62. * Delaying connections is a good practice to speed up scripts that
  63. * don't need database connectivity but for some reason want to
  64. * init RedbeanPHP.
  65. * @var boolean
  66. */
  67. protected $isConnected = false;
  68. /**
  69. * Constructor. You may either specify dsn, user and password or
  70. * just give an existing PDO connection.
  71. * Examples:
  72. * $driver = new RedBean_Driver_PDO($dsn, $user, $password);
  73. * $driver = new RedBean_Driver_PDO($existingConnection);
  74. *
  75. * @param string|PDO $dsn database connection string
  76. * @param string $user optional
  77. * @param string $pass optional
  78. *
  79. * @return void
  80. */
  81. public function __construct($dsn, $user = null, $pass = null) {
  82. if ($dsn instanceof PDO) {
  83. $this->pdo = $dsn;
  84. $this->isConnected = true;
  85. $this->pdo->setAttribute(1002, 'SET NAMES utf8');
  86. $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  87. $this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
  88. // make sure that the dsn at least contains the type
  89. $this->dsn = $this->getDatabaseType();
  90. } else {
  91. $this->dsn = $dsn;
  92. $this->connectInfo = array( 'pass'=>$pass, 'user'=>$user );
  93. }
  94. }
  95. /**
  96. * Establishes a connection to the database using PHP PDO
  97. * functionality. If a connection has already been established this
  98. * method will simply return directly. This method also turns on
  99. * UTF8 for the database and PDO-ERRMODE-EXCEPTION as well as
  100. * PDO-FETCH-ASSOC.
  101. *
  102. * @return void
  103. */
  104. public function connect() {
  105. if ($this->isConnected) return;
  106. $user = $this->connectInfo['user'];
  107. $pass = $this->connectInfo['pass'];
  108. //PDO::MYSQL_ATTR_INIT_COMMAND
  109. $this->pdo = new PDO(
  110. $this->dsn,
  111. $user,
  112. $pass,
  113. array(1002 => 'SET NAMES utf8',
  114. PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  115. PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
  116. )
  117. );
  118. $this->pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
  119. $this->isConnected = true;
  120. }
  121. /**
  122. * Binds parameters. This method binds parameters to a PDOStatement for
  123. * Query Execution. This method binds parameters as NULL, INTEGER or STRING
  124. * and supports both named keys and question mark keys.
  125. *
  126. * @param PDOStatement $s PDO Statement instance
  127. * @param array $aValues values that need to get bound to the statement
  128. *
  129. * @return void
  130. */
  131. protected function bindParams($s,$aValues) {
  132. foreach($aValues as $key=>&$value) {
  133. if (is_integer($key)) {
  134. if (is_null($value)){
  135. $s->bindValue($key+1,null,PDO::PARAM_NULL);
  136. }
  137. elseif (!$this->flagUseStringOnlyBinding && RedBean_QueryWriter_AQueryWriter::canBeTreatedAsInt($value) && $value < 2147483648) {
  138. $s->bindParam($key+1,$value,PDO::PARAM_INT);
  139. }
  140. else {
  141. $s->bindParam($key+1,$value,PDO::PARAM_STR);
  142. }
  143. }
  144. else {
  145. if (is_null($value)){
  146. $s->bindValue($key,null,PDO::PARAM_NULL);
  147. }
  148. elseif (!$this->flagUseStringOnlyBinding && RedBean_QueryWriter_AQueryWriter::canBeTreatedAsInt($value) && $value < 2147483648) {
  149. $s->bindParam($key,$value,PDO::PARAM_INT);
  150. }
  151. else {
  152. $s->bindParam($key,$value,PDO::PARAM_STR);
  153. }
  154. }
  155. }
  156. }
  157. /**
  158. * Runs a query. Internal function, available for subclasses. This method
  159. * runs the actual SQL query and binds a list of parameters to the query.
  160. * slots. The result of the query will be stored in the protected property
  161. * $rs (always array). The number of rows affected (result of rowcount, if supported by database)
  162. * is stored in protected property $affected_rows. If the debug flag is set
  163. * this function will send debugging output to screen buffer.
  164. *
  165. * @throws RedBean_Exception_SQL
  166. *
  167. * @param string $sql the SQL string to be send to database server
  168. * @param array $aValues the values that need to get bound to the query slots
  169. */
  170. protected function runQuery($sql,$aValues) {
  171. $this->connect();
  172. if ($this->debug && $this->logger) {
  173. $this->logger->log($sql, $aValues);
  174. }
  175. try {
  176. if (strpos('pgsql',$this->dsn)===0) {
  177. $s = $this->pdo->prepare($sql, array(PDO::PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT => true));
  178. }
  179. else {
  180. $s = $this->pdo->prepare($sql);
  181. }
  182. $this->bindParams( $s, $aValues );
  183. $s->execute();
  184. $this->affected_rows = $s->rowCount();
  185. if ($s->columnCount()) {
  186. $this->rs = $s->fetchAll();
  187. if ($this->debug && $this->logger) $this->logger->log('resultset: ' . count($this->rs) . ' rows');
  188. }
  189. else {
  190. $this->rs = array();
  191. }
  192. }catch(PDOException $e) {
  193. //Unfortunately the code field is supposed to be int by default (php)
  194. //So we need a property to convey the SQL State code.
  195. $x = new RedBean_Exception_SQL( $e->getMessage(), 0);
  196. $x->setSQLState( $e->getCode() );
  197. throw $x;
  198. }
  199. }
  200. /**
  201. * Runs a query and fetches results as a multi dimensional array.
  202. *
  203. * @param string $sql SQL to be executed
  204. *
  205. * @return array $results result
  206. */
  207. public function GetAll( $sql, $aValues=array() ) {
  208. $this->runQuery($sql,$aValues);
  209. return $this->rs;
  210. }
  211. /**
  212. * Runs a query and fetches results as a column.
  213. *
  214. * @param string $sql SQL Code to execute
  215. *
  216. * @return array $results Resultset
  217. */
  218. public function GetCol($sql, $aValues=array()) {
  219. $rows = $this->GetAll($sql,$aValues);
  220. $cols = array();
  221. if ($rows && is_array($rows) && count($rows)>0) {
  222. foreach ($rows as $row) {
  223. $cols[] = array_shift($row);
  224. }
  225. }
  226. return $cols;
  227. }
  228. /**
  229. * Runs a query an returns results as a single cell.
  230. *
  231. * @param string $sql SQL to execute
  232. *
  233. * @return mixed $cellvalue result cell
  234. */
  235. public function GetCell($sql, $aValues=array()) {
  236. $arr = $this->GetAll($sql,$aValues);
  237. $row1 = array_shift($arr);
  238. $col1 = array_shift($row1);
  239. return $col1;
  240. }
  241. /**
  242. * Runs a query and returns a flat array containing the values of
  243. * one row.
  244. *
  245. * @param string $sql SQL to execute
  246. *
  247. * @return array $row result row
  248. */
  249. public function GetRow($sql, $aValues=array()) {
  250. $arr = $this->GetAll($sql, $aValues);
  251. return array_shift($arr);
  252. }
  253. /**
  254. * Executes SQL code and allows key-value binding.
  255. * This function allows you to provide an array with values to bind
  256. * to query parameters. For instance you can bind values to question
  257. * marks in the query. Each value in the array corresponds to the
  258. * question mark in the query that matches the position of the value in the
  259. * array. You can also bind values using explicit keys, for instance
  260. * array(":key"=>123) will bind the integer 123 to the key :key in the
  261. * SQL. This method has no return value.
  262. *
  263. * @param string $sql SQL Code to execute
  264. * @param array $aValues Values to bind to SQL query
  265. *
  266. * @return void
  267. */
  268. public function Execute( $sql, $aValues=array() ) {
  269. $this->runQuery($sql,$aValues);
  270. return $this->affected_rows;
  271. }
  272. /**
  273. * Escapes a string for use in SQL using the currently selected
  274. * PDO driver.
  275. *
  276. * @param string $string string to be escaped
  277. *
  278. * @return string $string escaped string
  279. */
  280. public function Escape( $str ) {
  281. $this->connect();
  282. return substr(substr($this->pdo->quote($str), 1), 0, -1);
  283. }
  284. /**
  285. * Returns the latest insert ID if driver does support this
  286. * feature.
  287. *
  288. * @return integer $id primary key ID
  289. */
  290. public function GetInsertID() {
  291. $this->connect();
  292. return (int) $this->pdo->lastInsertId();
  293. }
  294. /**
  295. * Returns the number of rows affected by the most recent query
  296. * if the currently selected PDO driver supports this feature.
  297. *
  298. * @return integer $numOfRows number of rows affected
  299. */
  300. public function Affected_Rows() {
  301. $this->connect();
  302. return (int) $this->affected_rows;
  303. }
  304. /**
  305. * Toggles debug mode. In debug mode the driver will print all
  306. * SQL to the screen together with some information about the
  307. * results. All SQL code that passes through the driver will be
  308. * passes on to the screen for inspection.
  309. * This method has no return value.
  310. *
  311. * Additionally you can inject RedBean_ILogger implementation
  312. * where you can define your own log() method
  313. *
  314. * @param boolean $trueFalse turn on/off
  315. * @param RedBean_ILogger $logger
  316. *
  317. * @return void
  318. */
  319. public function setDebugMode( $tf, $logger = NULL ) {
  320. $this->connect();
  321. $this->debug = (bool)$tf;
  322. if ($this->debug and !$logger) $logger = new RedBean_Logger();
  323. $this->setLogger($logger);
  324. }
  325. /**
  326. * Injects RedBean_ILogger object.
  327. *
  328. * @param RedBean_ILogger $logger
  329. */
  330. public function setLogger( RedBean_ILogger $logger ) {
  331. $this->logger = $logger;
  332. }
  333. /**
  334. * Gets RedBean_ILogger object.
  335. *
  336. * @return RedBean_ILogger
  337. */
  338. public function getLogger() {
  339. return $this->logger;
  340. }
  341. /**
  342. * Starts a transaction.
  343. * This method is part of the transaction mechanism of
  344. * RedBeanPHP. All queries in a transaction are executed together.
  345. * In case of an error all commands will be rolled back so none of the
  346. * SQL in the transaction will affect the DB. Using transactions is
  347. * considered best practice.
  348. * This method has no return value.
  349. *
  350. * @return void
  351. */
  352. public function StartTrans() {
  353. $this->connect();
  354. $this->pdo->beginTransaction();
  355. }
  356. /**
  357. * Commits a transaction.
  358. * This method is part of the transaction mechanism of
  359. * RedBeanPHP. All queries in a transaction are executed together.
  360. * In case of an error all commands will be rolled back so none of the
  361. * SQL in the transaction will affect the DB. Using transactions is
  362. * considered best practice.
  363. * This method has no return value.
  364. *
  365. * @return void
  366. */
  367. public function CommitTrans() {
  368. $this->connect();
  369. $this->pdo->commit();
  370. }
  371. /**
  372. * Rolls back a transaction.
  373. * This method is part of the transaction mechanism of
  374. * RedBeanPHP. All queries in a transaction are executed together.
  375. * In case of an error all commands will be rolled back so none of the
  376. * SQL in the transaction will affect the DB. Using transactions is
  377. * considered best practice.
  378. * This method has no return value.
  379. *
  380. * @return void
  381. */
  382. public function FailTrans() {
  383. $this->connect();
  384. $this->pdo->rollback();
  385. }
  386. /**
  387. * Returns the name of the database type/brand: i.e. mysql, db2 etc.
  388. *
  389. * @return string $typeName database identification
  390. */
  391. public function getDatabaseType() {
  392. $this->connect();
  393. return $this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
  394. }
  395. /**
  396. * Returns the version number of the database.
  397. *
  398. * @return mixed $version version number of the database
  399. */
  400. public function getDatabaseVersion() {
  401. $this->connect();
  402. return $this->pdo->getAttribute(PDO::ATTR_CLIENT_VERSION);
  403. }
  404. /**
  405. * Returns the underlying PHP PDO instance.
  406. *
  407. * @return PDO $pdo PDO instance used by PDO wrapper
  408. */
  409. public function getPDO() {
  410. $this->connect();
  411. return $this->pdo;
  412. }
  413. /**
  414. * Closes database connection by destructing PDO.
  415. */
  416. public function close() {
  417. $this->pdo = null;
  418. $this->isConnected = false;
  419. }
  420. /**
  421. * Returns TRUE if the current PDO instance is connected.
  422. *
  423. * @return boolean $yesNO
  424. */
  425. public function isConnected() {
  426. if (!$this->isConnected && !$this->pdo) return false;
  427. return true;
  428. }
  429. }