0d47aa036d5906851a1ef75f15b67856adb6b843
[moodle.git] / lib / xmldb / xmldb_key.php
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/>.
17 /**
18  * This class represent one XMLDB Key
19  *
20  * @package    core_xmldb
21  * @copyright  1999 onwards Martin Dougiamas     http://dougiamas.com
22  *             2001-3001 Eloy Lafuente (stronk7) http://contiento.com
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
29 class xmldb_key extends xmldb_object {
31     /** @var int type of key */
32     protected $type;
34     /** @var array of fields */
35     protected $fields;
37     /** @var string referenced table */
38     protected $reftable;
40     /** @var array referenced fields */
41     protected $reffields;
43     /**
44      * Creates one new xmldb_key
45      * @param string $name
46      * @param string $type XMLDB_KEY_[PRIMARY|UNIQUE|FOREIGN|FOREIGN_UNIQUE]
47      * @param array $fields an array of fieldnames to build the key over
48      * @param string $reftable name of the table the FK points to or null
49      * @param array $reffields an array of fieldnames in the FK table or null
50      */
51     public function __construct($name, $type=null, $fields=array(), $reftable=null, $reffields=null) {
52         $this->type = null;
53         $this->fields = array();
54         $this->reftable = null;
55         $this->reffields = array();
56         parent::__construct($name);
57         $this->set_attributes($type, $fields, $reftable, $reffields);
58     }
60     /**
61      * Set all the attributes of one xmldb_key
62      *
63      * @param string $type XMLDB_KEY_[PRIMARY|UNIQUE|FOREIGN|FOREIGN_UNIQUE]
64      * @param array $fields an array of fieldnames to build the key over
65      * @param string $reftable name of the table the FK points to or null
66      * @param array $reffields an array of fieldnames in the FK table or null
67      */
68     public function set_attributes($type, $fields, $reftable=null, $reffields=null) {
69         $this->type = $type;
70         $this->fields = $fields;
71         $this->reftable = $reftable;
72         $this->reffields = empty($reffields) ? array() : $reffields;
73     }
75     /**
76      * Get the key type
77      * @return int
78      */
79     public function getType() {
80         return $this->type;
81     }
83     /**
84      * Set the key type
85      * @param int $type
86      */
87     public function setType($type) {
88         $this->type = $type;
89     }
91     /**
92      * Set the key fields
93      * @param array $fields
94      */
95     public function setFields($fields) {
96         $this->fields = $fields;
97     }
99     /**
100      * Set the key reftable
101      * @param string $reftable
102      */
103     public function setRefTable($reftable) {
104         $this->reftable = $reftable;
105     }
107     /**
108      * Set the key reffields
109      * @param array $reffields
110      */
111     public function setRefFields($reffields) {
112         $this->reffields = $reffields;
113     }
115     /**
116      * Get the key fields
117      * @return array
118      */
119     public function getFields() {
120         return $this->fields;
121     }
123     /**
124      * Get the key reftable
125      * @return string
126      */
127     public function getRefTable() {
128         return $this->reftable;
129     }
131     /**
132      * Get the key reffields
133      * @return array reference to ref fields
134      */
135     public function getRefFields() {
136         return $this->reffields;
137     }
139     /**
140      * Load data from XML to the key
141      * @param array $xmlarr
142      * @return bool success
143      */
144     public function arr2xmldb_key($xmlarr) {
146         $result = true;
148         // Debug the table
149         // traverse_xmlize($xmlarr);                   //Debug
150         // print_object ($GLOBALS['traverse_array']);  //Debug
151         // $GLOBALS['traverse_array']="";              //Debug
153         // Process key attributes (name, type, fields, reftable,
154         // reffields, comment, previous, next)
155         if (isset($xmlarr['@']['NAME'])) {
156             $this->name = trim($xmlarr['@']['NAME']);
157         } else {
158             $this->errormsg = 'Missing NAME attribute';
159             $this->debug($this->errormsg);
160             $result = false;
161         }
163         if (isset($xmlarr['@']['TYPE'])) {
164             // Check for valid type
165             $type = $this->getXMLDBKeyType(trim($xmlarr['@']['TYPE']));
166             if ($type) {
167                 $this->type = $type;
168             } else {
169                 $this->errormsg = 'Invalid TYPE attribute';
170                 $this->debug($this->errormsg);
171                 $result = false;
172             }
173         } else {
174             $this->errormsg = 'Missing TYPE attribute';
175             $this->debug($this->errormsg);
176             $result = false;
177         }
179         if (isset($xmlarr['@']['FIELDS'])) {
180             $fields = strtolower(trim($xmlarr['@']['FIELDS']));
181             if ($fields) {
182                 $fieldsarr = explode(',',$fields);
183                 if ($fieldsarr) {
184                     foreach ($fieldsarr as $key => $element) {
185                         $fieldsarr [$key] = trim($element);
186                     }
187                 } else {
188                     $this->errormsg = 'Incorrect FIELDS attribute (comma separated of fields)';
189                     $this->debug($this->errormsg);
190                     $result = false;
191                 }
192             } else {
193                 $this->errormsg = 'Empty FIELDS attribute';
194                 $this->debug($this->errormsg);
195                 $result = false;
196             }
197         } else {
198             $this->errormsg = 'Missing FIELDS attribute';
199             $this->debug($this->errormsg);
200             $result = false;
201         }
202         // Finally, set the array of fields
203         $this->fields = $fieldsarr;
205         if (isset($xmlarr['@']['REFTABLE'])) {
206             // Check we are in a FK
207             if ($this->type == XMLDB_KEY_FOREIGN ||
208                 $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
209                 $reftable = strtolower(trim($xmlarr['@']['REFTABLE']));
210                 if (!$reftable) {
211                     $this->errormsg = 'Empty REFTABLE attribute';
212                     $this->debug($this->errormsg);
213                     $result = false;
214                 }
215             } else {
216                 $this->errormsg = 'Wrong REFTABLE attribute (only FK can have it)';
217                 $this->debug($this->errormsg);
218                 $result = false;
219             }
220         } else if ($this->type == XMLDB_KEY_FOREIGN ||
221                    $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
222             $this->errormsg = 'Missing REFTABLE attribute';
223             $this->debug($this->errormsg);
224             $result = false;
225         }
226         // Finally, set the reftable
227         if ($this->type == XMLDB_KEY_FOREIGN ||
228             $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
229             $this->reftable = $reftable;
230         }
232         if (isset($xmlarr['@']['REFFIELDS'])) {
233             // Check we are in a FK
234             if ($this->type == XMLDB_KEY_FOREIGN ||
235                 $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
236                 $reffields = strtolower(trim($xmlarr['@']['REFFIELDS']));
237                 if ($reffields) {
238                     $reffieldsarr = explode(',',$reffields);
239                     if ($reffieldsarr) {
240                         foreach ($reffieldsarr as $key => $element) {
241                             $reffieldsarr [$key] = trim($element);
242                         }
243                     } else {
244                         $this->errormsg = 'Incorrect REFFIELDS attribute (comma separated of fields)';
245                         $this->debug($this->errormsg);
246                         $result = false;
247                     }
248                 } else {
249                     $this->errormsg = 'Empty REFFIELDS attribute';
250                     $this->debug($this->errormsg);
251                     $result = false;
252                 }
253             } else {
254                 $this->errormsg = 'Wrong REFFIELDS attribute (only FK can have it)';
255                 $this->debug($this->errormsg);
256                 $result = false;
257             }
258         } else if ($this->type == XMLDB_KEY_FOREIGN ||
259                    $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
260             $this->errormsg = 'Missing REFFIELDS attribute';
261             $this->debug($this->errormsg);
262             $result = false;
263         }
264         // Finally, set the array of reffields
265         if ($this->type == XMLDB_KEY_FOREIGN ||
266             $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
267             $this->reffields = $reffieldsarr;
268         }
270         if (isset($xmlarr['@']['COMMENT'])) {
271             $this->comment = trim($xmlarr['@']['COMMENT']);
272         }
274         // Set some attributes
275         if ($result) {
276             $this->loaded = true;
277         }
278         $this->calculateHash();
279         return $result;
280     }
282     /**
283      * This function returns the correct XMLDB_KEY_XXX value for the
284      * string passed as argument
285      * @param string $type
286      * @return int
287      */
288     public function getXMLDBKeyType($type) {
290         $result = XMLDB_KEY_INCORRECT;
292         switch (strtolower($type)) {
293             case 'primary':
294                 $result = XMLDB_KEY_PRIMARY;
295                 break;
296             case 'unique':
297                 $result = XMLDB_KEY_UNIQUE;
298                 break;
299             case 'foreign':
300                 $result = XMLDB_KEY_FOREIGN;
301                 break;
302             case 'foreign-unique':
303                 $result = XMLDB_KEY_FOREIGN_UNIQUE;
304                 break;
305             // case 'check':  //Not supported
306             //     $result = XMLDB_KEY_CHECK;
307             //     break;
308         }
309         // Return the normalized XMLDB_KEY
310         return $result;
311     }
313     /**
314      * This function returns the correct name value for the
315      * XMLDB_KEY_XXX passed as argument
316      * @param int $type
317      * @return string
318      */
319     public function getXMLDBKeyName($type) {
321         $result = '';
323         switch ($type) {
324             case XMLDB_KEY_PRIMARY:
325                 $result = 'primary';
326                 break;
327             case XMLDB_KEY_UNIQUE:
328                 $result = 'unique';
329                 break;
330             case XMLDB_KEY_FOREIGN:
331                 $result = 'foreign';
332                 break;
333             case XMLDB_KEY_FOREIGN_UNIQUE:
334                 $result = 'foreign-unique';
335                 break;
336             // case XMLDB_KEY_CHECK:  //Not supported
337             //     $result = 'check';
338             //     break;
339         }
340         // Return the normalized name
341         return $result;
342     }
344     /**
345      * This function calculate and set the hash of one xmldb_key
346      * @param bool $recursive
347      */
348      public function calculateHash($recursive = false) {
349         if (!$this->loaded) {
350             $this->hash = null;
351         } else {
352             $key = $this->type . implode(', ', $this->fields);
353             if ($this->type == XMLDB_KEY_FOREIGN ||
354                 $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
355                 $key .= $this->reftable . implode(', ', $this->reffields);
356             }
357                     ;
358             $this->hash = md5($key);
359         }
360     }
362     /**
363      *This function will output the XML text for one key
364      * @return string
365      */
366     public function xmlOutput() {
367         $o = '';
368         $o.= '        <KEY NAME="' . $this->name . '"';
369         $o.= ' TYPE="' . $this->getXMLDBKeyName($this->type) . '"';
370         $o.= ' FIELDS="' . implode(', ', $this->fields) . '"';
371         if ($this->type == XMLDB_KEY_FOREIGN ||
372             $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
373             $o.= ' REFTABLE="' . $this->reftable . '"';
374             $o.= ' REFFIELDS="' . implode(', ', $this->reffields) . '"';
375         }
376         if ($this->comment) {
377             $o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
378         }
379         $o.= '/>' . "\n";
381         return $o;
382     }
384     /**
385      * This function will set all the attributes of the xmldb_key object
386      * based on information passed in one ADOkey
387      * @oaram array $adokey
388      */
389     public function setFromADOKey($adokey) {
391         // Calculate the XMLDB_KEY
392         switch (strtolower($adokey['name'])) {
393             case 'primary':
394                 $this->type = XMLDB_KEY_PRIMARY;
395                 break;
396             default:
397                 $this->type = XMLDB_KEY_UNIQUE;
398         }
399         // Set the fields, converting all them to lowercase
400         $fields = array_flip(array_change_key_case(array_flip($adokey['columns'])));
401         $this->fields = $fields;
402         // Some more fields
403         $this->loaded = true;
404         $this->changed = true;
405     }
407     /**
408      * Returns the PHP code needed to define one xmldb_key
409      * @return string
410      */
411     public function getPHP() {
413         $result = '';
415         // The type
416         switch ($this->getType()) {
417             case XMLDB_KEY_PRIMARY:
418                 $result .= 'XMLDB_KEY_PRIMARY' . ', ';
419                 break;
420             case XMLDB_KEY_UNIQUE:
421                 $result .= 'XMLDB_KEY_UNIQUE' . ', ';
422                 break;
423             case XMLDB_KEY_FOREIGN:
424                 $result .= 'XMLDB_KEY_FOREIGN' . ', ';
425                 break;
426             case XMLDB_KEY_FOREIGN_UNIQUE:
427                 $result .= 'XMLDB_KEY_FOREIGN_UNIQUE' . ', ';
428                 break;
429         }
430         // The fields
431         $keyfields = $this->getFields();
432         if (!empty($keyfields)) {
433             $result .= 'array(' . "'".  implode("', '", $keyfields) . "')";
434         } else {
435             $result .= 'null';
436         }
437         // The FKs attributes
438         if ($this->getType() == XMLDB_KEY_FOREIGN ||
439             $this->getType() == XMLDB_KEY_FOREIGN_UNIQUE) {
440             // The reftable
441             $reftable = $this->getRefTable();
442             if (!empty($reftable)) {
443                 $result .= ", '" . $reftable . "', ";
444             } else {
445                 $result .= 'null, ';
446             }
447             // The reffields
448             $reffields = $this->getRefFields();
449             if (!empty($reffields)) {
450                 $result .= 'array(' . "'".  implode("', '", $reffields) . "')";
451             } else {
452                 $result .= 'null';
453             }
454         }
455         // Return result
456         return $result;
457     }
459     /**
460      * Shows info in a readable format
461      * @return string
462      */
463     public function readableInfo() {
464         $o = '';
465         // type
466         $o .= $this->getXMLDBKeyName($this->type);
467         // fields
468         $o .= ' (' . implode(', ', $this->fields) . ')';
469         // foreign key
470         if ($this->type == XMLDB_KEY_FOREIGN ||
471             $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
472             $o .= ' references ' . $this->reftable . ' (' . implode(', ', $this->reffields) . ')';
473         }
475         return $o;
476     }