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

/src/PDOWrapper.php

https://github.com/louisstow/thin-pdo-wrapper
PHP | 893 lines | 475 code | 114 blank | 304 comment | 80 complexity | cc9d33a7cf14a8803ae71c7edc09f65e MD5 | raw file
Possible License(s): MIT
  1. <?php
  2. /**
  3. * Thin PDO Wrapper: A simple database client utilizing PHP PDO.
  4. *
  5. * Copyright (c) 20010-2011 Louis Stowasser
  6. *
  7. * Distributed under the terms of the MIT License.
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright 2010-2011 Louis Stowasser <louisstow@gmail.com>
  11. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  12. * @link http://github.com/louisstow/thin-pdo-wrapper
  13. */
  14. /**
  15. * Wrapper object for a PDO connection to the database
  16. *
  17. * @package PDO Wrapper
  18. * @author Louis Stowasser - 08/24/2010
  19. * @version 1.2
  20. */
  21. class PDOWrapper {
  22. /**
  23. * Hardcoded database configuration
  24. */
  25. const DB_HOST_MASTER = '';
  26. const DB_NAME_MASTER = '';
  27. const DB_USER_MASTER = '';
  28. const DB_PASSWORD_MASTER = '';
  29. const DB_PORT_MASTER = '';
  30. const SLAVE1_HOST = '';
  31. const SLAVE1_NAME = '';
  32. const SLAVE1_USER = '';
  33. const SLAVE1_PASSWORD = '';
  34. const SLAVE1_PORT = '';
  35. const SLAVE2_HOST = '';
  36. const SLAVE2_NAME = '';
  37. const SLAVE2_USER = '';
  38. const SLAVE2_PASSWORD = '';
  39. const SLAVE2_PORT = '';
  40. // note: to add more, stick with the naming convention
  41. /**
  42. * Write all errors to error log
  43. *
  44. * @var boolean
  45. */
  46. public static $LOG_ERRORS = true;
  47. /**
  48. * Automatically add/update created/updated fields
  49. *
  50. * @var boolean
  51. */
  52. public static $TIMESTAMP_WRITES = false;
  53. /**
  54. * Dynamic master config creds
  55. *
  56. * @var Array - representing config details
  57. */
  58. protected $config_master;
  59. /**
  60. * Dynamic slave config creds
  61. *
  62. * @var Array of Arrays - associative arrays of slave creds
  63. */
  64. protected $config_slaves;
  65. /**
  66. * The PDO objects for the master connection
  67. *
  68. * @var PDO - the Pear Data Object
  69. */
  70. protected $pdo_master;
  71. /**
  72. * The PDO objects for the slave connection
  73. *
  74. * @var PDO - the Pear Data Object
  75. */
  76. protected $pdo_slave;
  77. /**
  78. * We will cache any PDO errors in case we want to get out them externally
  79. *
  80. * @var PDOException - for keeping track of any exceptions in PDO
  81. */
  82. protected $pdo_exception;
  83. /**
  84. * A reference to the singleton instance
  85. *
  86. * @var PDOWrapper
  87. */
  88. protected static $instance = null;
  89. /**
  90. * method instance.
  91. * - static, for singleton, for creating a global instance of this object
  92. *
  93. * @return - PDOWrapper Object
  94. */
  95. public static function instance() {
  96. if (!isset(self::$instance)) {
  97. self::$instance = new PDOWrapper();
  98. }
  99. return self::$instance;
  100. }
  101. /**
  102. * Constructor.
  103. * - make protected so only subclasses and self can create this object (singleton)
  104. */
  105. protected function __construct() {}
  106. /**
  107. * method configMaster
  108. * - configure connection credentials to the master db server
  109. *
  110. * @param host - the host name of the db to connect to
  111. * @param name - the database name
  112. * @param user - the user name
  113. * @param password - the users password
  114. * @param port (optional) - the port to connect using, default to 3306
  115. */
  116. public function configMaster($host, $name, $user, $password, $port=null) {
  117. if (isset($this->pdo_master)) {
  118. error_log('DATABASE WRAPPER::warning, attempting to config master after connection exists');
  119. }
  120. $this->config_master = array(
  121. 'host' => $host,
  122. 'name' => $name,
  123. 'user' => $user,
  124. 'password' => $password,
  125. 'port' => $port
  126. );
  127. }
  128. /**
  129. * method configSlave
  130. * - configure a connection to a slave (can be called multiple times)
  131. *
  132. * @param host - the host name of the db to connect to
  133. * @param name - the database name
  134. * @param user - the user name
  135. * @param password - the users password
  136. * @param port (optional) - the port to connect using, default to 3306
  137. */
  138. public function configSlave($host, $name, $user, $password, $port=null) {
  139. if (isset($this->pdo_slave)) {
  140. error_log('DATABASE WRAPPER::warning, attempting to config slave after connection exists');
  141. }
  142. if (!isset($this->config_slaves)) {
  143. $this->config_slaves = array();
  144. }
  145. $this->config_slaves[] = array(
  146. 'host' => $host,
  147. 'name' => $name,
  148. 'user' => $user,
  149. 'password' => $password,
  150. 'port' => $port
  151. );
  152. }
  153. /**
  154. * method createConnection.
  155. * - create a PDO connection using the credentials provided
  156. *
  157. * @param host - the host name of the db to connect to
  158. * @param name - the database name
  159. * @param user - the user name
  160. * @param password - the users password
  161. * @param port (optional) - the port to connect using, default to 3306
  162. * @return PDO object with a connection to the database specified
  163. */
  164. protected function createConnection($host, $name, $user, $password, $port=null) {
  165. // attempt to create pdo object and connect to the database
  166. try {
  167. // bulild the connection string from static constants
  168. $connection_string = 'mysql:host='.$host.';dbname='.$name.';';
  169. // add the port if one was specified
  170. if (!empty($port)) {
  171. $connection_string .= "port=$port";
  172. }
  173. // initialize the PDO object
  174. $new_connection = new PDO($connection_string, $user, $password);
  175. // set the error mode
  176. $new_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  177. // return the new connection
  178. return $new_connection;
  179. }
  180. // handle any exceptions by catching them and returning false
  181. catch (PDOException $e) {
  182. if (self::$LOG_ERRORS == true) {
  183. error_log('DATABASE WRAPPER::'.print_r($e, true));
  184. }
  185. $this->pdo_exception = $e;
  186. return false;
  187. }
  188. catch(Exception $e) {
  189. if (self::$LOG_ERRORS == true) {
  190. error_log('DATABASE WRAPPER::'.print_r($e, true));
  191. }
  192. $this->pdo_exception = $e;
  193. return false;
  194. }
  195. }
  196. /**
  197. * method getMaster.
  198. * - grab the PDO connection to the master DB
  199. */
  200. protected function getMaster() {
  201. // if we have not been configured, use hard coded values
  202. if (!isset($this->config_master)) {
  203. $this->config_master = array(
  204. 'host' => self::DB_HOST_MASTER,
  205. 'name' => self::DB_NAME_MASTER,
  206. 'user' => self::DB_USER_MASTER,
  207. 'password' => self::DB_PASSWORD_MASTER,
  208. 'port' => self::DB_PORT_MASTER
  209. );
  210. }
  211. // if we have not created the master db connection yet, create it now
  212. if (!isset($this->pdo_master)) {
  213. $this->pdo_master = $this->createConnection(
  214. $this->config_master['host'],
  215. $this->config_master['name'],
  216. $this->config_master['user'],
  217. $this->config_master['password'],
  218. $this->config_master['port']
  219. );
  220. }
  221. return $this->pdo_master;
  222. }
  223. /**
  224. * method getSlave.
  225. * - grab the PDO connection to the slave DB, create it if not there
  226. */
  227. protected function getSlave() {
  228. // if we have not created a slave db connection, create it now
  229. if (!isset($this->pdo_slave)) {
  230. // if no slaves were configured, use hardcoded values
  231. if (!isset($this->config_slaves)) {
  232. $i = 1;
  233. while (defined('self::SLAVE' . $i . '_HOST')
  234. && constant('self::SLAVE' . $i . '_HOST')) {
  235. $this->config_slaves[] = array(
  236. 'host' => constant('self::SLAVE' . $i . '_HOST'),
  237. 'name' => constant('self::SLAVE' . $i . '_NAME'),
  238. 'user' => constant('self::SLAVE' . $i . '_USER'),
  239. 'password' => constant('self::SLAVE' . $i . '_PASSWORD'),
  240. 'port' => constant('self::SLAVE' . $i . '_PORT'),
  241. );
  242. $i++;
  243. }
  244. }
  245. // if no slaves are configured, use the master connection
  246. if (empty($this->config_slaves)) {
  247. $this->pdo_slave = $this->getMaster();
  248. }
  249. // if we have slaves, randomly choose one to use for this request and connect
  250. else {
  251. $random_slave = $this->config_slaves[array_rand($this->config_slaves)];
  252. $this->pdo_slave = $this->createConnection(
  253. $random_slave['host'],
  254. $random_slave['name'],
  255. $random_slave['user'],
  256. $random_slave['password'],
  257. $random_slave['port']
  258. );
  259. }
  260. }
  261. return $this->pdo_slave;
  262. }
  263. /**
  264. * method select.
  265. * - retrieve information from the database, as an array
  266. *
  267. * @param string $table - the name of the db table we are retreiving the rows from
  268. * @param array $params - associative array representing the WHERE clause filters
  269. * @param int $limit (optional) - the amount of rows to return
  270. * @param int $start (optional) - the row to start on, indexed by zero
  271. * @param array $order_by (optional) - an array with order by clause
  272. * @param bool $use_master (optional) - use the master db for this read
  273. * @return mixed - associate representing the fetched table row, false on failure
  274. */
  275. public function select($table, $params = null, $limit = null, $start = null, $order_by=null, $use_master = false) {
  276. // building query string
  277. $sql_str = "SELECT * FROM $table";
  278. // append WHERE if necessary
  279. $sql_str .= ( count($params)>0 ? ' WHERE ' : '' );
  280. $add_and = false;
  281. // add each clause using parameter array
  282. if (empty($params)) {
  283. $params = array();
  284. }
  285. foreach ($params as $key=>$val) {
  286. // only add AND after the first clause item has been appended
  287. if ($add_and) {
  288. $sql_str .= ' AND ';
  289. } else {
  290. $add_and = true;
  291. }
  292. // append clause item
  293. $sql_str .= "$key = :$key";
  294. }
  295. // add the order by clause if we have one
  296. if (!empty($order_by)) {
  297. $sql_str .= ' ORDER BY';
  298. $add_comma = false;
  299. foreach ($order_by as $column => $order) {
  300. if ($add_comma) {
  301. $sql_str .= ', ';
  302. }
  303. else {
  304. $add_comma = true;
  305. }
  306. $sql_str .= " $column $order";
  307. }
  308. }
  309. // add the limit clause if we have one
  310. if (!is_null($limit)) {
  311. $sql_str .= ' LIMIT '.(!is_null($start) ? "$start, ": '')."$limit";
  312. }
  313. // now we attempt to retrieve the row using the sql string
  314. try {
  315. // decide which database we are selecting from
  316. $pdo_connection = $use_master ? $this->getMaster() : $this->getSlave();
  317. $pstmt = $pdo_connection->prepare($sql_str);
  318. // bind each parameter in the array
  319. foreach ($params as $key=>$val) {
  320. $pstmt->bindValue(':'.$key, $val);
  321. }
  322. $pstmt->execute();
  323. // now return the results, depending on if we want all or first row only
  324. if ( !is_null($limit) && $limit == 1 ) {
  325. return $pstmt->fetch(PDO::FETCH_ASSOC);
  326. } else {
  327. return $pstmt->fetchAll(PDO::FETCH_ASSOC);
  328. }
  329. }
  330. catch(PDOException $e) {
  331. if (self::$LOG_ERRORS == true) {
  332. error_log('DATABASE WRAPPER::'.print_r($e, true));
  333. }
  334. $this->pdo_exception = $e;
  335. return false;
  336. }
  337. catch(Exception $e) {
  338. if (self::$LOG_ERRORS == true) {
  339. error_log('DATABASE WRAPPER::'.print_r($e, true));
  340. }
  341. $this->pdo_exception = $e;
  342. return false;
  343. }
  344. }
  345. /**
  346. * method selectMaster.
  347. * - retrieve information from the master database, as an array
  348. *
  349. * @param table - the name of the db table we are retreiving the rows from
  350. * @param params - associative array representing the WHERE clause filters
  351. * @param int $limit (optional) - the amount of rows to return
  352. * @param int $start (optional) - the row to start on, indexed by zero
  353. * @param array $order_by (optional) - an array with order by clause
  354. * @return mixed - associate representing the fetched table row, false on failure
  355. */
  356. public function selectMaster($table, $params = array(), $limit = null, $start = null, $order_by=null) {
  357. return $this->select($table, $params, $limit, $start, $order_by, true);
  358. }
  359. /**
  360. * method selectFirst.
  361. * - retrieve the first row returned from a select statement
  362. *
  363. * @param table - the name of the db table we are retreiving the rows from
  364. * @param params - associative array representing the WHERE clause filters
  365. * @param array $order_by (optional) - an array with order by clause
  366. * @return mixed - associate representing the fetched table row, false on failure
  367. */
  368. public function selectFirst($table, $params = array(), $order_by=null) {
  369. return $this->select($table, $params, 1, null, $order_by);
  370. }
  371. /**
  372. * method selectFirstMaster.
  373. * - retrieve the first row returned from a select statement using the master database
  374. *
  375. * @param table - the name of the db table we are retreiving the rows from
  376. * @param params - associative array representing the WHERE clause filters
  377. * @param array $order_by (optional) - an array with order by clause
  378. * @return mixed - associate representing the fetched table row, false on failure
  379. */
  380. public function selectFirstMaster($table, $params = array(), $order_by=null) {
  381. return $this->select($table, $params, 1, null, $order_by, true);
  382. }
  383. /**
  384. * method delete.
  385. * - deletes rows from a table based on the parameters
  386. *
  387. * @param table - the name of the db table we are deleting the rows from
  388. * @param params - associative array representing the WHERE clause filters
  389. * @return bool - associate representing the fetched table row, false on failure
  390. */
  391. public function delete($table, $params = array()) {
  392. // building query string
  393. $sql_str = "DELETE FROM $table";
  394. // append WHERE if necessary
  395. $sql_str .= ( count($params)>0 ? ' WHERE ' : '' );
  396. $add_and = false;
  397. // add each clause using parameter array
  398. foreach ($params as $key=>$val) {
  399. // only add AND after the first clause item has been appended
  400. if ($add_and) {
  401. $sql_str .= ' AND ';
  402. } else {
  403. $add_and = true;
  404. }
  405. // append clause item
  406. $sql_str .= "$key = :$key";
  407. }
  408. // now we attempt to retrieve the row using the sql string
  409. try {
  410. $pstmt = $this->getMaster()->prepare($sql_str);
  411. // bind each parameter in the array
  412. foreach ($params as $key=>$val) {
  413. $pstmt->bindValue(':'.$key, $val);
  414. }
  415. // execute the delete query
  416. $successful_delete = $pstmt->execute();
  417. // if we were successful, return the amount of rows updated, otherwise return false
  418. return ($successful_delete == true) ? $pstmt->rowCount() : false;
  419. }
  420. catch(PDOException $e) {
  421. if (self::$LOG_ERRORS == true) {
  422. error_log('DATABASE WRAPPER::'.print_r($e, true));
  423. }
  424. $this->pdo_exception = $e;
  425. return false;
  426. }
  427. catch(Exception $e) {
  428. if (self::$LOG_ERRORS == true) {
  429. error_log('DATABASE WRAPPER::'.print_r($e, true));
  430. }
  431. $this->pdo_exception = $e;
  432. return false;
  433. }
  434. }
  435. /**
  436. * method update.
  437. * - updates a row to the specified table
  438. *
  439. * @param string $table - the name of the db table we are adding row to
  440. * @param array $params - associative array representing the columns and their respective values to update
  441. * @param array $wheres (Optional) - the where clause of the query
  442. * @param bool $timestamp_this (Optional) - if true we set date_created and date_modified values to now
  443. * @return int|bool - the amount of rows updated, false on failure
  444. */
  445. public function update($table, $params, $wheres=array(), $timestamp_this=null) {
  446. if (is_null($timestamp_this)) {
  447. $timestamp_this = self::$TIMESTAMP_WRITES;
  448. }
  449. // build the set part of the update query by
  450. // adding each parameter into the set query string
  451. $add_comma = false;
  452. $set_string = '';
  453. foreach ($params as $key=>$val) {
  454. // only add comma after the first parameter has been appended
  455. if ($add_comma) {
  456. $set_string .= ', ';
  457. } else {
  458. $add_comma = true;
  459. }
  460. // now append the parameter
  461. $set_string .= "$key=:param_$key";
  462. }
  463. // add the timestamp columns if neccessary
  464. if ($timestamp_this === true) {
  465. $set_string .= ($add_comma ? ', ' : '') . 'date_modified='.time();
  466. }
  467. // lets add our where clause if we have one
  468. $where_string = '';
  469. if (!empty($wheres)) {
  470. // load each key value pair, and implode them with an AND
  471. $where_array = array();
  472. foreach($wheres as $key => $val) {
  473. $where_array[] = "$key=:where_$key";
  474. }
  475. // build the final where string
  476. $where_string = 'WHERE '.implode(' AND ', $where_array);
  477. }
  478. // build final update string
  479. $sql_str = "UPDATE $table SET $set_string $where_string";
  480. // now we attempt to write this row into the database
  481. try {
  482. $pstmt = $this->getMaster()->prepare($sql_str);
  483. // bind each parameter in the array
  484. foreach ($params as $key=>$val) {
  485. $pstmt->bindValue(':param_'.$key, $val);
  486. }
  487. // bind each where item in the array
  488. foreach ($wheres as $key=>$val) {
  489. $pstmt->bindValue(':where_'.$key, $val);
  490. }
  491. // execute the update query
  492. $successful_update = $pstmt->execute();
  493. // if we were successful, return the amount of rows updated, otherwise return false
  494. return ($successful_update == true) ? $pstmt->rowCount() : false;
  495. }
  496. catch(PDOException $e) {
  497. if (self::$LOG_ERRORS == true) {
  498. error_log('DATABASE WRAPPER::'.print_r($e, true));
  499. }
  500. $this->pdo_exception = $e;
  501. return false;
  502. }
  503. catch(Exception $e) {
  504. if (self::$LOG_ERRORS == true) {
  505. error_log('DATABASE WRAPPER::'.print_r($e, true));
  506. }
  507. $this->pdo_exception = $e;
  508. return false;
  509. }
  510. }
  511. /**
  512. * method insert.
  513. * - adds a row to the specified table
  514. *
  515. * @param string $table - the name of the db table we are adding row to
  516. * @param array $params - associative array representing the columns and their respective values
  517. * @param bool $timestamp_this (Optional), if true we set date_created and date_modified values to now
  518. * @return mixed - new primary key of inserted table, false on failure
  519. */
  520. public function insert($table, $params = array(), $timestamp_this = null) {
  521. if (is_null($timestamp_this)) {
  522. $timestamp_this = self::$TIMESTAMP_WRITES;
  523. }
  524. // first we build the sql query string
  525. $columns_str = '(';
  526. $values_str = 'VALUES (';
  527. $add_comma = false;
  528. // add each parameter into the query string
  529. foreach ($params as $key=>$val) {
  530. // only add comma after the first parameter has been appended
  531. if ($add_comma) {
  532. $columns_str .= ', ';
  533. $values_str .= ', ';
  534. } else {
  535. $add_comma = true;
  536. }
  537. // now append the parameter
  538. $columns_str .= "$key";
  539. $values_str .= ":$key";
  540. }
  541. // add the timestamp columns if neccessary
  542. if ($timestamp_this === true) {
  543. $columns_str .= ($add_comma ? ', ' : '') . 'date_created, date_modified';
  544. $values_str .= ($add_comma ? ', ' : '') . time().', '.time();
  545. }
  546. // close the builder strings
  547. $columns_str .= ') ';
  548. $values_str .= ')';
  549. // build final insert string
  550. $sql_str = "INSERT INTO $table $columns_str $values_str";
  551. // now we attempt to write this row into the database
  552. try {
  553. $pstmt = $this->getMaster()->prepare($sql_str);
  554. // bind each parameter in the array
  555. foreach ($params as $key=>$val) {
  556. $pstmt->bindValue(':'.$key, $val);
  557. }
  558. $pstmt->execute();
  559. $newID = $this->getMaster()->lastInsertId();
  560. // return the new id
  561. return $newID;
  562. }
  563. catch(PDOException $e) {
  564. if (self::$LOG_ERRORS == true) {
  565. error_log('DATABASE WRAPPER::'.print_r($e, true));
  566. }
  567. $this->pdo_exception = $e;
  568. return false;
  569. }
  570. catch(Exception $e) {
  571. if (self::$LOG_ERRORS == true) {
  572. error_log('DATABASE WRAPPER::'.print_r($e, true));
  573. }
  574. $this->pdo_exception = $e;
  575. return false;
  576. }
  577. }
  578. /**
  579. * method insertMultiple.
  580. * - adds multiple rows to a table with a single query
  581. *
  582. * @param string $table - the name of the db table we are adding row to
  583. * @param array $columns - contains the column names
  584. * @param bool $timestamp_these (Optional), if true we set date_created and date_modified values to NOW() for each row
  585. * @return mixed - new primary key of inserted table, false on failure
  586. */
  587. public function insertMultiple($table, $columns = array(), $rows = array(), $timestamp_these = null) {
  588. if (is_null($timestamp_these)) {
  589. $timestamp_these = self::$TIMESTAMP_WRITES;
  590. }
  591. // generate the columns portion of the insert statment
  592. // adding the timestamp fields if needs be
  593. if ($timestamp_these) {
  594. $columns[] = 'date_created';
  595. $columns[] = 'date_modified';
  596. }
  597. $columns_str = '(' . implode(',', $columns) . ') ';
  598. // generate the values portions of the string
  599. $values_str = 'VALUES ';
  600. $add_comma = false;
  601. foreach ($rows as $row_index => $row_values) {
  602. // only add comma after the first row has been added
  603. if ($add_comma) {
  604. $values_str .= ', ';
  605. } else {
  606. $add_comma = true;
  607. }
  608. // here we will create the values string for a single row
  609. $values_str .= '(';
  610. $add_comma_forvalue = false;
  611. foreach ($row_values as $value_index => $value) {
  612. if ($add_comma_forvalue) {
  613. $values_str .= ', ';
  614. } else {
  615. $add_comma_forvalue = true;
  616. }
  617. // generate the bind variable name based on the row and column index
  618. $values_str .= ':'.$row_index.'_'.$value_index;
  619. }
  620. // append timestamps if necessary
  621. if ($timestamp_these) {
  622. $values_str .= ($add_comma_forvalue ? ', ' : '') . time().', '.time();
  623. }
  624. $values_str .= ')';
  625. }
  626. // build final insert string
  627. $sql_str = "INSERT INTO $table $columns_str $values_str";
  628. // now we attempt to write this multi inster query to the database using a transaction
  629. try {
  630. $this->getMaster()->beginTransaction();
  631. $pstmt = $this->getMaster()->prepare($sql_str);
  632. // traverse the 2d array of rows and values to bind all parameters
  633. foreach ($rows as $row_index => $row_values) {
  634. foreach ($row_values as $value_index => $value) {
  635. $pstmt->bindValue(':'.$row_index.'_'.$value_index, $value);
  636. }
  637. }
  638. // now lets execute the statement, commit the transaction and return
  639. $pstmt->execute();
  640. $this->getMaster()->commit();
  641. return true;
  642. }
  643. catch(PDOException $e) {
  644. if (self::$LOG_ERRORS == true) {
  645. error_log('DATABASE WRAPPER::'.print_r($e, true));
  646. }
  647. $this->pdo_exception = $e;
  648. $this->getMaster()->rollback();
  649. return false;
  650. }
  651. catch(Exception $e) {
  652. if (self::$LOG_ERRORS == true) {
  653. error_log('DATABASE WRAPPER::'.print_r($e, true));
  654. }
  655. $this->pdo_exception = $e;
  656. $this->getMaster()->rollback();
  657. return false;
  658. }
  659. }
  660. /**
  661. * method execute.
  662. * - executes a query that modifies the database
  663. *
  664. * @param string $query - the SQL query we are executing
  665. * @param bool $use_master (Optional) - whether or not to use the master connection
  666. * @return mixed - the affected rows, false on failure
  667. */
  668. public function execute($query, $params=array()) {
  669. try {
  670. // use the master connection
  671. $pdo_connection = $this->getMaster();
  672. // prepare the statement
  673. $pstmt = $pdo_connection->prepare($query);
  674. // bind each parameter in the array
  675. foreach ((array)$params as $key=>$val) {
  676. $pstmt->bindValue($key, $val);
  677. }
  678. // execute the query
  679. $result = $pstmt->execute();
  680. // only if return value is false did this query fail
  681. return ($result == true) ? $pstmt->rowCount() : false;
  682. }
  683. catch(PDOException $e) {
  684. if (self::$LOG_ERRORS == true) {
  685. error_log('DATABASE WRAPPER::'.print_r($e, true));
  686. }
  687. $this->pdo_exception = $e;
  688. return false;
  689. }
  690. catch(Exception $e) {
  691. if (self::$LOG_ERRORS == true) {
  692. error_log('DATABASE WRAPPER::'.print_r($e, true));
  693. }
  694. $this->pdo_exception = $e;
  695. return false;
  696. }
  697. }
  698. /**
  699. * method query.
  700. * - returns data from a free form select query
  701. *
  702. * @param string $query - the SQL query we are executing
  703. * @param array $params - a list of bind parameters
  704. * @param bool $use_master (Optional) - whether or not to use the master connection
  705. * @return mixed - the affected rows, false on failure
  706. */
  707. public function query($query, $params=array(), $use_master=false) {
  708. try {
  709. // decide which database we are selecting from
  710. $pdo_connection = $use_master ? $this->getMaster() : $this->getSlave();
  711. $pstmt = $pdo_connection->prepare($query);
  712. // bind each parameter in the array
  713. foreach ((array)$params as $key=>$val) {
  714. $pstmt->bindValue($key, $val);
  715. }
  716. // execute the query
  717. $pstmt->execute();
  718. // now return the results
  719. return $pstmt->fetchAll(PDO::FETCH_ASSOC);
  720. }
  721. catch(PDOException $e) {
  722. if (self::$LOG_ERRORS == true) {
  723. error_log('DATABASE WRAPPER::'.print_r($e, true));
  724. }
  725. $this->pdo_exception = $e;
  726. return false;
  727. }
  728. catch(Exception $e) {
  729. if (self::$LOG_ERRORS == true) {
  730. error_log('DATABASE WRAPPER::'.print_r($e, true));
  731. }
  732. $this->pdo_exception = $e;
  733. return false;
  734. }
  735. }
  736. /**
  737. * method queryFirst.
  738. * - returns the first record from a free form select query
  739. *
  740. * @param string $query - the SQL query we are executing
  741. * @param array $params - a list of bind parameters
  742. * @param bool $use_master (Optional) - whether or not to use the master connection
  743. * @return mixed - the affected rows, false on failure
  744. */
  745. public function queryFirst($query, $params=array(), $use_master=false) {
  746. $result = $this->query($query, $params, $use_master);
  747. if (empty($result)) {
  748. return false;
  749. }
  750. else {
  751. return $result[0];
  752. }
  753. }
  754. /**
  755. * method getErrorMessage.
  756. * - returns the last error message caught
  757. */
  758. public function getErrorMessage() {
  759. if ($this->pdo_exception)
  760. return $this->pdo_exception->getMessage();
  761. else
  762. return 'Database temporarily unavailable';
  763. }
  764. /**
  765. * method getError.
  766. * - returns the actual PDO exception
  767. */
  768. public function getPDOException() {
  769. return $this->pdo_exception;
  770. }
  771. /**
  772. * Destructor.
  773. * - release the PDO db connections
  774. */
  775. function __destruct() {
  776. unset($this->pdo_master);
  777. unset($this->pdo_slave);
  778. }
  779. }