Initial commit on HEAD of all the XMLDB stuff.
[moodle.git] / lib / xmldb / classes / XMLDBField.class.php
CommitLineData
8165877a 1<?php // $Id$
2
3///////////////////////////////////////////////////////////////////////////
4// //
5// NOTICE OF COPYRIGHT //
6// //
7// Moodle - Modular Object-Oriented Dynamic Learning Environment //
8// http://moodle.com //
9// //
10// Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
11// (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
12// //
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. //
17// //
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: //
22// //
23// http://www.gnu.org/copyleft/gpl.html //
24// //
25///////////////////////////////////////////////////////////////////////////
26
27/// This class represent one XMLDB Field
28
29class XMLDBField extends XMLDBObject {
30
31 var $type;
32 var $length;
33 var $unsigned;
34 var $notnull;
35 var $default;
36 var $sequence;
37 var $enum;
38 var $enumvalues;
39 var $decimals;
40
41 /**
42 * Creates one new XMLDBField
43 */
44 function XMLDBField($name) {
45 parent::XMLDBObject($name);
46 $this->type = NULL;
47 $this->length = NULL;
48 $this->unsigned = false;
49 $this->notnull = false;
50 $this->default = NULL;
51 $this->sequence = false;
52 $this->enum = false;
53 $this->enumvalues = NULL;
54 $this->decimals = NULL;
55 }
56
57 /**
58 * Get the type
59 */
60 function getType() {
61 return $this->type;
62 }
63
64 /**
65 * Get the length
66 */
67 function getLength() {
68 return $this->length;
69 }
70
71 /**
72 * Get the decimals
73 */
74 function getDecimals() {
75 return $this->decimals;
76 }
77
78 /**
79 * Get the notnull
80 */
81 function getNotNull() {
82 return $this->notnull;
83 }
84
85 /**
86 * Get the unsigned
87 */
88 function getUnsigned() {
89 return $this->unsigned;
90 }
91
92 /**
93 * Get the sequence
94 */
95 function getSequence() {
96 return $this->sequence;
97 }
98
99 /**
100 * Get the enum
101 */
102 function getEnum() {
103 return $this->enum;
104 }
105
106 /**
107 * Get the enumvalues
108 */
109 function getEnumValues() {
110 return $this->enumvalues;
111 }
112
113 /**
114 * Get the default
115 */
116 function getDefault() {
117 return $this->default;
118 }
119
120 /**
121 * Set the field type
122 */
123 function setType($type) {
124 $this->type = $type;
125 }
126
127 /**
128 * Set the field length
129 */
130 function setLength($length) {
131 $this->length = $length;
132 }
133
134 /**
135 * Set the field decimals
136 */
137 function setDecimals($decimals) {
138 $this->decimals = $decimals;
139 }
140
141 /**
142 * Set the field unsigned
143 */
144 function setUnsigned($unsigned=true) {
145 $this->unsigned = $unsigned;
146 }
147
148 /**
149 * Set the field notnull
150 */
151 function setNotNull($notnull=true) {
152 $this->notnull = $notnull;
153 }
154
155 /**
156 * Set the field sequence
157 */
158 function setSequence($sequence=true) {
159 $this->sequence = $sequence;
160 }
161
162 /**
163 * Set the field enum
164 */
165 function setEnum($enum=true) {
166 $this->enum = $enum;
167 }
168
169 /**
170 * Set the field enumvalues
171 */
172 function setEnumValues($enumvalues) {
173 $this->enumvalues = $enumvalues;
174 }
175
176 /**
177 * Set the field default
178 */
179 function setDefault($default) {
180 $this->default = $default;
181 }
182
183 /**
184 * Load data from XML to the table
185 */
186 function arr2XMLDBField($xmlarr) {
187
188 $result = true;
189
190 /// Debug the table
191 /// traverse_xmlize($xmlarr); //Debug
192 /// print_object ($GLOBALS['traverse_array']); //Debug
193 /// $GLOBALS['traverse_array']=""; //Debug
194
195 /// Process table attributes (name, type, length, unsigned,
196 /// notnull, sequence, enum, enumvalues, decimals, comment,
197 /// previous, next)
198 if (isset($xmlarr['@']['NAME'])) {
199 $this->name = trim($xmlarr['@']['NAME']);
200 } else {
201 $this->errormsg = 'Missing NAME attribute';
202 $result = false;
203 }
204
205 if (isset($xmlarr['@']['TYPE'])) {
206 /// Check for valid type
207 $type = $this->getXMLDBFieldType(trim($xmlarr['@']['TYPE']));
208 if ($type) {
209 $this->type = $type;
210 } else {
211 $this->errormsg = 'Invalid TYPE attribute';
212 $result = false;
213 }
214 } else {
215 $this->errormsg = 'Missing TYPE attribute';
216 $result = false;
217 }
218
219 if (isset($xmlarr['@']['LENGTH'])) {
220 $length = trim($xmlarr['@']['LENGTH']);
221 /// Check for integer values
222 if ($this->type == XMLDB_TYPE_INTEGER ||
223 $this->type == XMLDB_TYPE_NUMBER ||
224 $this->type == XMLDB_TYPE_CHAR) {
225 if (!(is_numeric($length)&&(intval($length)==floatval($length)))) {
226 $this->errormsg = 'Incorrect LENGTH attribute for int, number or char fields';
227 $result = false;
228 } else if (!$length) {
229 $this->errormsg = 'Zero LENGTH attribute';
230 $result = false;
231 }
232 }
233 /// Check for big, medium, small to be applied to text and binary
234 if ($this->type == XMLDB_TYPE_TEXT ||
235 $this->type == XMLDB_TYPE_BINARY) {
236 if (!$length) {
237 $length == 'big';
238 }
239 if ($length != 'big' &&
240 $length != 'medium' &&
241 $length != 'small') {
242 $this->errormsg = 'Incorrect LENGTH attribute for text and binary fields (only big, medium and small allowed)';
243 $result = false;
244 }
245 }
246 /// Finally, set the length
247 $this->length = $length;
248 }
249
250 if (isset($xmlarr['@']['UNSIGNED'])) {
251 $unsigned = strtolower(trim($xmlarr['@']['UNSIGNED']));
252 if ($unsigned == 'true') {
253 $this->unsigned = true;
254 } else if ($unsigned == 'false') {
255 $this->unsigned = false;
256 } else {
257 $this->errormsg = 'Incorrect UNSIGNED attribute (true/false allowed)';
258 $result = false;
259 }
260 }
261
262 if (isset($xmlarr['@']['NOTNULL'])) {
263 $notnull = strtolower(trim($xmlarr['@']['NOTNULL']));
264 if ($notnull == 'true') {
265 $this->notnull = true;
266 } else if ($notnull == 'false') {
267 $this->notnull = false;
268 } else {
269 $this->errormsg = 'Incorrect NOTNULL attribute (true/false allowed)';
270 $result = false;
271 }
272 }
273
274 if (isset($xmlarr['@']['SEQUENCE'])) {
275 $sequence = strtolower(trim($xmlarr['@']['SEQUENCE']));
276 if ($sequence == 'true') {
277 $this->sequence = true;
278 } else if ($sequence == 'false') {
279 $this->sequence = false;
280 } else {
281 $this->errormsg = 'Incorrect SEQUENCE attribute (true/false allowed)';
282 $result = false;
283 }
284 }
285
286 if (isset($xmlarr['@']['DEFAULT'])) {
287 $this->default = trim($xmlarr['@']['DEFAULT']);
288 }
289
290 if (isset($xmlarr['@']['ENUM'])) {
291 $enum = strtolower(trim($xmlarr['@']['ENUM']));
292 if ($enum == 'true') {
293 $this->enum = true;
294 } else if ($enum == 'false') {
295 $this->enum = false;
296 } else {
297 $this->errormsg = 'Incorrect ENUM attribute (true/false allowed)';
298 $result = false;
299 }
300 }
301
302 if (isset($xmlarr['@']['ENUMVALUES'])) {
303 $enumvalues = strtolower(trim($xmlarr['@']['ENUMVALUES']));
304 if (!$this->enum) {
305 $this->errormsg = 'Wrong ENUMVALUES attribute (not ENUM)';
306 $result = false;
307 $this->enumvalues = $enumvalues;
308 } else {
309 /// Check we have a valid list (comma separated of quoted values)
310 $enumarr = explode(',',$enumvalues);
311 if ($enumarr) {
312 foreach ($enumarr as $key => $enumelement) {
313 /// Clear some spaces
314 $enumarr[$key] = trim($enumelement);
315 $enumelement = trim($enumelement);
316 /// Skip if under error
317 if (!$result) {
318 continue;
319 }
320 /// Look for quoted strings
321 if (substr($enumelement, 0, 1) != "'" ||
322 substr($enumelement, -1, 1) != "'") {
323 $this->errormsg = 'Incorrect ENUMVALUES attribute (some value is not properly quoted)';
324 $result = false;
325 }
326 }
327 } else {
328 $this->errormsg = 'Incorrect ENUMVALUES attribute (comma separated of quoted values)';
329 $result = false;
330 }
331 }
332 } else if ($this->enum) {
333 $this->errormsg = 'Incorrect ENUMVALUES attribute (field is not declared as ENUM)';
334 $result = false;
335 }
336 /// Finally, set the value
337 if ($this->enum) {
338 $this->enumvalues = $enumarr;
339 }
340
341 $decimals = NULL;
342 if (isset($xmlarr['@']['DECIMALS'])) {
343 $decimals = trim($xmlarr['@']['DECIMALS']);
344 /// Check for integer values
345 if ($this->type == XMLDB_TYPE_NUMBER ||
346 $this->type == XMLDB_TYPE_FLOAT) {
347 if (!(is_numeric($decimals)&&(intval($decimals)==floatval($decimals)))) {
348 $this->errormsg = 'Incorrect DECIMALS attribute for number field';
349 $result = false;
350 } else if ($this->length <= $decimals){
351 $this->errormsg = 'Incorrect DECIMALS attribute (bigget than length)';
352 $result = false;
353 }
354 } else {
355 $this->errormsg = 'Incorrect DECIMALS attribute for non-number field';
356 $result = false;
357 }
358 } else {
359 if ($this->type == XMLDB_TYPE_NUMBER) {
360 $decimals = 0;
361 }
362 }
363 // Finally, set the decimals
364 if ($this->type == XMLDB_TYPE_NUMBER ||
365 $this->type == XMLDB_TYPE_FLOAT) {
366 $this->decimals = $decimals;
367 }
368
369 if (isset($xmlarr['@']['COMMENT'])) {
370 $this->comment = trim($xmlarr['@']['COMMENT']);
371 }
372
373 if (isset($xmlarr['@']['PREVIOUS'])) {
374 $this->previous = trim($xmlarr['@']['PREVIOUS']);
375 }
376
377 if (isset($xmlarr['@']['NEXT'])) {
378 $this->next = trim($xmlarr['@']['NEXT']);
379 }
380
381 /// Set some attributes
382 if ($result) {
383 $this->loaded = true;
384 }
385 $this->calculateHash();
386 return $result;
387 }
388
389 /**
390 * This function returns the correct XMLDB_TYPE_XXX value for the
391 * string passed as argument
392 */
393 function getXMLDBFieldType($type) {
394
395 $result = XMLDB_TYPE_INCORRECT;
396
397 switch (strtolower($type)) {
398 case 'int':
399 $result = XMLDB_TYPE_INTEGER;
400 break;
401 case 'number':
402 $result = XMLDB_TYPE_NUMBER;
403 break;
404 case 'float':
405 $result = XMLDB_TYPE_FLOAT;
406 break;
407 case 'char':
408 $result = XMLDB_TYPE_CHAR;
409 break;
410 case 'text':
411 $result = XMLDB_TYPE_TEXT;
412 break;
413 case 'binary':
414 $result = XMLDB_TYPE_BINARY;
415 break;
416 case 'datetime':
417 $result = XMLDB_TYPE_DATETIME;
418 break;
419 }
420 /// Return the normalized XMLDB_TYPE
421 return $result;
422 }
423
424 /**
425 * This function returns the correct name value for the
426 * XMLDB_TYPE_XXX passed as argument
427 */
428 function getXMLDBTypeName($type) {
429
430 $result = "";
431
432 switch (strtolower($type)) {
433 case XMLDB_TYPE_INTEGER:
434 $result = 'int';
435 break;
436 case XMLDB_TYPE_NUMBER:
437 $result = 'number';
438 break;
439 case XMLDB_TYPE_FLOAT:
440 $result = 'float';
441 break;
442 case XMLDB_TYPE_CHAR:
443 $result = 'char';
444 break;
445 case XMLDB_TYPE_TEXT:
446 $result = 'text';
447 break;
448 case XMLDB_TYPE_BINARY:
449 $result = 'binary';
450 break;
451 case XMLDB_TYPE_DATETIME:
452 $result = 'datetime';
453 break;
454 }
455 /// Return the normalized name
456 return $result;
457 }
458
459 /**
460 * This function calculate and set the hash of one XMLDBField
461 */
462 function calculateHash($recursive = false) {
463 if (!$this->loaded) {
464 $this->hash = NULL;
465 } else {
466 $key = $this->name . $this->type . $this->length .
467 $this->unsigned . $this->notnull . $this->sequence .
468 $this->decimals . $this->comment;
469 if ($this->enum) {
470 $key .= implode(', ',$this->enumvalues);
471 }
472 $this->hash = md5($key);
473 }
474 }
475
476 /**
477 *This function will output the XML text for one field
478 */
479 function xmlOutput() {
480 $o = '';
481 $o.= ' <FIELD NAME="' . $this->name . '"';
482 $o.= ' TYPE="' . $this->getXMLDBTypeName($this->type) . '"';
483 if ($this->length) {
484 $o.= ' LENGTH="' . $this->length . '"';
485 }
486 if ($this->notnull) {
487 $notnull = 'true';
488 } else {
489 $notnull = 'false';
490 }
491 $o.= ' NOTNULL="' . $notnull . '"';
492 if ($this->unsigned) {
493 $unsigned = 'true';
494 } else {
495 $unsigned = 'false';
496 }
497 if ($this->type == XMLDB_TYPE_INTEGER ||
498 $this->type == XMLDB_TYPE_NUMBER ||
499 $this->type == XMLDB_TYPE_FLOAT) {
500 if ($this->unsigned) {
501 $unsigned = 'true';
502 } else {
503 $unsigned = 'false';
504 }
505 $o.= ' UNSIGNED="' . $unsigned . '"';
506 }
507 if (!$this->sequence && $this->default !== NULL) {
508 $o.= ' DEFAULT="' . $this->default . '"';
509 }
510 if ($this->sequence) {
511 $sequence = 'true';
512 } else {
513 $sequence = 'false';
514 }
515 $o.= ' SEQUENCE="' . $sequence . '"';
516 if ($this->enum) {
517 $enum = 'true';
518 } else {
519 $enum = 'false';
520 }
521 $o.= ' ENUM="' . $enum . '"';
522 if ($this->enum) {
523 $o.= ' ENUMVALUES="' . implode(', ', $this->enumvalues) . '"';
524 }
525 if ($this->decimals !== NULL) {
526 $o.= ' DECIMALS="' . $this->decimals . '"';
527 }
528 if ($this->comment) {
529 $o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
530 }
531 if ($this->previous) {
532 $o.= ' PREVIOUS="' . $this->previous . '"';
533 }
534 if ($this->next) {
535 $o.= ' NEXT="' . $this->next . '"';
536 }
537 $o.= '/>' . "\n";
538
539 return $o;
540 }
541
542 /**
543 * This function will set all the attributes of the XMLDBField object
544 * based on information passed in one ADOField
545 */
546 function setFromADOField($adofield) {
547
548 /// Calculate the XMLDB_TYPE
549 switch (strtolower($adofield->type)) {
550 case 'int':
551 case 'tinyint':
552 case 'smallint':
553 case 'bigint':
554 case 'integer':
555 $this->type = XMLDB_TYPE_INTEGER;
556 break;
557 case 'number':
558 case 'decimal':
559 case 'dec':
560 case 'numeric':
561 $this->type = XMLDB_TYPE_NUMBER;
562 break;
563 case 'float':
564 case 'double':
565 $this->type = XMLDB_TYPE_FLOAT;
566 break;
567 case 'char':
568 case 'varchar':
569 case 'enum':
570 $this->type = XMLDB_TYPE_CHAR;
571 break;
572 case 'text':
573 case 'tinytext':
574 case 'mediumtext':
575 case 'longtext':
576 $this->type = XMLDB_TYPE_TEXT;
577 break;
578 case 'blob':
579 case 'tinyblob':
580 case 'mediumblob':
581 case 'longblob':
582 $this->type = XMLDB_TYPE_BINARY;
583 break;
584 case 'datetime':
585 case 'timestamp':
586 $this->type = XMLDB_TYPE_DATETIME;
587 break;
588 default:
589 $this->type = XMLDB_TYPE_TEXT;
590 }
591 /// Calculate the length of the field
592 if ($adofield->max_length > 0 &&
593 ($this->type == XMLDB_TYPE_INTEGER ||
594 $this->type == XMLDB_TYPE_NUMBER ||
595 $this->type == XMLDB_TYPE_FLOAT ||
596 $this->type == XMLDB_TYPE_CHAR)) {
597 $this->length = $adofield->max_length;
598 }
599 if ($this->type == XMLDB_TYPE_TEXT) {
600 switch (strtolower($adofield->type)) {
601 case 'tinytext':
602 case 'text':
603 $this->length = 'small';
604 break;
605 case 'mediumtext':
606 $this->length = 'medium';
607 break;
608 case 'longtext':
609 $this->length = 'big';
610 break;
611 default:
612 $this->length = 'small';
613 }
614 }
615 if ($this->type == XMLDB_TYPE_BINARY) {
616 switch (strtolower($adofield->type)) {
617 case 'tinyblob':
618 case 'blob':
619 $this->length = 'small';
620 break;
621 case 'mediumblob':
622 $this->length = 'medium';
623 break;
624 case 'longblob':
625 $this->length = 'big';
626 break;
627 default:
628 $this->length = 'small';
629 }
630 }
631 /// Calculate the decimals of the field
632 if ($adofield->max_length > 0 &&
633 $adofield->scale &&
634 ($this->type == XMLDB_TYPE_NUMBER ||
635 $this->type == XMLDB_TYPE_FLOAT)) {
636 $this->decimals = $adofield->scale;
637 }
638 /// Calculate the unsigned field
639 if ($adofield->unsigned &&
640 ($this->type == XMLDB_TYPE_INTEGER ||
641 $this->type == XMLDB_TYPE_NUMBER ||
642 $this->type == XMLDB_TYPE_FLOAT)) {
643 $this->unsigned = true;
644 }
645 /// Calculate the notnull field
646 if ($adofield->not_null) {
647 $this->notnull = true;
648 }
649 /// Calculate the default field
650 if ($adofield->has_default) {
651 $this->default = $adofield->default_value;
652 }
653 /// Calculate the sequence field
654 if ($adofield->auto_increment) {
655 $this->sequence = true;
656 /// Sequence fields are always unsigned
657 $this->unsigned = true;
658 }
659 /// Calculate the enum and enumvalues field
660 if ($adofield->type == 'enum') {
661 $this->enum = true;
662 $this->enumvalues = $adofield->enums;
663 }
664 /// Some more fields
665 $this->loaded = true;
666 $this->changed = true;
667 }
668
669 /**
670 * Shows info in a readable format
671 */
672 function readableInfo() {
673 $o = '';
674 /// type
675 $o .= $this->getXMLDBTypeName($this->type);
676 /// length
677 if ($this->type == XMLDB_TYPE_INTEGER ||
678 $this->type == XMLDB_TYPE_NUMBER ||
679 $this->type == XMLDB_TYPE_FLOAT ||
680 $this->type == XMLDB_TYPE_CHAR) {
681 if ($this->length) {
682 $o .= ' (' . $this->length;
683 if ($this->type == XMLDB_TYPE_NUMBER ||
684 $this->type == XMLDB_TYPE_FLOAT) {
685 if ($this->decimals !== NULL) {
686 $o .= ', ' . $this->decimals;
687 }
688 }
689 $o .= ')';
690 }
691 }
692 if ($this->type == XMLDB_TYPE_TEXT ||
693 $this->type == XMLDB_TYPE_BINARY) {
694 $o .= ' (' . $this->length . ')';
695 }
696 /// enum
697 if ($this->enum) {
698 $o .= ' enum(' . implode(', ', $this->enumvalues) . ')';
699 }
700 /// unsigned
701 if ($this->type == XMLDB_TYPE_INTEGER ||
702 $this->type == XMLDB_TYPE_NUMBER ||
703 $this->type == XMLDB_TYPE_FLOAT) {
704 if ($this->unsigned) {
705 $o .= ' unsigned';
706 } else {
707 $o .= ' signed';
708 }
709 }
710 /// not null
711 if ($this->notnull) {
712 $o .= ' not null';
713 }
714 /// default
715 if ($this->default !== NULL) {
716 $o .= ' default ';
717 if ($this->type == XMLDB_TYPE_CHAR ||
718 $this->type == XMLDB_TYPE_TEXT) {
719 $o .= "'" . $this->default . "'";
720 } else {
721 $o .= $this->default;
722 }
723 }
724 /// sequence
725 if ($this->sequence) {
726 $o .= ' auto-numbered';
727 }
728
729 return $o;
730 }
731}
732
733?>