schema.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  1. <?php
  2. /*
  3. FusionPBX
  4. Version: MPL 1.1
  5. The contents of this file are subject to the Mozilla Public License Version
  6. 1.1 (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.mozilla.org/MPL/
  9. Software distributed under the License is distributed on an "AS IS" basis,
  10. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. for the specific language governing rights and limitations under the
  12. License.
  13. The Original Code is FusionPBX
  14. The Initial Developer of the Original Code is
  15. Mark J Crane <[email protected]>
  16. Copyright (C) 2013 - 2019
  17. All Rights Reserved.
  18. Contributor(s):
  19. Mark J Crane <[email protected]>
  20. */
  21. //define the schema class
  22. if (!class_exists('schema')) {
  23. class schema {
  24. //define variables
  25. private $db;
  26. public $apps;
  27. public $db_type;
  28. public $result;
  29. public $data_types;
  30. //class constructor
  31. public function __construct() {
  32. //connect to the database
  33. require_once "resources/classes/database.php";
  34. $database = new database;
  35. $database->connect();
  36. $this->db = $database->db;
  37. //includes files
  38. require_once dirname(__DIR__, 2) . "/resources/require.php";
  39. //get the list of installed apps from the core and mod directories
  40. $config_list = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/*/*/app_config.php");
  41. $x=0;
  42. foreach ($config_list as &$config_path) {
  43. try {
  44. include($config_path);
  45. }
  46. catch (Exception $e) {
  47. //echo 'Caught exception: ', $e->getMessage(), "\n";
  48. }
  49. $x++;
  50. }
  51. $this->apps = $apps;
  52. }
  53. //create the database schema
  54. public function sql() {
  55. $sql = '';
  56. $sql_schema = '';
  57. foreach ($this->apps as $app) {
  58. if (isset($app['db']) && count($app['db'])) {
  59. foreach ($app['db'] as $row) {
  60. //create the sql string
  61. $table_name = $row['table']['name'];
  62. $sql = "CREATE TABLE " . $row['table']['name'] . " (\n";
  63. $field_count = 0;
  64. foreach ($row['fields'] as $field) {
  65. if (!empty($field['deprecated']) and ($field['deprecated'] == "true")) {
  66. //skip this field
  67. }
  68. else {
  69. if ($field_count > 0 ) { $sql .= ",\n"; }
  70. if (is_array($field['name'])) {
  71. $sql .= $field['name']['text']." ";
  72. }
  73. else {
  74. $sql .= $field['name']." ";
  75. }
  76. if (is_array($field['type'])) {
  77. $sql .= $field['type'][$this->db_type];
  78. }
  79. else {
  80. $sql .= $field['type'];
  81. }
  82. if (isset($field['key']) && isset($field['key']['type']) && ($field['key']['type'] == "primary")) {
  83. $sql .= " PRIMARY KEY";
  84. }
  85. if (isset($field['key']) && isset($field['key']['type']) && ($field['key']['type'] == "foreign")) {
  86. if ($this->db_type == "pgsql") {
  87. //$sql .= " references ".$field['key']['reference']['table']."(".$field['key']['reference']['field'].")";
  88. }
  89. if ($this->db_type == "sqlite") {
  90. //$sql .= " references ".$field['key']['reference']['table']."(".$field['key']['reference']['field'].")";
  91. }
  92. if ($this->db_type == "mysql") {
  93. //$sql .= " references ".$field['key']['reference']['table']."(".$field['key']['reference']['field'].")";
  94. }
  95. }
  96. $field_count++;
  97. }
  98. }
  99. if ($this->db_type == "mysql") {
  100. $sql .= ") ENGINE=INNODB;";
  101. }
  102. else {
  103. $sql .= ");";
  104. }
  105. $this->result['sql'][] = $sql;
  106. unset($sql);
  107. }
  108. }
  109. }
  110. }
  111. //create the database schema
  112. public function exec() {
  113. foreach ($this->result['sql'] as $sql) {
  114. //start the sql transaction
  115. $this->db->beginTransaction();
  116. //execute the sql query
  117. try {
  118. $this->db->query($sql);
  119. }
  120. catch (PDOException $error) {
  121. echo "error: " . $error->getMessage() . " sql: $sql<br/>";
  122. }
  123. //complete the transaction
  124. $this->db->commit();
  125. }
  126. }
  127. //check if a column exists in sqlite
  128. private function sqlite_column_exists($table_info, $column_name) {
  129. foreach ($table_info as $key => &$row) {
  130. if ($row['name'] == $column_name) {
  131. return true;
  132. }
  133. }
  134. return $false;
  135. }
  136. //check if a column exists
  137. public function column_exists ($db_name, $table_name, $column_name) {
  138. if ($this->db_type == "sqlite") {
  139. $table_info = $this->table_info($db_name, $table_name);
  140. if ($this->sqlite_column_exists($table_info, $column_name)) {
  141. return true;
  142. }
  143. else {
  144. return false;
  145. }
  146. }
  147. if ($this->db_type == "pgsql") {
  148. $sql = "SELECT attname FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = '$table_name' limit 1) AND attname = '$column_name'; ";
  149. }
  150. if ($this->db_type == "mysql") {
  151. //$sql .= "SELECT * FROM information_schema.COLUMNS where TABLE_SCHEMA = '$db_name' and TABLE_NAME = '$table_name' and COLUMN_NAME = '$column_name' ";
  152. $sql = "show columns from $table_name where field = '$column_name' ";
  153. }
  154. if ($sql) {
  155. $prep_statement = $this->db->prepare($sql);
  156. $prep_statement->execute();
  157. $result = $prep_statement->fetchAll(PDO::FETCH_NAMED);
  158. if (!$result) {
  159. return false;
  160. }
  161. if (count($result) > 0) {
  162. return true;
  163. }
  164. else {
  165. return false;
  166. }
  167. unset ($prep_statement);
  168. }
  169. }
  170. //get the table information
  171. public function table_info($db_name, $table_name) {
  172. if (empty($table_name)) { return false; }
  173. if ($this->db_type == "sqlite") {
  174. $sql = "PRAGMA table_info(".$table_name.");";
  175. }
  176. if ($this->db_type == "pgsql") {
  177. $sql = "SELECT ordinal_position, ";
  178. $sql .= "column_name, ";
  179. $sql .= "data_type, ";
  180. $sql .= "column_default, ";
  181. $sql .= "is_nullable, ";
  182. $sql .= "character_maximum_length, ";
  183. $sql .= "numeric_precision ";
  184. $sql .= "FROM information_schema.columns ";
  185. $sql .= "WHERE table_name = '".$table_name."' ";
  186. $sql .= "and table_catalog = '".$db_name."' ";
  187. $sql .= "ORDER BY ordinal_position; ";
  188. }
  189. if ($this->db_type == "mysql") {
  190. $sql = "describe ".$table_name.";";
  191. }
  192. $prep_statement = $this->db->prepare($sql);
  193. $prep_statement->execute();
  194. return $prep_statement->fetchAll(PDO::FETCH_ASSOC);
  195. }
  196. //database table exists alternate
  197. private function db_table_exists_alternate ($db_type, $table_name) {
  198. $sql = "select count(*) from $table_name ";
  199. $result = $this->db->query($sql);
  200. if ($result > 0) {
  201. return true; //table exists
  202. }
  203. else {
  204. return false; //table doesn't exist
  205. }
  206. }
  207. //database table exists
  208. private function db_table_exists ($db_type, $db_name, $table_name) {
  209. $sql = "";
  210. if ($db_type == "sqlite") {
  211. $sql .= "SELECT * FROM sqlite_master WHERE type='table' and name='$table_name' ";
  212. }
  213. if ($db_type == "pgsql") {
  214. $sql .= "select * from pg_tables where schemaname='public' and tablename = '$table_name' ";
  215. }
  216. if ($db_type == "mysql") {
  217. $sql .= "SELECT TABLE_NAME FROM information_schema.tables WHERE table_schema = '$db_name' and TABLE_NAME = '$table_name' ";
  218. }
  219. $prep_statement = $this->db->prepare(check_sql($sql));
  220. $prep_statement->execute();
  221. $result = $prep_statement->fetchAll(PDO::FETCH_NAMED);
  222. if (count($result) > 0) {
  223. return true; //table exists
  224. }
  225. else {
  226. return false; //table doesn't exist
  227. }
  228. }
  229. //database table information
  230. private function db_table_info($db_name, $db_type, $table_name) {
  231. if (empty($table_name)) { return false; }
  232. if ($db_type == "sqlite") {
  233. $sql = "PRAGMA table_info(".$table_name.");";
  234. }
  235. if ($db_type == "pgsql") {
  236. $sql = "SELECT ordinal_position, ";
  237. $sql .= "column_name, ";
  238. $sql .= "data_type, ";
  239. $sql .= "column_default, ";
  240. $sql .= "is_nullable, ";
  241. $sql .= "character_maximum_length, ";
  242. $sql .= "numeric_precision ";
  243. $sql .= "FROM information_schema.columns ";
  244. $sql .= "WHERE table_name = '".$table_name."' ";
  245. $sql .= "and table_catalog = '".$db_name."' ";
  246. $sql .= "ORDER BY ordinal_position; ";
  247. }
  248. if ($db_type == "mysql") {
  249. $sql = "describe ".$table_name.";";
  250. }
  251. $prep_statement = $this->db->prepare($sql);
  252. $prep_statement->execute();
  253. return $prep_statement->fetchAll(PDO::FETCH_ASSOC);
  254. }
  255. //database type
  256. private function db_data_type($db_type, $table_info, $column_name) {
  257. if ($db_type == "sqlite") {
  258. foreach ($table_info as $key => &$row) {
  259. if ($row['name'] == $column_name) {
  260. return $row['type'];
  261. }
  262. }
  263. }
  264. if ($db_type == "pgsql") {
  265. foreach ($table_info as $key => &$row) {
  266. if ($row['column_name'] == $column_name) {
  267. return $row['data_type'];
  268. }
  269. }
  270. }
  271. if ($db_type == "mysql") {
  272. foreach ($table_info as $key => &$row) {
  273. if ($row['Field'] == $column_name) {
  274. return $row['Type'];
  275. }
  276. }
  277. }
  278. }
  279. //sqlite column exists
  280. private function db_sqlite_column_exists($table_info, $column_name) {
  281. foreach ($table_info as $key => &$row) {
  282. if ($row['name'] == $column_name) {
  283. return true;
  284. }
  285. }
  286. return $false;
  287. }
  288. //database column exists
  289. private function db_column_exists ($db_type, $db_name, $table_name, $column_name) {
  290. if ($db_type == "sqlite") {
  291. $table_info = $this->db_table_info($db_name, $db_type, $table_name);
  292. if ($this->db_sqlite_column_exists($table_info, $column_name)) {
  293. return true;
  294. }
  295. else {
  296. return false;
  297. }
  298. }
  299. if ($db_type == "pgsql") {
  300. $sql = "SELECT attname FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = '$table_name' limit 1) AND attname = '$column_name'; ";
  301. }
  302. if ($db_type == "mysql") {
  303. //$sql .= "SELECT * FROM information_schema.COLUMNS where TABLE_SCHEMA = '$db_name' and TABLE_NAME = '$table_name' and COLUMN_NAME = '$column_name' ";
  304. $sql = "show columns from $table_name where field = '$column_name' ";
  305. }
  306. if ($sql) {
  307. $prep_statement = $this->db->prepare(check_sql($sql));
  308. $prep_statement->execute();
  309. $result = $prep_statement->fetchAll(PDO::FETCH_NAMED);
  310. if (!$result) {
  311. return false;
  312. }
  313. if (count($result) > 0) {
  314. return true;
  315. }
  316. else {
  317. return false;
  318. }
  319. unset ($prep_statement);
  320. }
  321. }
  322. //database column data type
  323. private function db_column_data_type ($db_type, $db_name, $table_name, $column_name) {
  324. $table_info = $this->db_table_info($db_name, $db_type, $table_name);
  325. return $this->db_data_type($db_type, $table_info, $column_name);
  326. }
  327. //database create table
  328. public function db_create_table ($apps, $db_type, $table) {
  329. if (is_array($apps)) foreach ($apps as $x => &$app) {
  330. if (is_array($app['db'])) foreach ($app['db'] as $y => $row) {
  331. if (is_array($row['table']['name'])) {
  332. $table_name = $row['table']['name']['text'];
  333. }
  334. else {
  335. $table_name = $row['table']['name'];
  336. }
  337. if ($table_name == $table) {
  338. $sql = "CREATE TABLE " . $table_name . " (\n";
  339. $field_count = 0;
  340. if (is_array($row['fields'])) foreach ($row['fields'] as $field) {
  341. if (!empty($field['deprecated']) && $field['deprecated'] == "true") {
  342. //skip this row
  343. }
  344. else {
  345. if ($field_count > 0 ) { $sql .= ",\n"; }
  346. if (is_array($field['name'])) {
  347. $sql .= $field['name']['text'] . " ";
  348. }
  349. else {
  350. $sql .= $field['name'] . " ";
  351. }
  352. if (is_array($field['type'])) {
  353. $sql .= $field['type'][$db_type];
  354. }
  355. else {
  356. $sql .= $field['type'];
  357. }
  358. if ($field['key']['type'] == "primary") {
  359. $sql .= " PRIMARY KEY";
  360. }
  361. $field_count++;
  362. }
  363. }
  364. $sql .= ");\n";
  365. return $sql;
  366. }
  367. }
  368. }
  369. }
  370. //database insert
  371. private function db_insert_into ($apps, $db_type, $table) {
  372. global $db_name;
  373. foreach ($apps as $x => &$app) {
  374. foreach ($app['db'] as $y => $row) {
  375. if ($row['table']['name'] == $table) {
  376. $sql = "INSERT INTO " . $row['table']['name'] . " (";
  377. $field_count = 0;
  378. foreach ($row['fields'] as $field) {
  379. if (!empty($field['deprecated']) && $field['deprecated'] == "true") {
  380. //skip this field
  381. }
  382. else {
  383. if ($field_count > 0 ) { $sql .= ","; }
  384. if (is_array($field['name'])) {
  385. $sql .= $field['name']['text'];
  386. }
  387. else {
  388. $sql .= $field['name'];
  389. }
  390. $field_count++;
  391. }
  392. }
  393. $sql .= ")\n";
  394. $sql .= "SELECT ";
  395. $field_count = 0;
  396. foreach ($row['fields'] as $field) {
  397. if (!empty($field['deprecated']) && $field['deprecated'] == "true") {
  398. //skip this field
  399. }
  400. else {
  401. if ($field_count > 0 ) { $sql .= ","; }
  402. if (is_array($field['name'])) {
  403. if ($field['exists'] == "false") {
  404. if (is_array($field['name']['deprecated'])) {
  405. $found = false;
  406. foreach ($field['name']['deprecated'] as $row) {
  407. if ($this->db_column_exists ($db_type, $db_name, 'tmp_'.$table, $row)) {
  408. $sql .= $row;
  409. $found = true;
  410. break;
  411. }
  412. }
  413. if (!$found) { $sql .= "''"; }
  414. }
  415. else {
  416. if ($this->db_column_exists ($db_type, $db_name, 'tmp_'.$table, $field['name']['deprecated'])) {
  417. $sql .= $field['name']['deprecated'];
  418. }
  419. else {
  420. $sql .= "''";
  421. }
  422. }
  423. }
  424. else {
  425. $sql .= $field['name']['text'];
  426. }
  427. }
  428. else {
  429. $sql .= $field['name'];
  430. }
  431. $field_count++;
  432. }
  433. }
  434. $sql .= " FROM tmp_".$table.";\n";
  435. return $sql;
  436. }
  437. }
  438. }
  439. }
  440. //datatase schema
  441. public function schema ($format = '') {
  442. //set the global variable
  443. global $db, $text, $output_format;
  444. if ($format == '') $format = $output_format;
  445. //get the db variables
  446. require_once "resources/classes/config.php";
  447. $config = new config;
  448. $config_exists = $config->exists();
  449. $config_path = $config->find();
  450. $config->get();
  451. $db_type = $config->db_type;
  452. $db_name = $config->db_name;
  453. $db_username = $config->db_username;
  454. $db_password = $config->db_password;
  455. $db_host = $config->db_host;
  456. $db_path = $config->db_path;
  457. $db_port = $config->db_port;
  458. //includes files
  459. require_once dirname(__DIR__, 2) . "/resources/require.php";
  460. //add multi-lingual support
  461. if (!isset($text)) {
  462. $language = new text;
  463. $text = $language->get(null,'core/upgrade');
  464. }
  465. //PHP PDO check if table or column exists
  466. //check if table exists
  467. // SELECT * FROM sqlite_master WHERE type='table' AND name='v_cdr'
  468. //check if column exists
  469. // SELECT * FROM sqlite_master WHERE type='table' AND name='v_cdr' AND sql LIKE '%caller_id_name TEXT,%'
  470. //aditional information
  471. // http://www.sqlite.org/faq.html#q9
  472. //postgresql
  473. //list all tables in the database
  474. // SELECT table_name FROM pg_tables WHERE schemaname='public';
  475. //check if table exists
  476. // SELECT * FROM pg_tables WHERE schemaname='public' AND table_name = 'v_groups'
  477. //check if column exists
  478. // SELECT attname FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = 'v_cdr') AND attname = 'caller_id_name';
  479. //mysql
  480. //list all tables in the database
  481. // SELECT TABLE_NAME FROM information_schema.tables WHERE table_schema = 'fusionpbx'
  482. //check if table exists
  483. // SELECT TABLE_NAME FROM information_schema.tables WHERE table_schema = 'fusionpbx' AND TABLE_NAME = 'v_groups'
  484. //check if column exists
  485. // SELECT * FROM information_schema.COLUMNS where TABLE_SCHEMA = 'fusionpbx' AND TABLE_NAME = 'v_cdr' AND COLUMN_NAME = 'context'
  486. //oracle
  487. //check if table exists
  488. // SELECT TABLE_NAME FROM ALL_TABLES
  489. //get the $apps array from the installed apps from the core and mod directories
  490. $config_list = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/*/*/app_config.php");
  491. $x=0;
  492. foreach ($config_list as &$config_path) {
  493. try {
  494. include($config_path);
  495. }
  496. catch (Exception $e) {
  497. //echo 'Caught exception: ', $e->getMessage(), "\n";
  498. }
  499. $x++;
  500. }
  501. //update the app db array add exists true or false
  502. $sql = '';
  503. foreach ($apps as $x => &$app) {
  504. if (isset($app['db'])) foreach ($app['db'] as $y => &$row) {
  505. if (isset($row['table']['name'])) {
  506. if (is_array($row['table']['name'])) {
  507. $table_name = $row['table']['name']['text'];
  508. }
  509. else {
  510. $table_name = $row['table']['name'];
  511. }
  512. }
  513. else {
  514. //old array syntax
  515. if (is_array($row['table'])) {
  516. $table_name = $row['table']['text'];
  517. }
  518. else {
  519. $table_name = $row['table'];
  520. }
  521. }
  522. if (!empty($table_name)) {
  523. //check if the table exists
  524. if ($this->db_table_exists($db_type, $db_name, $table_name)) {
  525. $apps[$x]['db'][$y]['exists'] = 'true';
  526. }
  527. else {
  528. $apps[$x]['db'][$y]['exists'] = 'false';
  529. }
  530. //check if the column exists
  531. foreach ($row['fields'] as $z => $field) {
  532. if (!empty($field['deprecated']) && $field['deprecated'] == "true") {
  533. //skip this field
  534. }
  535. else {
  536. if (is_array($field['name'])) {
  537. $field_name = $field['name']['text'];
  538. }
  539. else {
  540. $field_name = $field['name'];
  541. }
  542. if (!empty($field_name)) {
  543. if ($this->db_column_exists ($db_type, $db_name, $table_name, $field_name)) {
  544. //found
  545. $apps[$x]['db'][$y]['fields'][$z]['exists'] = 'true';
  546. }
  547. else {
  548. //not found
  549. $apps[$x]['db'][$y]['fields'][$z]['exists'] = 'false';
  550. }
  551. }
  552. unset($field_name);
  553. }
  554. }
  555. unset($table_name);
  556. }
  557. }
  558. }
  559. //prepare the variables
  560. $sql_update = '';
  561. $var_uuid = $_GET["id"] ?? '';
  562. //add missing tables and fields
  563. foreach ($apps as $x => &$app) {
  564. if (isset($app['db'])) foreach ($app['db'] as $y => &$row) {
  565. if (is_array($row['table']['name'])) {
  566. $table_name = $row['table']['name']['text'];
  567. if ($this->db_table_exists($db_type, $db_name, $row['table']['name']['deprecated'])) {
  568. $row['exists'] = "false"; //testing
  569. if ($db_type == "pgsql") {
  570. $sql_update .= "ALTER TABLE ".$row['table']['name']['deprecated']." RENAME TO ".$row['table']['name']['text'].";\n";
  571. }
  572. if ($db_type == "mysql") {
  573. $sql_update .= "RENAME TABLE ".$row['table']['name']['deprecated']." TO ".$row['table']['name']['text'].";\n";
  574. }
  575. if ($db_type == "sqlite") {
  576. $sql_update .= "ALTER TABLE ".$row['table']['name']['deprecated']." RENAME TO ".$row['table']['name']['text'].";\n";
  577. }
  578. }
  579. else {
  580. if ($this->db_table_exists($db_type, $db_name, $row['table']['name']['text'])) {
  581. $row['exists'] = "true";
  582. }
  583. else {
  584. $row['exists'] = "false";
  585. $sql_update .= $this->db_create_table($apps, $db_type, $row['table']['name']['text']);
  586. }
  587. }
  588. }
  589. else {
  590. $table_name = $row['table']['name'];
  591. }
  592. //check if the table exists
  593. if ($row['exists'] == "true") {
  594. if (count($row['fields']) > 0) {
  595. foreach ($row['fields'] as $z => $field) {
  596. if (!empty($field['deprecated']) && $field['deprecated'] == "true") {
  597. //skip this field
  598. }
  599. else {
  600. //get the data type
  601. if (is_array($field['type'])) {
  602. $field_type = $field['type'][$db_type];
  603. }
  604. else {
  605. $field_type = $field['type'];
  606. }
  607. //get the field name
  608. if (is_array($field['name'])) {
  609. $field_name = $field['name']['text'];
  610. if (!$this->db_column_exists ($db_type, $db_name, $table_name, $field_name)) {
  611. $field['exists'] == "false";
  612. }
  613. }
  614. else {
  615. $field_name = $field['name'];
  616. }
  617. //add or rename fields
  618. if (isset($field['name']['deprecated']) && $this->db_column_exists ($db_type, $db_name, $table_name, $field['name']['deprecated'])) {
  619. if ($db_type == "pgsql") {
  620. $sql_update .= "ALTER TABLE ".$table_name." RENAME COLUMN ".$field['name']['deprecated']." to ".$field['name']['text'].";\n";
  621. }
  622. if ($db_type == "mysql") {
  623. $field_type = str_replace("AUTO_INCREMENT PRIMARY KEY", "", $field_type);
  624. $sql_update .= "ALTER TABLE ".$table_name." CHANGE ".$field['name']['deprecated']." ".$field['name']['text']." ".$field_type.";\n";
  625. }
  626. if ($db_type == "sqlite") {
  627. //a change has been made to the field name
  628. $apps[$x]['db'][$y]['rebuild'] = 'true';
  629. }
  630. }
  631. else {
  632. //find missing fields and add them
  633. if ($field['exists'] == "false") {
  634. $sql_update .= "ALTER TABLE ".$table_name." ADD ".$field_name." ".$field_type.";\n";
  635. }
  636. }
  637. //change the data type if it has been changed
  638. //if the data type in the app db array is different than the type in the database then change the data type
  639. if ($this->data_types) {
  640. $db_field_type = $this->db_column_data_type ($db_type, $db_name, $table_name, $field_name);
  641. $field_type_array = explode("(", $field_type);
  642. $field_type = $field_type_array[0];
  643. if (trim($db_field_type) != trim($field_type) && !empty($db_field_type)) {
  644. if ($db_type == "pgsql") {
  645. if (strtolower($field_type) == "uuid") {
  646. $sql_update .= "ALTER TABLE ".$table_name." ALTER COLUMN ".$field_name." TYPE uuid USING\n";
  647. $sql_update .= "CAST(regexp_replace(".$field_name.", '([A-Z0-9]{4})([A-Z0-9]{12})', E'\\1-\\2')\n";
  648. $sql_update .= "AS uuid);\n";
  649. }
  650. else {
  651. //field type has not changed
  652. if ($db_field_type == "integer" && strtolower($field_type) == "serial") { }
  653. else if ($db_field_type == "timestamp without time zone" && strtolower($field_type) == "timestamp") { }
  654. else if ($db_field_type == "timestamp without time zone" && strtolower($field_type) == "datetime") { }
  655. else if ($db_field_type == "timestamp with time zone" && strtolower($field_type) == "timestamptz") { }
  656. else if ($db_field_type == "integer" && strtolower($field_type) == "numeric") { }
  657. else if ($db_field_type == "character" && strtolower($field_type) == "char") { }
  658. //field type has changed
  659. else {
  660. switch ($field_type) {
  661. case 'numeric': $using = $field_name."::numeric"; break;
  662. case 'timestamp':
  663. case 'datetime': $using = $field_name."::timestamp without time zone"; break;
  664. case 'timestamptz': $using = $field_name."::timestamp with time zone"; break;
  665. case 'boolean': $using = $field_name."::boolean"; break;
  666. default: unset($using);
  667. }
  668. $sql_update .= "ALTER TABLE ".$table_name." ALTER COLUMN ".$field_name." TYPE ".$field_type." ".($using ? "USING ".$using : null).";\n";
  669. }
  670. }
  671. }
  672. if ($db_type == "mysql") {
  673. $type = explode("(", $db_field_type);
  674. if ($type[0] == $field_type) {
  675. //do nothing
  676. }
  677. else if ($field_type == "numeric" && $type[0] == "decimal") {
  678. //do nothing
  679. }
  680. else {
  681. $sql_update .= "ALTER TABLE ".$table_name." modify ".$field_name." ".$field_type.";\n";
  682. }
  683. unset($type);
  684. }
  685. if ($db_type == "sqlite") {
  686. //a change has been made to the field type
  687. $apps[$x]['db'][$y]['rebuild'] = 'true';
  688. }
  689. }
  690. }
  691. }
  692. }
  693. unset($column_array);
  694. }
  695. }
  696. else {
  697. //create table
  698. if (!is_array($row['table']['name'])) {
  699. $sql_update .= $this->db_create_table($apps, $db_type, $row['table']['name']);
  700. }
  701. }
  702. }
  703. }
  704. //rebuild and populate the table
  705. foreach ($apps as $x => &$app) {
  706. if (isset($app['db'])) foreach ($app['db'] as $y => &$row) {
  707. if (is_array($row['table']['name'])) {
  708. $table_name = $row['table']['name']['text'];
  709. }
  710. else {
  711. $table_name = $row['table']['name'];
  712. }
  713. if (!empty($field['rebuild']) && $row['rebuild'] == "true") {
  714. if ($db_type == "sqlite") {
  715. //start the transaction
  716. //$sql_update .= "BEGIN TRANSACTION;\n";
  717. //rename the table
  718. $sql_update .= "ALTER TABLE ".$table_name." RENAME TO tmp_".$table_name.";\n";
  719. //create the table
  720. $sql_update .= $this->db_create_table($apps, $db_type, $table_name);
  721. //insert the data into the new table
  722. $sql_update .= $this->db_insert_into($apps, $db_type, $table_name);
  723. //drop the old table
  724. $sql_update .= "DROP TABLE tmp_".$table_name.";\n";
  725. //commit the transaction
  726. //$sql_update .= "COMMIT;\n";
  727. }
  728. }
  729. }
  730. }
  731. // initialize response variable
  732. $response = '';
  733. //display results as html
  734. if ($format == "html") {
  735. //show the database type
  736. $response .= "<strong>".$text['header-database_type'].": ".$db_type. "</strong><br /><br />";
  737. //start the table
  738. $response .= "<table width='100%' border='0' cellpadding='20' cellspacing='0'>\n";
  739. //show the changes
  740. if (!empty($sql_update)) {
  741. $response .= "<tr>\n";
  742. $response .= "<td class='row_style1' colspan='3'>\n";
  743. $response .= "<br />\n";
  744. $response .= "<strong>".$text['label-sql_changes'].":</strong><br />\n";
  745. $response .= "<pre>\n";
  746. $response .= $sql_update;
  747. $response .= "</pre>\n";
  748. $response .= "<br />\n";
  749. $response .= "</td>\n";
  750. $response .= "</tr>\n";
  751. }
  752. //list all tables
  753. $response .= "<tr>\n";
  754. $response .= "<th>".$text['label-table']."</th>\n";
  755. $response .= "<th>".$text['label-exists']."</th>\n";
  756. $response .= "<th>".$text['label-details']."</th>\n";
  757. $response .= "<tr>\n";
  758. //build the html while looping through the app db array
  759. $sql = '';
  760. foreach ($apps as &$app) {
  761. if (isset($app['db'])) foreach ($app['db'] as $row) {
  762. if (is_array($row['table']['name'])) {
  763. $table_name = $row['table']['name']['text'];
  764. }
  765. else {
  766. $table_name = $row['table']['name'];
  767. }
  768. $response .= "<tr>\n";
  769. //check if the table exists
  770. if ($row['exists'] == "true") {
  771. $response .= "<td valign='top' class='row_style1'>".$table_name."</td>\n";
  772. $response .= "<td valign='top' class='vncell' style='padding-top: 3px;'>".$text['option-true']."</td>\n";
  773. if (count($row['fields']) > 0) {
  774. $response .= "<td class='row_style1'>\n";
  775. //show the list of columns
  776. $response .= "<table border='0' cellpadding='10' cellspacing='0'>\n";
  777. $response .= "<tr>\n";
  778. $response .= "<th>".$text['label-name']."</th>\n";
  779. $response .= "<th>".$text['label-type']."</th>\n";
  780. $response .= "<th>".$text['label-exists']."</th>\n";
  781. $response .= "</tr>\n";
  782. foreach ($row['fields'] as $field) {
  783. if (!empty($field['deprecated']) && $field['deprecated'] == "true") {
  784. //skip this field
  785. }
  786. else {
  787. if (is_array($field['name'])) {
  788. $field_name = $field['name']['text'];
  789. }
  790. else {
  791. $field_name = $field['name'];
  792. }
  793. if (is_array($field['type'])) {
  794. $field_type = $field['type'][$db_type];
  795. }
  796. else {
  797. $field_type = $field['type'];
  798. }
  799. $response .= "<tr>\n";
  800. $response .= "<td class='row_style1' width='200'>".$field_name."</td>\n";
  801. $response .= "<td class='row_style1'>".$field_type."</td>\n";
  802. if ($field['exists'] == "true") {
  803. $response .= "<td class='row_style0' style=''>".$text['option-true']."</td>\n";
  804. $response .= "<td>&nbsp;</td>\n";
  805. }
  806. else {
  807. $response .= "<td class='row_style1' style='background-color:#444444;color:#CCCCCC;'>".$text['option-false']."</td>\n";
  808. $response .= "<td>&nbsp;</td>\n";
  809. }
  810. $response .= "</tr>\n";
  811. }
  812. }
  813. unset($column_array);
  814. $response .= " </table>\n";
  815. $response .= "</td>\n";
  816. }
  817. }
  818. else {
  819. $response .= "<td valign='top' class='row_style1'>$table_name</td>\n";
  820. $response .= "<td valign='top' class='row_style1' style='background-color:#444444;color:#CCCCCC;'><strong>".$text['label-exists']."</strong><br />".$text['option-false']."</td>\n";
  821. $response .= "<td valign='top' class='row_style1'>&nbsp;</td>\n";
  822. }
  823. $response .= "</tr>\n";
  824. }
  825. }
  826. unset ($prep_statement);
  827. //end the list of tables
  828. $response .= "</table>\n";
  829. $response .= "<br />\n";
  830. }
  831. //loop line by line through all the lines of sql code
  832. $x = 0;
  833. if (empty($sql_update) && $format == "text") {
  834. $response .= " ".$text['label-schema'].": ".$text['label-no_change']."\n";
  835. }
  836. else {
  837. if ($format == "text") {
  838. $response .= " ".$text['label-schema']."\n";
  839. }
  840. //$this->db->beginTransaction();
  841. $update_array = explode(";", $sql_update);
  842. foreach($update_array as $sql) {
  843. if (strlen(trim($sql))) {
  844. try {
  845. $this->db->query(trim($sql));
  846. if ($format == "text") {
  847. $response .= " $sql;\n";
  848. }
  849. }
  850. catch (PDOException $error) {
  851. $response .= " error: " . $error->getMessage() . " sql: $sql\n";
  852. }
  853. }
  854. }
  855. //$this->db->commit();
  856. $response .= "\n";
  857. unset ($file_contents, $sql_update, $sql);
  858. }
  859. //handle response
  860. //if ($output == "echo") {
  861. // echo $response;
  862. //}
  863. //else if ($output == "return") {
  864. return $response;
  865. //}
  866. } //end function
  867. }
  868. }
  869. //example use
  870. //require_once "resources/classes/schema.php";
  871. //$obj = new schema;
  872. //$obj->db_type = $db_type;
  873. //$obj->schema();
  874. //$result_array = $schema->obj['sql'];
  875. //print_r($result_array);
  876. ?>