PageRenderTime 58ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/includes/classes/class.dbstorage.php

https://github.com/DragonFire/wowcs
PHP | 381 lines | 224 code | 27 blank | 130 comment | 46 complexity | b07b27fc42ae04335edd915fcd41748c MD5 | raw file
  1. <?php
  2. /**
  3. * Copyright (C) 2011 Shadez <https://github.com/Shadez>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. **/
  19. /**
  20. * This class introduces simple ORM (Object Related Mapping) feature.
  21. * To use this, you should create new storage class with some options included:
  22. * - fields list (table fields, see examples (/includes/storages/*.php))
  23. * - storage (table) name
  24. * - storage (table) index field
  25. * - database hanler
  26. * If you want to find all achievements with `factionFlag` = 1, you should do this:
  27. * $achievement = new AchievementStorage();
  28. * $achievement->SetSearchQuery(array('factionFlag' => -1))->FindEntry();
  29. * print_r($achievement->GetData()); // will print all found data
  30. * If you want to find achievement with `id` = 6, you should do this:
  31. * $achievement = new AchievementStorage();
  32. * $achievement->FindEntry(6);
  33. * print_r($achievement->GetData()); // will print all found data
  34. * // or you can just simple write:
  35. * echo 'Achievement #' . $achievement->id . ' name is "' . $achievement->name . '".'; // Will print 'Achievement #6 name is "Level 10".'
  36. **/
  37. class WoW_DBStorage {
  38. /**
  39. * Table fields, must be defined in inherited class
  40. **/
  41. public $m_fields = array();
  42. /**
  43. * Table name
  44. **/
  45. protected $m_storageName = null;
  46. /**
  47. * Table index (default search row)
  48. **/
  49. protected $m_storageIndex = '';
  50. /**
  51. * Item entry (id to find)
  52. **/
  53. protected $m_entry = 0;
  54. /**
  55. * Search result
  56. **/
  57. protected $m_data = array();
  58. /**
  59. * Database link, must be defined in child InitStorage() method!
  60. **/
  61. protected $m_db = null;
  62. /**
  63. * WoW DB locale (_en, _ru, etc.), defined at object creation
  64. **/
  65. protected $m_locale = '';
  66. /**
  67. * World DB Locale ID (_loc1, _loc8, etc), defined at object creation, must be > 0
  68. **/
  69. protected $m_dbLocale = 0;
  70. /**
  71. * Advanced search options
  72. **/
  73. protected $m_searchOptions = array();
  74. /**
  75. * Use options or not, will be changed to 'true' in SetSearchOptions()
  76. **/
  77. protected $m_useOptions = false;
  78. /**
  79. * SQL Query data (query with parameters), generated automatically
  80. **/
  81. private $m_sqlData = array();
  82. /**
  83. * Class constructor, defines locale and inits storage
  84. **/
  85. public function __construct() {
  86. $this->m_locale = WoW_Locale::GetLocale();
  87. $this->m_dbLocale = WoW_Locale::GetLocaleID();
  88. $this->InitStorage();
  89. return true;
  90. }
  91. /**
  92. * Defines database, storage name and index. MUST BE re-defined in child class!
  93. **/
  94. protected function InitStorage() {
  95. exit;
  96. }
  97. /**
  98. * Returns data from search query
  99. **/
  100. public function GetData() {
  101. return $this->m_data;
  102. }
  103. /**
  104. * Some actions that will be executed before data loading, should be re-defined in child class (if required).
  105. **/
  106. protected function BeforeLoad() { return $this; }
  107. /**
  108. * Some actions that will be executed after data loading.
  109. * If you will re-define it in child class, add parent::AfterLoad(); in your method!
  110. **/
  111. protected function AfterLoad() {
  112. $keys = array_keys($this->m_fields);
  113. // Find first field's alias
  114. if(isset($this->m_fields[$keys[0]]['alias']))
  115. $keys[0] = $this->m_fields[$keys[0]]['alias']; // Found, set as primary
  116. if(isset($this->m_data[$keys[0]]) && !is_array($this->m_data[$keys[0]])) {
  117. foreach($this->m_fields as $name => $field) {
  118. if(is_array($field) && isset($field['alias']))
  119. $name = $field['alias'];
  120. $this->{$name} = $this->m_data[$name];
  121. }
  122. }
  123. unset($keys, $name, $field);
  124. return $this;
  125. }
  126. /**
  127. * Sets search options. Options must be sent as array:
  128. * array('fieldName' => fieldValue, 'field2Name' => field2Value)
  129. **/
  130. public function SetSearchOptions($options) {
  131. if (!is_array($options)) {
  132. return false;
  133. }
  134. $this->m_searchOptions = $options;
  135. $this->m_useOptions = true;
  136. return $this;
  137. }
  138. /**
  139. * MUST BE called as last method in chain!
  140. *
  141. * $achievement = new AchievementStorage();
  142. * $achievement->SetSearchOptions('factionFlag' => -1)->FindEntry();
  143. *
  144. * or just
  145. *
  146. * $achievement = new AchievementStorage();
  147. * $achievement->FindEntry();
  148. **/
  149. public function FindEntry($entry = 0) {
  150. $this->BeforeLoad();
  151. if((!$this->m_storageIndex && !$this->m_searchOptions) || !$this->m_storageName) {
  152. WoW_Log::WriteError('%s : fatal error: storage name or storage index was not defined!', __METHOD__);
  153. return false;
  154. }
  155. $this->m_entry = $entry;
  156. $sql_query = array(
  157. 'query' => 'SELECT',
  158. 'data' => array()
  159. );
  160. if(is_array($this->m_searchOptions) && $this->m_useOptions) {
  161. $this->AssignSearchData($sql_query)->SetSqlData($sql_query)->select();
  162. }
  163. else {
  164. $this->ParseFields($sql_query);
  165. $sql_query['query'] .= ' WHERE `' . $this->m_storageIndex . '` = \'%s\'';
  166. $sql_query['data'] = array($this->m_entry);
  167. $this->SetSqlData($sql_query)->selectRow();
  168. }
  169. return $this->AfterLoad();
  170. }
  171. /**
  172. * Executes "selectRow" method of $this->m_db object.
  173. **/
  174. protected function selectRow() {
  175. if(!is_object($this->m_db) || !method_exists($this->m_db, 'selectRow'))
  176. return $this;
  177. $this->m_data = call_user_func_array(array($this->m_db, 'selectRow'), $this->m_sqlData);
  178. return $this;
  179. }
  180. /**
  181. * Executes "select" method of $this->m_db object.
  182. **/
  183. protected function select() {
  184. if(!is_object($this->m_db) || !method_exists($this->m_db, 'select'))
  185. return $this;
  186. $this->m_data = call_user_func_array(array($this->m_db, 'select'), $this->m_sqlData);
  187. return $this;
  188. }
  189. /**
  190. * Generates $this->m_sqlData array
  191. **/
  192. private function SetSqlData($sql_query) {
  193. $this->m_sqlData = array($sql_query['query']);
  194. foreach($sql_query['data'] as $element) {
  195. $this->m_sqlData[] = $element;
  196. }
  197. return $this;
  198. }
  199. /**
  200. * Assigns search options
  201. **/
  202. private function AssignSearchData(&$query) {
  203. $this->ParseFields($query)
  204. ->ParseSearchOptions($query);
  205. return $this;
  206. }
  207. /**
  208. * Performs search options parsing
  209. **/
  210. private function ParseSearchOptions(&$query) {
  211. $query['query'] .= ' WHERE';
  212. $count = count($this->m_searchOptions);
  213. $current = 1;
  214. foreach($this->m_searchOptions as $table => $value) {
  215. if(!is_string($table)) {
  216. WoW_Log::WriteLog('%s : skipping index "%s"', __METHOD__, $table);
  217. ++$current;
  218. continue;
  219. }
  220. if(!isset($this->m_fields[$table])) {
  221. WoW_Log::WriteLog('%s : unknown field "%s" in "%s" storage, ignore.', __METHOD__, $table, $this->m_storageName);
  222. continue;
  223. }
  224. $query['query'] .= ' `' . $this->GetAppropriateFieldName($table) . '` = \'%s\'';
  225. $query['data'][] = $value;
  226. if($current < $count) {
  227. $query['query'] .= ' AND';
  228. }
  229. ++$current;
  230. }
  231. return $this;
  232. }
  233. /**
  234. * Returns correct table name
  235. **/
  236. private function GetAppropriateFieldName($f) {
  237. foreach($this->m_fields as $name => &$field) {
  238. if(!is_string($name)) {
  239. continue;
  240. }
  241. if($f == $name) {
  242. if(isset($field['locale']) && $field['locale'] == true) {
  243. return $name . '_' . $this->m_locale;
  244. }
  245. elseif(isset($field['dbLocale']) && $field['dbLocale'] == true) {
  246. return $name . '_loc' . $this->m_dbLocale;
  247. }
  248. else {
  249. return $name;
  250. }
  251. }
  252. }
  253. return $f;
  254. }
  255. /**
  256. * Performs model fields parsing
  257. **/
  258. private function ParseFields(&$query) {
  259. if(!$this->m_fields) {
  260. WoW_Log::WriteError('%s : no fields were found for Model "%s"!', __METHOD__, $this->m_storageName);
  261. return false;
  262. }
  263. $count = count($this->m_fields);
  264. $current = 0;
  265. $query['query'] .= ' ';
  266. foreach($this->m_fields as $name => $field) {
  267. if(!is_string($name) && (is_array($field))) {
  268. WoW_Log::WriteLog('%s : skipping index "%s"', __METHOD__, $name);
  269. ++$current;
  270. continue;
  271. }
  272. elseif(isset($field['locale']) && $field['locale']) {
  273. $query['query'] .= '`' . $name . '_' . $this->m_locale . '` AS `' . $this->FieldAlias($field, $name) . '`';
  274. }
  275. elseif(isset($field['dbLocale']) && $field['dbLocale']) {
  276. $query['query'] .= '`' . $name . '_loc' . $this->m_dbLocale . '` AS `' . $this->FieldAlias($field, $name) . '`';
  277. }
  278. elseif(isset($field['alias'])) {
  279. $query['query'] .= '`' . $name . '` AS `' . $field['alias'] . '`';
  280. }
  281. else {
  282. $query['query'] .= '`' . $name . '`';
  283. }
  284. ++$current;
  285. if($current < $count) {
  286. $query['query'] .= ', ';
  287. }
  288. }
  289. $query['query'] .= ' FROM `' . $this->m_storageName . '`';
  290. return $this;
  291. }
  292. /**
  293. * Returns table alias (if exists)
  294. **/
  295. private function FieldAlias(&$field, $name) {
  296. if(isset($field['alias'])) {
  297. return $field['alias'];
  298. }
  299. return $name;
  300. }
  301. /**
  302. * Joins one or more storages into one.
  303. * Usage:
  304. * $ach = new AchievementStorage();
  305. * $ach->FindEntry(6)->Join('CharacterAchievementStorage', 6, 'achievement');
  306. **/
  307. public function Join($storage_name, $storage_entry, $storage_index = '') {
  308. $storage = new $storage_name();
  309. if(!$storage) {
  310. WoW_Log::WriteError('%s : storage %s was not found, unable to perform joining!', __METHOD__, $storage_name);
  311. return false;
  312. }
  313. if($storage_index != '') {
  314. $storage->SetSearchOptions(array($storage_index => $storage_entry))->FindEntry();
  315. }
  316. else {
  317. $storage->FindEntry($storage_entry);
  318. }
  319. $db_data = $storage->GetData();
  320. $data = array();
  321. $i = 0;
  322. if(is_array($db_data)) {
  323. foreach($db_data as $field => $value) {
  324. if(is_array($value)) {
  325. foreach($value as $key => $val) {
  326. $data[$i][$key] = $val;
  327. }
  328. ++$i;
  329. }
  330. else {
  331. $data[$field][$value];
  332. }
  333. }
  334. }
  335. $tmp = array();
  336. foreach($data as $index => $value) {
  337. if(is_Array($value)) {
  338. $tmp = array();
  339. foreach($value as $key => $val) {
  340. $tmp[$key] = $val;
  341. }
  342. $this->m_data[] = $tmp;
  343. }
  344. else {
  345. if(isset($this->m_data[$index])) {
  346. $index .= '_' . $storage_name;
  347. }
  348. $this->m_data[$index] = $value;
  349. }
  350. }
  351. return $this;
  352. }
  353. }
  354. ?>