PageRenderTime 40ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/A/Db/Adapter.php

http://skeleton.googlecode.com/
PHP | 361 lines | 225 code | 37 blank | 99 comment | 40 complexity | f448f08887d7a16a88ee2fa80f35d733 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**
  3. * Adapter.php
  4. *
  5. * @license http://www.opensource.org/licenses/bsd-license.php BSD
  6. * @link http://skeletonframework.com/
  7. */
  8. /**
  9. * A_Db_Adapter
  10. *
  11. * Abstract class for database wrappers. Meant to be extended, and abstract methods implemented for database-specific behavior.
  12. *
  13. * @package A_Db
  14. */
  15. abstract class A_Db_Adapter
  16. {
  17. protected $_connection = null;
  18. protected $_config = array();
  19. /**
  20. * convert connnect keys based on this table
  21. *
  22. * @var array
  23. */
  24. protected $_config_alias = array(
  25. 'dbname' => 'database',
  26. 'hostname' => 'host',
  27. 'hostspec' => 'host',
  28. 'user' => 'username'
  29. );
  30. protected $_recordset_class;
  31. protected $_result_class;
  32. protected $_sql = array();
  33. protected $_transaction_level = 0;
  34. protected $_numRows = 0;
  35. protected $_exception = '';
  36. protected $_error = 0;
  37. protected $_errorMsg = '';
  38. protected $_currentDatabase = null;
  39. /**
  40. * Constructor.
  41. *
  42. * Must be passed a configuration array (or implementation of ArrayAccess). The configuration must contain key/value pairs with the information necessary to connect to the database. These options are common to most adapters:
  43. *
  44. * database => (string) The name of the database to user
  45. * username => (string) Connect to the database as this username.
  46. * password => (string) Password associated with the username.
  47. * host => (string) What host to connect to, defaults to localhost
  48. *
  49. * You can also pass a 'connection' key and it will be used as the database connection.
  50. *
  51. * @param array|ArrayAccess|object|resource $connection
  52. * @throws A_Db_Exception
  53. * @see ArrayAccess
  54. */
  55. public function __construct($config=array())
  56. {
  57. if ($config) {
  58. if (isset($config['connection']) && $config['connection']) {
  59. $this->_connection = $config['connection'];
  60. }
  61. $this->config($config);
  62. }
  63. }
  64. /**
  65. * Configure the internal settings. Will merge and overwrite existing settings. See the constructor for valid configuration keys (sans 'connection').
  66. *
  67. * @param array|ArrayAccess $config
  68. * @return $this
  69. */
  70. public function config($config)
  71. {
  72. if (is_object($config) && method_exists($config, 'toArray')) {
  73. $config = $config->toArray();
  74. }
  75. // config element compatablity
  76. foreach ($this->_config_alias as $alias => $name) {
  77. if (isset($config[$alias])) {
  78. $config[$name] = $config[$alias];
  79. }
  80. }
  81. $this->_config = array_merge($this->_config, $config);
  82. if (isset($config['exception'])) {
  83. $this->setException($config['exception']);
  84. }
  85. return $this;
  86. }
  87. public function setResultClasses($result_class, $recordset_class)
  88. {
  89. if ($result_class) {
  90. $this->_result_class = $result_class;
  91. }
  92. if ($recordset_class) {
  93. $this->_recordset_class = $recordset_class;
  94. }
  95. return $this;
  96. }
  97. public function getConfig($sql='')
  98. {
  99. return $this->_config;
  100. }
  101. public function setException($class)
  102. {
  103. if ($class === true) {
  104. $this->_exception = 'A_Db_Exception';
  105. } else {
  106. $this->_exception = $class;
  107. }
  108. }
  109. public function getSql()
  110. {
  111. return $this->_sql;
  112. }
  113. public function queryHasResultSet($sql)
  114. {
  115. if (in_array(strtoupper(substr($sql, 0, 5)), array('SELEC','SHOW ','DESCR','EXPLA'))) {
  116. return true;
  117. } else {
  118. return false;
  119. }
  120. }
  121. protected function createResultObject()
  122. {
  123. return new $this->_result_class($this->_numRows, $this->_error, $this->_errorMsg);
  124. }
  125. protected function createRecordsetObject()
  126. {
  127. return new $this->_recordset_class($this->_numRows, $this->_error, $this->_errorMsg);
  128. }
  129. /**
  130. * Open connection to database using settings specified in config.
  131. *
  132. * @return $this
  133. */
  134. public function connect()
  135. {
  136. if (!$this->_connection) {
  137. if ($this->_config) {
  138. $this->_connect();
  139. $this->selectDb();
  140. } else {
  141. $this->_errorHandler(1, "No config data. ");
  142. }
  143. }
  144. return $this;
  145. }
  146. /**
  147. * Supplied by child class - Open connection as specified by $config
  148. *
  149. * @return $this
  150. */
  151. abstract protected function _connect();
  152. /*
  153. * Executes a query against the database. If no connection exists, an attempt is made to connect.
  154. *
  155. * @param string|A_Sql_* SQL query to execute. Can be string or a A_Sql object.
  156. * @return A_Db_Recordset_Base
  157. */
  158. public function query($sql, $bind=array())
  159. {
  160. if (is_object($sql)) {
  161. $sql = $sql->render($this);
  162. }
  163. if ($bind) {
  164. $prepare = new A_Sql_Prepare($sql, $bind);
  165. $prepare->setDb($this);
  166. $sql = $prepare->render();
  167. }
  168. $this->connect();
  169. if ($this->_connection) {
  170. $this->_sql[] = $sql;
  171. return $this->_query($sql);
  172. } else {
  173. $this->_errorHandler(3, 'No connection. ');
  174. }
  175. }
  176. abstract protected function _query($sql);
  177. /**
  178. * Closes connection (if close is supported by extension)
  179. *
  180. * @return $this
  181. */
  182. public function close()
  183. {
  184. if ($this->_connection) {
  185. $this->_close();
  186. $this->_connection = null;
  187. }
  188. return $this;
  189. }
  190. abstract protected function _close();
  191. public function disconnect()
  192. {
  193. return $this->close();
  194. }
  195. /**
  196. * Gets the ID of the most recently inserted row
  197. *
  198. * @return string|bool Either the row ID, or false if there is no connection or no rows have been inserted.
  199. */
  200. public function lastId()
  201. {
  202. if ($this->_connection) {
  203. return $this->_lastId();
  204. } else {
  205. return false;
  206. }
  207. }
  208. /**
  209. * Adapter-specific method to get the last inserted row ID.
  210. *
  211. * @return mixed
  212. */
  213. abstract protected function _lastId();
  214. /**
  215. * Switch to using a different database/schema. If the database passed is already selected, no call is made.
  216. *
  217. * @param string $database If omitted, the database in the configuration will be used
  218. */
  219. public function selectDb($database=null) {
  220. if (empty($database)) {
  221. $database = $this->_config['database'];
  222. } else {
  223. $this->_config['database'] = $database;
  224. }
  225. if ($database && $this->_currentDatabase != $database && $this->_connection) {
  226. $this->_selectDb($database);
  227. $this->_currentDatabase = $database;
  228. }
  229. return $this;
  230. }
  231. /**
  232. * Adapter-specific method to select database if adapter supports it.
  233. *
  234. * @return mixed
  235. */
  236. abstract protected function _selectDb($database);
  237. /**
  238. * Adds limit syntax to SQL statement
  239. *
  240. * @param string $sql
  241. * @param int $count
  242. * @param int $offset
  243. */
  244. abstract public function limit($sql, $count, $offset='');
  245. public function start()
  246. {
  247. if ($this->_transaction_level < 1) {
  248. $result = $this->query('START');
  249. $this->_transaction_level = 0;
  250. } else {
  251. $result = false;
  252. }
  253. $this->_transaction_level++;
  254. return $result;
  255. }
  256. public function savepoint($savepoint='')
  257. {
  258. if ($savepoint) {
  259. return $this->query('SAVEPOINT ' . $savepoint);
  260. }
  261. }
  262. public function commit()
  263. {
  264. $this->_transaction_level--;
  265. if ($this->_transaction_level == 0) {
  266. $result = $this->query('COMMIT');
  267. } else {
  268. $result = false;
  269. }
  270. return $result;
  271. }
  272. public function rollback($savepoint='')
  273. {
  274. $this->_transaction_level--;
  275. if ($this->_transaction_level == 0) {
  276. $result = $this->query('ROLLBACK' . ($savepoint ? ' TO SAVEPOINT ' . $savepoint : ''));
  277. } else {
  278. $result = false;
  279. }
  280. return $result;
  281. }
  282. public function getTransactionLevel()
  283. {
  284. return $this->_transaction_level;
  285. }
  286. public function escape($value)
  287. {
  288. return addslashes($value);
  289. }
  290. public function isError()
  291. {
  292. return $this->_error;
  293. }
  294. public function getErrorMsg()
  295. {
  296. return $this->_errorMsg;
  297. }
  298. /**
  299. * Access the connection resource/object directly. Returns boolean false if not connected.
  300. *
  301. * @return resource|object|bool
  302. */
  303. public function getConnection()
  304. {
  305. return $this->_connection ? $this->_connection : false;
  306. }
  307. /**
  308. * Get whether or not the adapter is connected to the database server.
  309. *
  310. * @return bool
  311. */
  312. public function isConnected()
  313. {
  314. return $this->_connection ? true : false;
  315. }
  316. protected function _errorHandler($errno, $errorMsg)
  317. {
  318. $this->_error = $errno;
  319. $this->_errorMsg .= $errorMsg;
  320. if ($errno && $this->_exception) {
  321. throw A_Exception::getInstance($this->_exception, $errorMsg);
  322. }
  323. }
  324. }