ホームページ  >  記事  >  バックエンド開発  >  クエンティン・ゼルヴァースのDBO

クエンティン・ゼルヴァースのDBO

WBOY
WBOYオリジナル
2016-07-25 09:10:09839ブラウズ
『Web 2.0 Development in Practice』の著者である Quentin Zervaas は、本の中で単純な PHP データ アクセス オブジェクトについて言及しました。
  1. /**
  2. * DatabaseObject
  3. *
  4. * データベーステーブル内のデータを簡単に操作するために使用される抽象クラス
  5. * 単純なロード/保存/削除メソッドを介して
  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->gt;_table = $table;
  21. $this->_idField = $idField;
  22. }
  23. public functionload($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 return false;
  30. }
  31. $query = sprintf('select %s from %s where %s = ? ',
  32. join(', ', $this->getSelectFields()),
  33. $this->_table,
  34. $field);
  35. $query = $this->_db->quoteInto($query , $id);
  36. return $this->_load($query);
  37. }
  38. protected function getSelectFields($prefix = '')
  39. {
  40. $fields = array($prefix . $this->_idField);
  41. foreach ($this->_properties as $k => $v)
  42. $fields[] = $prefix 。 $k;
  43. return $fields;
  44. }
  45. 保護関数 _load($query)
  46. {
  47. $result = $this->_db->query($query);
  48. $row = $result-> fetch();
  49. if (!$row)
  50. return false;
  51. $this->_init($row);
  52. $this->postLoad();
  53. return true;
  54. }
  55. public function _init($row)
  56. {
  57. foreach ($this->_properties as $k => $v) {
  58. $val = $row[$k];
  59. switch ($v['type']) {
  60. case self::TYPE_TIMESTAMP:
  61. if (!is_null($val))
  62. $val = strtotime($val);
  63. Break;
  64. case self::TYPE_BOOLEAN:
  65. $val = (bool) $val;
  66. Break;
  67. }
  68. $this->_properties[$k]['value'] = $val;
  69. }
  70. $this->_id = (int) $row[$this->_idField];
  71. }
  72. public function save($useTransactions = true)
  73. {
  74. $update = $this->isSaved();
  75. if ($useTransactions)
  76. $this->db->beginTransaction();
  77. if ($update)
  78. $commit = $this->preUpdate();
  79. else
  80. $commit = $this->preInsert();
  81. if (!$commit) {
  82. if ($useTransactions)
  83. $this ->_db->rollback();
  84. return false;
  85. }
  86. $row = array();
  87. foreach ($this->_properties as $k => $v) {
  88. if ($update && !$v['updated'])
  89. continue;
  90. switch ($v['type']) {
  91. case self::TYPE_TIMESTAMP:
  92. if (!is_null($v ['値'])) {
  93. if ($this->_db インスタンスof Zend_Db_Adapter_Pdo_Pgsql)
  94. $v['値'] = date('Y-m-d H:i:sO', $v['値']);
  95. else
  96. $v['value'] = date('Y-m-d H:i:s', $v['value']);
  97. }
  98. Break;
  99. case self::TYPE_BOOLEAN:
  100. $v['value' ] = (int) ((bool) $v['value']);
  101. Break;
  102. }
  103. $row[$k] = $v['value'];
  104. }
  105. if (count($row ) > 0) {
  106. // 挿入/更新を実行します
  107. if ($update) {
  108. $this->_db->update($this->_table, $row, sprintf('%s = %d) ', $this->_idField, $this->getId()));
  109. }
  110. else {
  111. $this->_db->insert($this->_table, $row);
  112. $this->_id = $this->_db->lastInsertId($this-> _table, $this->_idField);
  113. }
  114. }
  115. // 内部 ID を更新します
  116. if ($commit) {
  117. if ($update)
  118. $commit = $this->postUpdate();
  119. else
  120. $commit = $this->postInsert();
  121. }
  122. if ($useTransactions) {
  123. if ($commit)
  124. $this->_db->commit();
  125. else
  126. $this-> ;_db->rollback();
  127. }
  128. return $commit;
  129. }
  130. public function delete($useTransactions = true)
  131. {
  132. if (!$this->isSaved())
  133. return false;
  134. if ($useTransactions)
  135. $this->_db->beginTransaction();
  136. $commit = $this->preDelete();
  137. if ($commit) {
  138. $this->_db- >delete($this->_table, sprintf('%s = %d', $this->_idField, $this->getId()));
  139. }
  140. else {
  141. if ($useTransactions)
  142. $this->db->rollback();
  143. return false;
  144. }
  145. $commit = $this->postDelete();
  146. $this->id = null;
  147. if ($ useTransactions) {
  148. if ($commit)
  149. $this->_db->commit();
  150. else
  151. $this->_db->rollback();
  152. }
  153. return $commit;
  154. }
  155. public function isSaved()
  156. {
  157. return $this->getId() > 0;
  158. }
  159. public function getId()
  160. {
  161. return (int) $this->gt;_id;
  162. }
  163. public function getDb()
  164. {
  165. return $this->gt;_db;
  166. }
  167. public function __set($name, $value)
  168. {
  169. if (array_key_exists($name, $this->_properties)) {
  170. $this->_properties[$name]['value'] = $value;
  171. $ this->_properties[$name]['updated'] = true;
  172. return true;
  173. }
  174. return false;
  175. }
  176. public function __get($name)
  177. {
  178. return array_key_exists($name, $this ->_プロパティ)? $this->_properties[$name]['value'] : null;
  179. }
  180. protected function add($field, $default = null, $type = null)
  181. {
  182. $this->_properties[$フィールド] = array('value' => $default,
  183. 'type' => in_array($type, self::$types) ? $type : null,
  184. 'updated' => false);
  185. }
  186. 保護関数 preInsert()
  187. {
  188. return true;
  189. }
  190. 保護関数 postInsert()
  191. {
  192. return true;
  193. }
  194. 保護関数 preUpdate()
  195. {
  196. return true;
  197. }
  198. 保護関数 postUpdate ()
  199. {
  200. return true;
  201. }
  202. 保護関数 preDelete()
  203. {
  204. return true;
  205. }
  206. 保護関数 postDelete()
  207. {
  208. return true;
  209. }
  210. 保護関数 postLoad()
  211. {
  212. return true;
  213. }
  214. public static function BuildMultiple($db, $class, $data)
  215. {
  216. $ret = array();
  217. if (!class_exists($class))
  218. throw new Exception('未定義クラス指定された: ' 。 $class);
  219. $testObj = new $class($db);
  220. if (!$testObj instanceof DatabaseObject)
  221. throw new Exception('クラスは DatabaseObject から拡張されていません');
  222. foreach ($data as $ row) {
  223. $obj = new $class($db);
  224. $obj->_init($row);
  225. $ret[$obj->getId()] = $obj;
  226. }
  227. return $ret;
  228. }
  229. }
复制代
  1. class DatabaseObject_User extends DatabaseObject
  2. {
  3. static $userTypes = array('member' => 'メンバー',
  4. '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('パスワード');
  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. 保護関数 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. 保護された関数 postInsert()
  29. {
  30. $this-> profile->setUserId($this->getId());
  31. $this->profile->save(false);
  32. $this->sendEmail('user-register.tpl');
  33. return true;
  34. }
  35. 保護関数 postUpdate()
  36. {
  37. $this->profile->save(false);
  38. return true;
  39. }
  40. 保護関数 preDelete()
  41. {
  42. $this->gt; profile->delete();
  43. return true;
  44. }
  45. public function sendEmail($tpl)
  46. {
  47. $templater = new Templater();
  48. $templater->user = $this;
  49. // フェッチ電子メールの本文
  50. $body = $templater->render('email/' . $tpl);
  51. // 最初の行から件名を抽出します
  52. list($subject, $body) = preg_split('/r|n/', $body, 2);
  53. // 設定して送信します電子メール
  54. $mail = new Zend_Mail();
  55. // 「宛先」行に宛先アドレスとユーザーのフルネームを設定します
  56. $mail->addTo($this->profile->email ,
  57. rim($this->profile->first_name . ' ' .
  58. $this->profile->last_name));
  59. // 設定から管理者の詳細を取得します
  60. $mail- >setFrom(Zend_Registry::get('config')->email->from->email,
  61. Zend_Registry::get('config')->email->from->name);
  62. // 件名と本文を設定してメールを送信します
  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('%s ユーザー %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 = '不明なユーザー名';
  96. Break;
  97. case Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS:
  98. $reason = 'このユーザー名を持つ複数のユーザーが見つかりました';
  99. Break;
  100. case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
  101. $reason = '無効なパスワード';
  102. Break;
  103. default:
  104. $reason = '';
  105. }
  106. $ message = sprintf('%s ユーザー %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. // 新しいパスワードプロパティを生成します
  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. // 新しいパスワードをプロファイルに保存して電子メールを送信
  126. $this->profile->save();
  127. $this->sendEmail ('user-fetch-password.tpl');
  128. return true;
  129. }
  130. public functionconfirmNewPassword($key)
  131. {
  132. // 有効なパスワードリセットデータが設定されていることを確認してください
  133. if (!isset($this- >プロフィール->新しいパスワード)
  134. || !isset($this->profile->new_password_ts)
  135. || !isset($this->profile->new_password_key)) {
  136. return false;
  137. }
  138. // パスワードが 1 日以内に確認されるかどうかを確認します
  139. if (time() - $this->profile ->new_password_ts > 86400)
  140. return false;
  141. // キーが正しいことを確認します
  142. if ($this->profile->new_password_key != $key)
  143. return false;
  144. //有効です。新しいパスワードを使用するようにアカウントを更新します
  145. // new_password は既に 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. // 最後に保存します更新されたユーザー レコードと更新されたプロファイル
  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. returnparent::__set($name, $value);
  177. }
  178. }
  179. ?>
复制代


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。