3 ///////////////////////////////////////////////////////////////////////////
5 // NOTICE OF COPYRIGHT //
7 // Moodle - Modular Object-Oriented Dynamic Learning Environment //
8 // http://moodle.com //
10 // Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
11 // (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
13 // This program is free software; you can redistribute it and/or modify //
14 // it under the terms of the GNU General Public License as published by //
15 // the Free Software Foundation; either version 2 of the License, or //
16 // (at your option) any later version. //
18 // This program is distributed in the hope that it will be useful, //
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
21 // GNU General Public License for more details: //
23 // http://www.gnu.org/copyleft/gpl.html //
25 ///////////////////////////////////////////////////////////////////////////
27 /// This class will save the changes performed to one key
29 class edit_key_save
extends XMLDBAction
{
32 * Init method, every subclass will have its own
37 /// Set own custom attributes
39 /// Get needed strings
40 $this->loadStrings(array(
41 'keynameempty' => 'xmldb',
42 'incorrectkeyname' => 'xmldb',
43 'duplicatekeyname' => 'xmldb',
44 'nofieldsspecified' => 'xmldb',
45 'duplicatefieldsused' => 'xmldb',
46 'fieldsnotintable' => 'xmldb',
47 'fieldsusedinkey' => 'xmldb',
48 'fieldsusedinindex' => 'xmldb',
49 'noreftablespecified' => 'xmldb',
50 'wrongnumberofreffields' => 'xmldb',
51 'noreffieldsspecified' => 'xmldb',
52 'nomasterprimaryuniquefound' => 'xmldb',
53 'masterprimaryuniqueordernomatch' => 'xmldb',
54 'primarykeyonlyallownotnullfields' => 'xmldb',
55 'administration' => ''
60 * Invoke method, every class will have its own
61 * returns true/false on completion, setting both
62 * errormsg and output as necessary
69 /// Set own core attributes
70 $this->does_generate
= ACTION_NONE
;
71 //$this->does_generate = ACTION_GENERATE_HTML;
73 /// These are always here
76 /// Do the job, setting result as needed
78 if (!data_submitted('nomatch')) { ///Basic prevention
79 error('Wrong action call');
83 $dirpath = required_param('dir', PARAM_PATH
);
84 $dirpath = $CFG->dirroot
. stripslashes_safe($dirpath);
86 $tableparam = strtolower(required_param('table', PARAM_PATH
));
87 $keyparam = strtolower(required_param('key', PARAM_PATH
));
88 $name = trim(strtolower(optional_param('name', $keyparam, PARAM_PATH
)));
90 $comment = required_param('comment', PARAM_CLEAN
);
91 $comment = trim(stripslashes_safe($comment));
93 $type = required_param('type', PARAM_INT
);
94 $fields = required_param('fields', PARAM_CLEAN
);
95 $fields = str_replace(' ', '', trim(strtolower(stripslashes_safe($fields))));
97 if ($type == XMLDB_KEY_FOREIGN ||
98 $type == XMLDB_KEY_FOREIGN_UNIQUE
) {
99 $reftable = trim(strtolower(required_param('reftable', PARAM_PATH
)));
100 $reffields= required_param('reffields', PARAM_CLEAN
);
101 $reffields = str_replace(' ', '', trim(strtolower(stripslashes_safe($reffields))));
104 $editeddir =& $XMLDB->editeddirs
[$dirpath];
105 $structure =& $editeddir->xml_file
->getStructure();
106 $table =& $structure->getTable($tableparam);
107 $key =& $table->getKey($keyparam);
108 $oldhash = $key->getHash();
110 $errors = array(); /// To store all the errors found
112 /// Perform some checks
115 $errors[] = $this->str
['keynameempty'];
117 /// Check incorrect name
118 if ($name == 'changeme') {
119 $errors[] = $this->str
['incorrectkeyname'];
121 /// Check duplicate name
122 if ($keyparam != $name && $table->getKey($name)) {
123 $errors[] = $this->str
['duplicatekeyname'];
125 $fieldsarr = explode(',', $fields);
126 /// Check the fields isn't empty
127 if (empty($fieldsarr[0])) {
128 $errors[] = $this->str
['nofieldsspecified'];
130 /// Check that there aren't duplicate column names
131 $uniquearr = array_unique($fieldsarr);
132 if (count($fieldsarr) != count($uniquearr)) {
133 $errors[] = $this->str
['duplicatefieldsused'];
135 /// Check that all the fields in belong to the table
136 foreach ($fieldsarr as $field) {
137 if (!$table->getField($field)) {
138 $errors[] = $this->str
['fieldsnotintable'];
142 /// If primary, check that all the fields are not null
143 if ($type == XMLDB_KEY_PRIMARY
) {
144 foreach ($fieldsarr as $field) {
145 if ($fi = $table->getField($field)) {
146 if (!$fi->getNotNull()) {
147 $errors[] = $this->str
['primarykeyonlyallownotnullfields'];
153 /// Check that there isn't any key using exactly the same fields
154 $tablekeys = $table->getKeys();
156 foreach ($tablekeys as $tablekey) {
157 /// Skip checking against itself
158 if ($keyparam == $tablekey->getName()) {
161 $keyfieldsarr = $tablekey->getFields();
162 /// Compare both arrays, looking for diferences
163 $diferences = array_merge(array_diff($fieldsarr, $keyfieldsarr), array_diff($keyfieldsarr, $fieldsarr));
164 if (empty($diferences)) {
165 $errors[] = $this->str
['fieldsusedinkey'];
170 /// Check that there isn't any index using exactlt the same fields
171 $tableindexes = $table->getIndexes();
173 foreach ($tableindexes as $tableindex) {
174 $indexfieldsarr = $tableindex->getFields();
175 /// Compare both arrays, looking for diferences
176 $diferences = array_merge(array_diff($fieldsarr, $indexfieldsarr), array_diff($indexfieldsarr, $fieldsarr));
177 if (empty($diferences)) {
178 $errors[] = $this->str
['fieldsusedinindex'];
184 if ($type == XMLDB_KEY_FOREIGN ||
185 $type == XMLDB_KEY_FOREIGN_UNIQUE
) {
186 $reffieldsarr = explode(',', $reffields);
187 /// Check reftable is not empty
188 if (empty($reftable)) {
189 $errors[] = $this->str
['noreftablespecified'];
191 /// Check reffields are not empty
192 if (empty($reffieldsarr[0])) {
193 $errors[] = $this->str
['noreffieldsspecified'];
195 /// Check the number of fields is correct
196 if (count($fieldsarr) != count($reffieldsarr)) {
197 $errors[] = $this->str
['wrongnumberofreffields'];
199 /// Check, if pointing to one structure table, that there is one master key for this key
200 if ($rt = $structure->getTable($reftable)) {
201 $masterfound = false;
202 $reftablekeys = $rt->getKeys();
204 foreach ($reftablekeys as $reftablekey) {
205 /// Only compare with primary and unique keys
206 if ($reftablekey->getType() != XMLDB_KEY_PRIMARY
&& $reftablekey->getType() != XMLDB_KEY_UNIQUE
) {
209 $keyfieldsarr = $reftablekey->getFields();
210 /// Compare both arrays, looking for diferences
211 $diferences = array_merge(array_diff($reffieldsarr, $keyfieldsarr), array_diff($keyfieldsarr, $reffieldsarr));
212 if (empty($diferences)) {
218 $errors[] = $this->str
['nomasterprimaryuniquefound'];
220 /// Quick test of the order
221 if (implode(',', $reffieldsarr) != implode(',', $keyfieldsarr)) {
222 $errors[] = $this->str
['masterprimaryuniqueordernomatch'];
232 if (!empty($errors)) {
233 $tempkey = new XMLDBKey($name);
234 $tempkey->setType($type);
235 $tempkey->setFields($fieldsarr);
236 if ($type == XMLDB_KEY_FOREIGN ||
237 $type == XMLDB_KEY_FOREIGN_UNIQUE
) {
238 $tempkey->setRefTable($reftable);
239 $tempkey->setRefFields($reffieldsarr);
241 /// Prepare the output
243 print_header("$site->shortname: XMLDB",
245 "<a href=\"../index.php\">" . $this->str
['administration'] . "</a> -> <a href=\"index.php\">XMLDB</a>");
246 notice ('<p>' .implode(', ', $errors) . '</p>
247 <p>' . $tempkey->readableInfo(),
248 'index.php?action=edit_key&key=' .$key->getName() . '&table=' . $table->getName() . '&dir=' . urlencode(str_replace($CFG->dirroot
, '', $dirpath)));
252 /// Continue if we aren't under errors
253 if (empty($errors)) {
254 /// If there is one name change, do it, changing the prev and next
255 /// atributes of the adjacent fields
256 if ($keyparam != $name) {
257 $key->setName($name);
258 if ($key->getPrevious()) {
259 $prev =& $table->getKey($key->getPrevious());
260 $prev->setNext($name);
261 $prev->setChanged(true);
263 if ($key->getNext()) {
264 $next =& $table->getKey($key->getNext());
265 $next->setPrevious($name);
266 $next->setChanged(true);
271 $key->setComment($comment);
273 /// Set the rest of fields
274 $key->setType($type);
275 $key->setFields($fieldsarr);
276 if ($type == XMLDB_KEY_FOREIGN ||
277 $type == XMLDB_KEY_FOREIGN_UNIQUE
) {
278 $key->setRefTable($reftable);
279 $key->setRefFields($reffieldsarr);
282 /// If the hash has changed from the old one, change the version
283 /// and mark the structure as changed
284 $key->calculateHash(true);
285 if ($oldhash != $key->getHash()) {
286 $key->setChanged(true);
287 $table->setChanged(true);
288 /// Recalculate the structure hash
289 $structure->calculateHash(true);
290 $structure->setVersion(userdate(time(), '%Y%m%d', 99, false));
292 $structure->setChanged(true);
295 /// Launch postaction if exists (leave this here!)
296 if ($this->getPostAction() && $result) {
297 return $this->launch($this->getPostAction());
301 /// Return ok if arrived here