PageRenderTime 57ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/classes/bors/storage/dbal.php

https://bitbucket.org/Balancer/bors-core
PHP | 453 lines | 353 code | 85 blank | 15 comment | 35 complexity | e02b2027ae9c4c1b644fbbcea5904279 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-3.0
  1. <?php
  2. /**
  3. Бэкенд, использующий для инициализации объектов Doctrine DBAL
  4. */
  5. driver_dbal::register();
  6. class bors_storage_dbal extends bors_storage implements Iterator
  7. {
  8. function load($object)
  9. {
  10. $select = array();
  11. $post_functions = array();
  12. foreach(bors_lib_orm::main_fields($object) as $f)
  13. {
  14. $x = $f['name'];
  15. if($f['name'] != $f['property'])
  16. $x .= " AS `{$f['property']}`";
  17. $select[] = $x;
  18. if(!empty($f['post_function']))
  19. $post_functions[$f['property']] = $f['post_function'];
  20. }
  21. $where = array('`'.$object->id_field().'`=' => $object->id());
  22. $dummy = array();
  23. self::__join('inner', $object, $select, $where, $post_functions, $dummy);
  24. self::__join('left', $object, $select, $where, $post_functions, $dummy);
  25. $dbh = new driver_dbal($object->db_name());
  26. $data = $dbh->select($object->table_name(), join(',', $select), $where);
  27. if(!$data)
  28. return $object->set_is_loaded(false);
  29. $object->data = $data;
  30. if(!empty($post_functions))
  31. self::post_functions_do($object, $post_functions);
  32. $object->set_is_loaded(true);
  33. // print_d($data);
  34. return true;
  35. }
  36. function load_array($object, $where)
  37. {
  38. if(is_null($object))
  39. {
  40. $db_name = $where['*db'];
  41. $table_name = $where['*table'];
  42. unset($where['*db'], $where['*table']);
  43. $select = array('*');
  44. $class_name = 'base_object_db';
  45. $object = new base_object_db(NULL);
  46. }
  47. else
  48. {
  49. $db_name = $object->db_name();
  50. $table_name = $object->table_name();
  51. $class_name = $object->class_name();
  52. list($select, $where) = self::__query_data_prepare($object, $where);
  53. }
  54. $dbh = new driver_dbal($db_name);
  55. $datas = $dbh->select_array($table_name, join(',', $select), $where, $class_name);
  56. $objects = array();
  57. foreach($datas as $data)
  58. {
  59. $object->set_id($data['id']);
  60. $object->data = $data;
  61. $object->set_is_loaded(true);
  62. $objects[] = $object;
  63. $object = new $class_name(NULL);
  64. }
  65. return $objects;
  66. }
  67. function count($object, $where)
  68. {
  69. if(is_null($object))
  70. {
  71. $db_name = $where['*db'];
  72. $table_name = $where['*table'];
  73. unset($where['*db'], $where['*table']);
  74. $select = array('*');
  75. $class_name = 'base_object_db';
  76. $object = new base_object_db(NULL);
  77. }
  78. else
  79. {
  80. $db_name = $object->db_name();
  81. $table_name = $object->table_name();
  82. $class_name = $object->class_name();
  83. list($select, $where) = self::__query_data_prepare($object, $where);
  84. }
  85. $dbh = new driver_dbal($db_name);
  86. $count = $dbh->select($table_name, 'COUNT(*)', $where, $class_name);
  87. if(!empty($where['group']))
  88. $count = intval($dbh->get('SELECT FOUND_ROWS()'));
  89. return $count;
  90. }
  91. static private function __query_data_prepare($object, $where)
  92. {
  93. $select = array();
  94. $post_functions = array();
  95. foreach(bors_lib_orm::main_fields($object) as $f)
  96. {
  97. $x = $f['name'];
  98. if($f['name'] != $f['property'])
  99. {
  100. $x .= " AS `{$f['property']}`";
  101. if(array_key_exists($f['property'], $where))
  102. {
  103. $where[$f['name']] = $where[$f['property']];
  104. unset($where[$f['property']]);
  105. }
  106. }
  107. $select[] = $x;
  108. if(!empty($f['post_function']))
  109. $post_functions[$f['property']] = $f['post_function'];
  110. }
  111. $dummy = array();
  112. self::__join('inner', $object, $select, $where, $post_functions, $dummy);
  113. self::__join('left', $object, $select, $where, $post_functions, $dummy);
  114. return array($select, $where, $post_functions);
  115. }
  116. static private function __update_data_prepare($object, $where)
  117. {
  118. $_back_functions = array(
  119. 'html_entity_decode' => 'htmlspecialchars',
  120. 'bors_entity_decode' => 'htmlspecialchars',
  121. 'UNIX_TIMESTAMP' => 'FROM_UNIXTIME',
  122. 'aviaport_old_denormalize' => 'aviaport_old_normalize',
  123. 'stripslashes' => 'addslashes',
  124. );
  125. $update = array();
  126. $db_name = $object->db_name();
  127. $table_name = $object->table_name();
  128. foreach(bors_lib_orm::main_fields($object) as $f)
  129. {
  130. // echo "{$f['property']} => {$f['name']}: ".$object->get($f['property'])."<br/>\n";
  131. $x = $f['name'];
  132. // Сюда сунуть обратное преобразование
  133. // if(!empty($f['post_function']))
  134. // $post_functions[$f['property']] = $f['post_function'];
  135. if(preg_match('/^(\w+)\(([\w`]+)\)$/', $f['name'], $m))
  136. {
  137. $f['name'] = $m[2];
  138. $sql = $_back_functions[$m[1]];
  139. }
  140. else
  141. $sql = false;
  142. if(array_key_exists($f['property'], $object->changed_fields))
  143. {
  144. if($sql)
  145. $update[$db_name][$table_name][$f['name']] = $sql.'('.$object->get($f['property']).')';
  146. else
  147. $update[$db_name][$table_name][$f['name']] = $object->get($f['property']);
  148. }
  149. }
  150. $select = array(); // dummy
  151. self::__join('inner', $object, $select, $where, $post_functions, $update);
  152. self::__join('left', $object, $select, $where, $post_functions, $update);
  153. if(empty($update[$db_name][$table_name][$object->id_field()]))
  154. $update[$db_name][$table_name][$object->id_field()] = $object->id();
  155. return array($update, $where);
  156. }
  157. function save($object)
  158. {
  159. $where = array($object->id_field() => $object->id());
  160. list($update, $where) = self::__update_data_prepare($object, $where);
  161. $update_plain = array();
  162. foreach($update as $db_name => $tables)
  163. foreach($tables as $table_name => $fields)
  164. {
  165. unset($fields['*id_field']);
  166. $update_plain = array_merge($update_plain, $fields);
  167. }
  168. if(!$update_plain)
  169. return;
  170. $dbh = new driver_dbal($object->db_name());
  171. $dbh->update($object->table_name(), $where, $update_plain);
  172. }
  173. private $data;
  174. private $dbi;
  175. private $object;
  176. private $__class_name;
  177. static function each($class_name, $where)
  178. {
  179. $object = new $class_name(NULL);
  180. list($select, $where) = self::__query_data_prepare($object, $where);
  181. $db_name = $object->db_name();
  182. $table_name = $object->table_name();
  183. $iterator = new bors_storage_dbal();
  184. $iterator->object = $object;
  185. $iterator->__class_name = $class_name;
  186. $iterator->dbi = driver_dbal::factory($db_name)->each($table_name, join(',', $select), $where);
  187. return $iterator;
  188. }
  189. public function key() { } // Not implemented
  190. public function current() { return $this->object; }
  191. public function next()
  192. {
  193. $this->data = $this->dbi->next();
  194. return $this->__init_object();
  195. }
  196. public function rewind()
  197. {
  198. $this->data = $this->dbi->rewind();
  199. return $this->__init_object();
  200. }
  201. public function valid() { return $this->data != false; }
  202. private function __init_object()
  203. {
  204. $data = $this->data;
  205. $class_name = $this->__class_name;
  206. $object = new $class_name($data['id']);
  207. // $object->set_id($data['id']);
  208. $object->data = $data;
  209. $object->set_is_loaded(true);
  210. return $this->object = $object;
  211. }
  212. static private function __join($type, $object, &$select, &$where, &$post_functions, &$update)
  213. {
  214. $where['*class_name'] = $object->class_name();
  215. $main_db = $object->db_name();
  216. $main_table = $object->table_name();
  217. $main_id_field = $object->id_field();
  218. $join = $object->get("{$type}_join_fields");
  219. if($join)
  220. {
  221. foreach($join as $db_name => $tables)
  222. {
  223. foreach($tables as $table_name => $fields)
  224. {
  225. if(!preg_match('/^(\w+)\((\w+)\)$/', $table_name, $m))
  226. throw new Exception('Unknown field format '.$table_name.' for class '.$object->class_name());
  227. $id_field = $m[2];
  228. $table_name = $m[1];
  229. $t = '';
  230. if($db_name != $main_db)
  231. $t = "`$db_name`.";
  232. $t .= "`$table_name`";
  233. $j = "$t ON `$main_table`.`$main_id_field` = $t.`$id_field`";
  234. $where[$type.'_join'][] = $j;
  235. $update[$db_name][$table_name]['*id_field'] = $id_field;
  236. foreach($fields as $property => $field)
  237. {
  238. $field = bors_lib_orm::field($property, $field);
  239. $x = "$t.`{$field['name']}`";//FIXME: предусмотреть возможность подключать FUNC(`field`)
  240. if($field['name'] != $field['property'])
  241. $x .= " AS `{$field['property']}`";
  242. $select[] = $x;
  243. if(!empty($field['post_function']))
  244. $post_functions[$field['property']] = $field['post_function'];
  245. // echo "{$field['property']} => {$field['name']}: ".$object->get($field['property'])."<br/>\n";
  246. if(!empty($object->changed_fields) && array_key_exists($field['property'], $object->changed_fields))
  247. $update[$db_name][$table_name][$field['name']] = $object->get($field['property']);
  248. }
  249. }
  250. }
  251. }
  252. }
  253. function create($object)
  254. {
  255. $where = array();
  256. list($data, $where) = self::__update_data_prepare($object, $where);
  257. if(!$data)
  258. return;
  259. $main_table = true;
  260. foreach($data as $db_name => $tables)
  261. {
  262. $dbh = new driver_dbal($db_name);
  263. foreach($tables as $table_name => $fields)
  264. {
  265. if($main_table)
  266. {
  267. unset($fields[$object->id_field()]);
  268. }
  269. else
  270. {
  271. $id_field = $fields['*id_field'];
  272. unset($fields['*id_field']);
  273. $fields[$id_field] = $new_id;
  274. }
  275. bors_debug::syslog("inserts", "insert $table_name, ".print_r($fields, true));
  276. $dbh->insert($table_name, $fields);
  277. if($main_table)
  278. {
  279. $main_table = false;
  280. $new_id = $dbh->last_id();
  281. }
  282. }
  283. }
  284. $object->set_id($new_id);
  285. // echo "New id=$new_id, {$object->id()}<br/>";
  286. // exit();
  287. }
  288. function delete($object)
  289. {
  290. $object->on_delete();
  291. $update = array();
  292. $where = array();
  293. $select = array();
  294. $post_functions = array();
  295. self::__join('inner', $object, $select, $where, $post_functions, $update);
  296. self::__join('left', $object, $select, $where, $post_functions, $update);
  297. foreach($update as $db_name => $tables)
  298. {
  299. $dbh = new driver_dbal($db_name);
  300. foreach($tables as $table_name => $fields)
  301. $dbh->delete($table_name, array($fields['*id_field'] => $object->id()));
  302. }
  303. $dbh = new driver_dbal($object->db_name());
  304. $dbh->delete($object->table_name(), array($object->id_field() => $object->id()));
  305. }
  306. static function create_table($class_name)
  307. {
  308. $class = new $class_name(NULL);
  309. $map = array(
  310. 'string' => 'string',
  311. 'text' => 'text',
  312. 'int' => 'integer',
  313. 'uint' => array('integer', array('unsigned' => true)),
  314. 'bool' => 'boolean',
  315. 'float' => 'decimal',
  316. );
  317. $db_name = $class->db_name();
  318. $table_name = $class->table_name();
  319. $fields = $class->table_fields();
  320. $schema = new \Doctrine\DBAL\Schema\Schema();
  321. $table = $schema->createTable($table_name);
  322. $object_properties = bors_lib_orm::main_fields($class);
  323. $id_field = NULL;
  324. foreach($object_properties as $field)
  325. {
  326. $type = $map[$field['type']];
  327. $args = array();
  328. if($field['property'] == 'id')
  329. {
  330. $id_field = $field['name'];
  331. $args['autoincrement'] = true;
  332. }
  333. if(is_array($type))
  334. $table->addColumn($field['name'], $type[0], array_merge($type[1], $args));
  335. else
  336. $table->addColumn($field['name'], $type, $args);
  337. //$table->addColumn("username", "string", array("length" => 32));
  338. //$table->addUniqueIndex(array("username"));
  339. }
  340. $table->setPrimaryKey(array($id_field));
  341. $db = new driver_dbal($db_name, true);
  342. $queries = $schema->toSql($db->connection()->getDatabasePlatform());
  343. try
  344. {
  345. foreach($queries as $query)
  346. $db->query($query);
  347. }
  348. catch(Exception $e) { }
  349. $db->close();
  350. }
  351. static function drop_table($class_name)
  352. {
  353. if(!config('can-drop-tables'))
  354. return bors_throw(ec('Удаление таблиц запрещено'));
  355. $class = new $class_name(NULL);
  356. foreach($class->fields() as $db_name => $tables)
  357. {
  358. $db = new driver_dbal($db_name);
  359. foreach($tables as $table_name => $fields)
  360. {
  361. if(preg_match('/^(\w+)\((\w+)\)$/', $table_name, $m))
  362. $table_name = $m[1];
  363. $db->query("DROP TABLE IF EXISTS $table_name");
  364. // $db->close();
  365. }
  366. }
  367. }
  368. }