PageRenderTime 71ms CodeModel.GetById 42ms RepoModel.GetById 0ms app.codeStats 0ms

/admin/xmldb/actions/edit_key_save/edit_key_save.class.php

https://github.com/kpike/moodle
PHP | 306 lines | 202 code | 29 blank | 75 comment | 60 complexity | 29aedbf549eb4c53523c7c1faeb215b8 MD5 | raw file
  1. <?php
  2. // This file is part of Moodle - http://moodle.org/
  3. //
  4. // Moodle is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Moodle is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * @package xmldb-editor
  18. * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  19. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  20. */
  21. /**
  22. * This class verifies all the data introduced when editing a key for correctness,
  23. * performing changes / displaying errors depending of the results.
  24. *
  25. * @package xmldb-editor
  26. * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  27. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  28. */
  29. class edit_key_save extends XMLDBAction {
  30. /**
  31. * Init method, every subclass will have its own
  32. */
  33. function init() {
  34. parent::init();
  35. /// Set own custom attributes
  36. /// Get needed strings
  37. $this->loadStrings(array(
  38. 'keynameempty' => 'xmldb',
  39. 'incorrectkeyname' => 'xmldb',
  40. 'duplicatekeyname' => 'xmldb',
  41. 'nofieldsspecified' => 'xmldb',
  42. 'duplicatefieldsused' => 'xmldb',
  43. 'fieldsnotintable' => 'xmldb',
  44. 'fieldsusedinkey' => 'xmldb',
  45. 'fieldsusedinindex' => 'xmldb',
  46. 'noreftablespecified' => 'xmldb',
  47. 'wrongnumberofreffields' => 'xmldb',
  48. 'noreffieldsspecified' => 'xmldb',
  49. 'nomasterprimaryuniquefound' => 'xmldb',
  50. 'masterprimaryuniqueordernomatch' => 'xmldb',
  51. 'primarykeyonlyallownotnullfields' => 'xmldb',
  52. 'back' => 'xmldb',
  53. 'administration' => ''
  54. ));
  55. }
  56. /**
  57. * Invoke method, every class will have its own
  58. * returns true/false on completion, setting both
  59. * errormsg and output as necessary
  60. */
  61. function invoke() {
  62. parent::invoke();
  63. $result = true;
  64. /// Set own core attributes
  65. //$this->does_generate = ACTION_NONE;
  66. $this->does_generate = ACTION_GENERATE_HTML;
  67. /// These are always here
  68. global $CFG, $XMLDB;
  69. /// Do the job, setting result as needed
  70. if (!data_submitted()) { ///Basic prevention
  71. print_error('wrongcall', 'error');
  72. }
  73. /// Get parameters
  74. $dirpath = required_param('dir', PARAM_PATH);
  75. $dirpath = $CFG->dirroot . $dirpath;
  76. $tableparam = strtolower(required_param('table', PARAM_PATH));
  77. $keyparam = strtolower(required_param('key', PARAM_PATH));
  78. $name = trim(strtolower(optional_param('name', $keyparam, PARAM_PATH)));
  79. $comment = required_param('comment', PARAM_CLEAN);
  80. $comment = trim($comment);
  81. $type = required_param('type', PARAM_INT);
  82. $fields = required_param('fields', PARAM_CLEAN);
  83. $fields = str_replace(' ', '', trim(strtolower($fields)));
  84. if ($type == XMLDB_KEY_FOREIGN ||
  85. $type == XMLDB_KEY_FOREIGN_UNIQUE) {
  86. $reftable = trim(strtolower(required_param('reftable', PARAM_PATH)));
  87. $reffields= required_param('reffields', PARAM_CLEAN);
  88. $reffields = str_replace(' ', '', trim(strtolower($reffields)));
  89. }
  90. $editeddir =& $XMLDB->editeddirs[$dirpath];
  91. $structure =& $editeddir->xml_file->getStructure();
  92. $table =& $structure->getTable($tableparam);
  93. $key =& $table->getKey($keyparam);
  94. $oldhash = $key->getHash();
  95. $errors = array(); /// To store all the errors found
  96. /// Perform some checks
  97. /// Check empty name
  98. if (empty($name)) {
  99. $errors[] = $this->str['keynameempty'];
  100. }
  101. /// Check incorrect name
  102. if ($name == 'changeme') {
  103. $errors[] = $this->str['incorrectkeyname'];
  104. }
  105. /// Check duplicate name
  106. if ($keyparam != $name && $table->getKey($name)) {
  107. $errors[] = $this->str['duplicatekeyname'];
  108. }
  109. $fieldsarr = explode(',', $fields);
  110. /// Check the fields isn't empty
  111. if (empty($fieldsarr[0])) {
  112. $errors[] = $this->str['nofieldsspecified'];
  113. } else {
  114. /// Check that there aren't duplicate column names
  115. $uniquearr = array_unique($fieldsarr);
  116. if (count($fieldsarr) != count($uniquearr)) {
  117. $errors[] = $this->str['duplicatefieldsused'];
  118. }
  119. /// Check that all the fields in belong to the table
  120. foreach ($fieldsarr as $field) {
  121. if (!$table->getField($field)) {
  122. $errors[] = $this->str['fieldsnotintable'];
  123. break;
  124. }
  125. }
  126. /// If primary, check that all the fields are not null
  127. if ($type == XMLDB_KEY_PRIMARY) {
  128. foreach ($fieldsarr as $field) {
  129. if ($fi = $table->getField($field)) {
  130. if (!$fi->getNotNull()) {
  131. $errors[] = $this->str['primarykeyonlyallownotnullfields'];
  132. break;
  133. }
  134. }
  135. }
  136. }
  137. /// Check that there isn't any key using exactly the same fields
  138. $tablekeys = $table->getKeys();
  139. if ($tablekeys) {
  140. foreach ($tablekeys as $tablekey) {
  141. /// Skip checking against itself
  142. if ($keyparam == $tablekey->getName()) {
  143. continue;
  144. }
  145. $keyfieldsarr = $tablekey->getFields();
  146. /// Compare both arrays, looking for diferences
  147. $diferences = array_merge(array_diff($fieldsarr, $keyfieldsarr), array_diff($keyfieldsarr, $fieldsarr));
  148. if (empty($diferences)) {
  149. $errors[] = $this->str['fieldsusedinkey'];
  150. break;
  151. }
  152. }
  153. }
  154. /// Check that there isn't any index using exactlt the same fields
  155. $tableindexes = $table->getIndexes();
  156. if ($tableindexes) {
  157. foreach ($tableindexes as $tableindex) {
  158. $indexfieldsarr = $tableindex->getFields();
  159. /// Compare both arrays, looking for diferences
  160. $diferences = array_merge(array_diff($fieldsarr, $indexfieldsarr), array_diff($indexfieldsarr, $fieldsarr));
  161. if (empty($diferences)) {
  162. $errors[] = $this->str['fieldsusedinindex'];
  163. break;
  164. }
  165. }
  166. }
  167. /// If foreign key
  168. if ($type == XMLDB_KEY_FOREIGN ||
  169. $type == XMLDB_KEY_FOREIGN_UNIQUE) {
  170. $reffieldsarr = explode(',', $reffields);
  171. /// Check reftable is not empty
  172. if (empty($reftable)) {
  173. $errors[] = $this->str['noreftablespecified'];
  174. } else
  175. /// Check reffields are not empty
  176. if (empty($reffieldsarr[0])) {
  177. $errors[] = $this->str['noreffieldsspecified'];
  178. } else
  179. /// Check the number of fields is correct
  180. if (count($fieldsarr) != count($reffieldsarr)) {
  181. $errors[] = $this->str['wrongnumberofreffields'];
  182. } else {
  183. /// Check, if pointing to one structure table, that there is one master key for this key
  184. if ($rt = $structure->getTable($reftable)) {
  185. $masterfound = false;
  186. $reftablekeys = $rt->getKeys();
  187. if ($reftablekeys) {
  188. foreach ($reftablekeys as $reftablekey) {
  189. /// Only compare with primary and unique keys
  190. if ($reftablekey->getType() != XMLDB_KEY_PRIMARY && $reftablekey->getType() != XMLDB_KEY_UNIQUE) {
  191. continue;
  192. }
  193. $keyfieldsarr = $reftablekey->getFields();
  194. /// Compare both arrays, looking for diferences
  195. $diferences = array_merge(array_diff($reffieldsarr, $keyfieldsarr), array_diff($keyfieldsarr, $reffieldsarr));
  196. if (empty($diferences)) {
  197. $masterfound = true;
  198. break;
  199. }
  200. }
  201. if (!$masterfound) {
  202. $errors[] = $this->str['nomasterprimaryuniquefound'];
  203. } else {
  204. /// Quick test of the order
  205. if (implode(',', $reffieldsarr) != implode(',', $keyfieldsarr)) {
  206. $errors[] = $this->str['masterprimaryuniqueordernomatch'];
  207. }
  208. }
  209. }
  210. }
  211. }
  212. }
  213. }
  214. if (!empty($errors)) {
  215. $tempkey = new xmldb_key($name);
  216. $tempkey->setType($type);
  217. $tempkey->setFields($fieldsarr);
  218. if ($type == XMLDB_KEY_FOREIGN ||
  219. $type == XMLDB_KEY_FOREIGN_UNIQUE) {
  220. $tempkey->setRefTable($reftable);
  221. $tempkey->setRefFields($reffieldsarr);
  222. }
  223. /// Prepare the output
  224. $o = '<p>' .implode(', ', $errors) . '</p>
  225. <p>' . $name . ': ' . $tempkey->readableInfo() . '</p>';
  226. $o.= '<a href="index.php?action=edit_key&amp;key=' .$key->getName() . '&amp;table=' . $table->getName() .
  227. '&amp;dir=' . urlencode(str_replace($CFG->dirroot, '', $dirpath)) . '">[' . $this->str['back'] . ']</a>';
  228. $this->output = $o;
  229. }
  230. /// Continue if we aren't under errors
  231. if (empty($errors)) {
  232. /// If there is one name change, do it, changing the prev and next
  233. /// atributes of the adjacent fields
  234. if ($keyparam != $name) {
  235. $key->setName($name);
  236. if ($key->getPrevious()) {
  237. $prev =& $table->getKey($key->getPrevious());
  238. $prev->setNext($name);
  239. $prev->setChanged(true);
  240. }
  241. if ($key->getNext()) {
  242. $next =& $table->getKey($key->getNext());
  243. $next->setPrevious($name);
  244. $next->setChanged(true);
  245. }
  246. }
  247. /// Set comment
  248. $key->setComment($comment);
  249. /// Set the rest of fields
  250. $key->setType($type);
  251. $key->setFields($fieldsarr);
  252. if ($type == XMLDB_KEY_FOREIGN ||
  253. $type == XMLDB_KEY_FOREIGN_UNIQUE) {
  254. $key->setRefTable($reftable);
  255. $key->setRefFields($reffieldsarr);
  256. }
  257. /// If the hash has changed from the old one, change the version
  258. /// and mark the structure as changed
  259. $key->calculateHash(true);
  260. if ($oldhash != $key->getHash()) {
  261. $key->setChanged(true);
  262. $table->setChanged(true);
  263. /// Recalculate the structure hash
  264. $structure->calculateHash(true);
  265. $structure->setVersion(userdate(time(), '%Y%m%d', 99, false));
  266. /// Mark as changed
  267. $structure->setChanged(true);
  268. }
  269. /// Launch postaction if exists (leave this here!)
  270. if ($this->getPostAction() && $result) {
  271. return $this->launch($this->getPostAction());
  272. }
  273. }
  274. /// Return ok if arrived here
  275. return $result;
  276. }
  277. }