当前位置:Gxlcms > PHP教程 > QuentinZervaas'sDBO

QuentinZervaas'sDBO

时间:2021-07-01 10:21:17 帮助过:37人阅读

《Web 2.0 开发实战》一书的作者,Quentin Zervaas 在书中提到的一个简易PHP数据访问对象。
  1. /**
  2. * DatabaseObject
  3. *
  4. * Abstract class used to easily manipulate data in a database table
  5. * via simple load/save/delete methods
  6. */
  7. abstract class DatabaseObject
  8. {
  9. const TYPE_TIMESTAMP = 1;
  10. const TYPE_BOOLEAN = 2;
  11. protected static $types = array(self::TYPE_TIMESTAMP, self::TYPE_BOOLEAN);
  12. private $_id = null;
  13. private $_properties = array();
  14. protected $_db = null;
  15. protected $_table = '';
  16. protected $_idField = '';
  17. public function __construct(Zend_Db_Adapter_Abstract $db, $table, $idField)
  18. {
  19. $this->_db = $db;
  20. $this->_table = $table;
  21. $this->_idField = $idField;
  22. }
  23. public function load($id, $field = null)
  24. {
  25. if (strlen($field) == 0)
  26. $field = $this->_idField;
  27. if ($field == $this->_idField) {
  28. $id = (int) $id;
  29. if ($id <= 0)
  30. return false;
  31. }
  32. $query = sprintf('select %s from %s where %s = ?',
  33. join(', ', $this->getSelectFields()),
  34. $this->_table,
  35. $field);
  36. $query = $this->_db->quoteInto($query, $id);
  37. return $this->_load($query);
  38. }
  39. protected function getSelectFields($prefix = '')
  40. {
  41. $fields = array($prefix . $this->_idField);
  42. foreach ($this->_properties as $k => $v)
  43. $fields[] = $prefix . $k;
  44. return $fields;
  45. }
  46. protected function _load($query)
  47. {
  48. $result = $this->_db->query($query);
  49. $row = $result->fetch();
  50. if (!$row)
  51. return false;
  52. $this->_init($row);
  53. $this->postLoad();
  54. return true;
  55. }
  56. public function _init($row)
  57. {
  58. foreach ($this->_properties as $k => $v) {
  59. $val = $row[$k];
  60. switch ($v['type']) {
  61. case self::TYPE_TIMESTAMP:
  62. if (!is_null($val))
  63. $val = strtotime($val);
  64. break;
  65. case self::TYPE_BOOLEAN:
  66. $val = (bool) $val;
  67. break;
  68. }
  69. $this->_properties[$k]['value'] = $val;
  70. }
  71. $this->_id = (int) $row[$this->_idField];
  72. }
  73. public function save($useTransactions = true)
  74. {
  75. $update = $this->isSaved();
  76. if ($useTransactions)
  77. $this->_db->beginTransaction();
  78. if ($update)
  79. $commit = $this->preUpdate();
  80. else
  81. $commit = $this->preInsert();
  82. if (!$commit) {
  83. if ($useTransactions)
  84. $this->_db->rollback();
  85. return false;
  86. }
  87. $row = array();
  88. foreach ($this->_properties as $k => $v) {
  89. if ($update && !$v['updated'])
  90. continue;
  91. switch ($v['type']) {
  92. case self::TYPE_TIMESTAMP:
  93. if (!is_null($v['value'])) {
  94. if ($this->_db instanceof Zend_Db_Adapter_Pdo_Pgsql)
  95. $v['value'] = date('Y-m-d H:i:sO', $v['value']);
  96. else
  97. $v['value'] = date('Y-m-d H:i:s', $v['value']);
  98. }
  99. break;
  100. case self::TYPE_BOOLEAN:
  101. $v['value'] = (int) ((bool) $v['value']);
  102. break;
  103. }
  104. $row[$k] = $v['value'];
  105. }
  106. if (count($row) > 0) {
  107. // perform insert/update
  108. if ($update) {
  109. $this->_db->update($this->_table, $row, sprintf('%s = %d', $this->_idField, $this->getId()));
  110. }
  111. else {
  112. $this->_db->insert($this->_table, $row);
  113. $this->_id = $this->_db->lastInsertId($this->_table, $this->_idField);
  114. }
  115. }
  116. // update internal id
  117. if ($commit) {
  118. if ($update)
  119. $commit = $this->postUpdate();
  120. else
  121. $commit = $this->postInsert();
  122. }
  123. if ($useTransactions) {
  124. if ($commit)
  125. $this->_db->commit();
  126. else
  127. $this->_db->rollback();
  128. }
  129. return $commit;
  130. }
  131. public function delete($useTransactions = true)
  132. {
  133. if (!$this->isSaved())
  134. return false;
  135. if ($useTransactions)
  136. $this->_db->beginTransaction();
  137. $commit = $this->preDelete();
  138. if ($commit) {
  139. $this->_db->delete($this->_table, sprintf('%s = %d', $this->_idField, $this->getId()));
  140. }
  141. else {
  142. if ($useTransactions)
  143. $this->_db->rollback();
  144. return false;
  145. }
  146. $commit = $this->postDelete();
  147. $this->_id = null;
  148. if ($useTransactions) {
  149. if ($commit)
  150. $this->_db->commit();
  151. else
  152. $this->_db->rollback();
  153. }
  154. return $commit;
  155. }
  156. public function isSaved()
  157. {
  158. return $this->getId() > 0;
  159. }
  160. public function getId()
  161. {
  162. return (int) $this->_id;
  163. }
  164. public function getDb()
  165. {
  166. return $this->_db;
  167. }
  168. public function __set($name, $value)
  169. {
  170. if (array_key_exists($name, $this->_properties)) {
  171. $this->_properties[$name]['value'] = $value;
  172. $this->_properties[$name]['updated'] = true;
  173. return true;
  174. }
  175. return false;
  176. }
  177. public function __get($name)
  178. {
  179. return array_key_exists($name, $this->_properties) ? $this->_properties[$name]['value'] : null;
  180. }
  181. protected function add($field, $default = null, $type = null)
  182. {
  183. $this->_properties[$field] = array('value' => $default,
  184. 'type' => in_array($type, self::$types) ? $type : null,
  185. 'updated' => false);
  186. }
  187. protected function preInsert()
  188. {
  189. return true;
  190. }
  191. protected function postInsert()
  192. {
  193. return true;
  194. }
  195. protected function preUpdate()
  196. {
  197. return true;
  198. }
  199. protected function postUpdate()
  200. {
  201. return true;
  202. }
  203. protected function preDelete()
  204. {
  205. return true;
  206. }
  207. protected function postDelete()
  208. {
  209. return true;
  210. }
  211. protected function postLoad()
  212. {
  213. return true;
  214. }
  215. public static function BuildMultiple($db, $class, $data)
  216. {
  217. $ret = array();
  218. if (!class_exists($class))
  219. throw new Exception('Undefined class specified: ' . $class);
  220. $testObj = new $class($db);
  221. if (!$testObj instanceof DatabaseObject)
  222. throw new Exception('Class does not extend from DatabaseObject');
  223. foreach ($data as $row) {
  224. $obj = new $class($db);
  225. $obj->_init($row);
  226. $ret[$obj->getId()] = $obj;
  227. }
  228. return $ret;
  229. }
  230. }
  1. class DatabaseObject_User extends DatabaseObject
  2. {
  3. static $userTypes = array('member' => 'Member',
  4. 'administrator' => 'Administrator');
  5. public $profile = null;
  6. public $_newPassword = null;
  7. public function __construct($db)
  8. {
  9. parent::__construct($db, 'users', 'user_id');
  10. $this->add('username');
  11. $this->add('password');
  12. $this->add('user_type', 'member');
  13. $this->add('ts_created', time(), self::TYPE_TIMESTAMP);
  14. $this->add('ts_last_login', null, self::TYPE_TIMESTAMP);
  15. $this->profile = new Profile_User($db);
  16. }
  17. protected function preInsert()
  18. {
  19. $this->_newPassword = Text_Password::create(8);
  20. $this->password = $this->_newPassword;
  21. return true;
  22. }
  23. protected function postLoad()
  24. {
  25. $this->profile->setUserId($this->getId());
  26. $this->profile->load();
  27. }
  28. protected function postInsert()
  29. {
  30. $this->profile->setUserId($this->getId());
  31. $this->profile->save(false);
  32. $this->sendEmail('user-register.tpl');
  33. return true;
  34. }
  35. protected function postUpdate()
  36. {
  37. $this->profile->save(false);
  38. return true;
  39. }
  40. protected function preDelete()
  41. {
  42. $this->profile->delete();
  43. return true;
  44. }
  45. public function sendEmail($tpl)
  46. {
  47. $templater = new Templater();
  48. $templater->user = $this;
  49. // fetch the e-mail body
  50. $body = $templater->render('email/' . $tpl);
  51. // extract the subject from the first line
  52. list($subject, $body) = preg_split('/\r|\n/', $body, 2);
  53. // now set up and send the e-mail
  54. $mail = new Zend_Mail();
  55. // set the to address and the user's full name in the 'to' line
  56. $mail->addTo($this->profile->email,
  57. trim($this->profile->first_name . ' ' .
  58. $this->profile->last_name));
  59. // get the admin 'from' details from the config
  60. $mail->setFrom(Zend_Registry::get('config')->email->from->email,
  61. Zend_Registry::get('config')->email->from->name);
  62. // set the subject and body and send the mail
  63. $mail->setSubject(trim($subject));
  64. $mail->setBodyText(trim($body));
  65. $mail->send();
  66. }
  67. public function createAuthIdentity()
  68. {
  69. $identity = new stdClass;
  70. $identity->user_id = $this->getId();
  71. $identity->username = $this->username;
  72. $identity->user_type = $this->user_type;
  73. $identity->first_name = $this->profile->first_name;
  74. $identity->last_name = $this->profile->last_name;
  75. $identity->email = $this->profile->email;
  76. return $identity;
  77. }
  78. public function loginSuccess()
  79. {
  80. $this->ts_last_login = time();
  81. unset($this->profile->new_password);
  82. unset($this->profile->new_password_ts);
  83. unset($this->profile->new_password_key);
  84. $this->save();
  85. $message = sprintf('Successful login attempt from %s user %s',
  86. $_SERVER['REMOTE_ADDR'],
  87. $this->username);
  88. $logger = Zend_Registry::get('logger');
  89. $logger->notice($message);
  90. }
  91. static public function LoginFailure($username, $code = '')
  92. {
  93. switch ($code) {
  94. case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND:
  95. $reason = 'Unknown username';
  96. break;
  97. case Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS:
  98. $reason = 'Multiple users found with this username';
  99. break;
  100. case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
  101. $reason = 'Invalid password';
  102. break;
  103. default:
  104. $reason = '';
  105. }
  106. $message = sprintf('Failed login attempt from %s user %s',
  107. $_SERVER['REMOTE_ADDR'],
  108. $username);
  109. if (strlen($reason) > 0)
  110. $message .= sprintf(' (%s)', $reason);
  111. $logger = Zend_Registry::get('logger');
  112. $logger->warn($message);
  113. }
  114. public function fetchPassword()
  115. {
  116. if (!$this->isSaved())
  117. return false;
  118. // generate new password properties
  119. $this->_newPassword = Text_Password::create(8);
  120. $this->profile->new_password = md5($this->_newPassword);
  121. $this->profile->new_password_ts = time();
  122. $this->profile->new_password_key = md5(uniqid() .
  123. $this->getId() .
  124. $this->_newPassword);
  125. // save new password to profile and send e-mail
  126. $this->profile->save();
  127. $this->sendEmail('user-fetch-password.tpl');
  128. return true;
  129. }
  130. public function confirmNewPassword($key)
  131. {
  132. // check that valid password reset data is set
  133. if (!isset($this->profile->new_password)
  134. || !isset($this->profile->new_password_ts)
  135. || !isset($this->profile->new_password_key)) {
  136. return false;
  137. }
  138. // check if the password is being confirm within a day
  139. if (time() - $this->profile->new_password_ts > 86400)
  140. return false;
  141. // check that the key is correct
  142. if ($this->profile->new_password_key != $key)
  143. return false;
  144. // everything is valid, now update the account to use the new password
  145. // bypass the local setter as new_password is already an md5
  146. parent::__set('password', $this->profile->new_password);
  147. unset($this->profile->new_password);
  148. unset($this->profile->new_password_ts);
  149. unset($this->profile->new_password_key);
  150. // finally, save the updated user record and the updated profile
  151. return $this->save();
  152. }
  153. public function usernameExists($username)
  154. {
  155. $query = sprintf('select count(*) as num from %s where username = ?',
  156. $this->_table);
  157. $result = $this->_db->fetchOne($query, $username);
  158. return $result > 0;
  159. }
  160. static public function IsValidUsername($username)
  161. {
  162. $validator = new Zend_Validate_Alnum();
  163. return $validator->isValid($username);
  164. }
  165. public function __set($name, $value)
  166. {
  167. switch ($name) {
  168. case 'password':
  169. $value = md5($value);
  170. break;
  171. case 'user_type':
  172. if (!array_key_exists($value, self::$userTypes))
  173. $value = 'member';
  174. break;
  175. }
  176. return parent::__set($name, $value);
  177. }
  178. }
  179. ?>

人气教程排行