Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
/**
18
 * This class represent one XMLDB Field
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
 */
25
 
26
defined('MOODLE_INTERNAL') || die();
27
 
28
 
29
class xmldb_field extends xmldb_object {
30
 
31
    /** @var int XMLDB_TYPE_ constants */
32
    protected $type;
33
 
34
    /** @var int size of field */
35
    protected $length;
36
 
37
    /** @var bool is null forbidden? XMLDB_NOTNULL */
38
    protected $notnull;
39
 
40
    /** @var mixed default value */
41
    protected $default;
42
 
43
    /** @var bool use automatic counter */
44
    protected $sequence;
45
 
46
    /** @var int number of decimals */
47
    protected $decimals;
48
 
49
    /**
50
     * Note:
51
     *  - Oracle: VARCHAR2 has a limit of 4000 bytes
52
     *  - SQL Server: NVARCHAR has a limit of 40000 chars
53
     *  - MySQL: VARCHAR 65,535 chars
54
     *  - PostgreSQL: no limit
55
     *
56
     * @var maximum length of text field
57
     */
58
    const CHAR_MAX_LENGTH = 1333;
59
 
60
 
61
    /**
62
     * @var maximum number of digits of integers
63
     */
64
    const INTEGER_MAX_LENGTH = 20;
65
 
66
    /**
67
     * @var max length (precision, the total number of digits) of decimals
68
     */
69
    const NUMBER_MAX_LENGTH = 38;
70
 
71
    /**
72
     * @var max length of floats
73
     */
74
    const FLOAT_MAX_LENGTH = 20;
75
 
76
    /**
77
     * Note:
78
     *  - PostgreSQL has a limit of 63 ascii chars (bytes) for table names. Others have greater limits.
79
     *
80
     * @var int max length of field names.
81
     */
82
    const NAME_MAX_LENGTH = 63;
83
 
84
    /**
85
     * Creates one new xmldb_field
86
     * @param string $name of field
87
     * @param int $type XMLDB_TYPE_INTEGER, XMLDB_TYPE_NUMBER, XMLDB_TYPE_CHAR, XMLDB_TYPE_TEXT, XMLDB_TYPE_BINARY
88
     * @param string $precision length for integers and chars, two-comma separated numbers for numbers
89
     * @param bool $unsigned XMLDB_UNSIGNED or null (or false)
90
     * @param bool $notnull XMLDB_NOTNULL or null (or false)
91
     * @param bool $sequence XMLDB_SEQUENCE or null (or false)
92
     * @param mixed $default meaningful default o null (or false)
93
     * @param string $previous
94
     */
95
    public function __construct($name, $type=null, $precision=null, $unsigned=null, $notnull=null, $sequence=null, $default=null, $previous=null) {
96
        $this->type = null;
97
        $this->length = null;
98
        $this->notnull = false;
99
        $this->default = null;
100
        $this->sequence = false;
101
        $this->decimals = null;
102
        parent::__construct($name);
103
        $this->set_attributes($type, $precision, $unsigned, $notnull, $sequence, $default, $previous);
104
    }
105
 
106
    /**
107
     * Set all the attributes of one xmldb_field
108
     *
109
     * @param int $type XMLDB_TYPE_INTEGER, XMLDB_TYPE_NUMBER, XMLDB_TYPE_CHAR, XMLDB_TYPE_TEXT, XMLDB_TYPE_BINARY
110
     * @param string $precision length for integers and chars, two-comma separated numbers for numbers
111
     * @param bool $unsigned XMLDB_UNSIGNED or null (or false)
112
     * @param bool $notnull XMLDB_NOTNULL or null (or false)
113
     * @param bool $sequence XMLDB_SEQUENCE or null (or false)
114
     * @param mixed $default meaningful default o null (or false)
115
     * @param string $previous
116
     */
117
    public function set_attributes($type, $precision=null, $unsigned=null, $notnull=null, $sequence=null, $default=null, $previous=null) {
118
        $this->type = $type;
119
 
120
        // LOBs (BINARY OR TEXT) don't support any precision (neither length or decimals).
121
        if ($type == XMLDB_TYPE_BINARY || $this->type == XMLDB_TYPE_TEXT) {
122
            $this->length = null;
123
            $this->decimals = null;
124
 
125
        } else if (!is_null($precision)) {
126
            // Try to split the not null precision into length and decimals and apply each one as needed.
127
            $precisionarr = explode(',', $precision);
128
            if (isset($precisionarr[0])) {
129
                $this->length = trim($precisionarr[0]);
130
            }
131
            if (isset($precisionarr[1])) {
132
                $this->decimals = trim($precisionarr[1]);
133
            }
134
        }
135
 
136
        $this->notnull = !empty($notnull) ? true : false;
137
        $this->sequence = !empty($sequence) ? true : false;
138
        $this->setDefault($default);
139
 
140
        $this->previous = $previous;
141
    }
142
 
143
    /**
144
     * Get the type
145
     * @return int
146
     */
147
    public function getType() {
148
        return $this->type;
149
    }
150
 
151
    /**
152
     * Get the length
153
     * @return int
154
     */
155
    public function getLength() {
156
        return $this->length;
157
    }
158
 
159
    /**
160
     * Get the decimals
161
     * @return string
162
     */
163
    public function getDecimals() {
164
        return $this->decimals;
165
    }
166
 
167
    /**
168
     * Get the notnull
169
     * @return bool
170
     */
171
    public function getNotNull() {
172
        return $this->notnull;
173
    }
174
 
175
    /**
176
     * Get the unsigned
177
     * @deprecated since moodle 2.3
178
     * @return bool
179
     */
180
    public function getUnsigned() {
181
        return false;
182
    }
183
 
184
    /**
185
     * Get the sequence
186
     * @return bool
187
     */
188
    public function getSequence() {
189
        return $this->sequence;
190
    }
191
 
192
    /**
193
     * Get the default
194
     * @return mixed
195
     */
196
    public function getDefault() {
197
        return $this->default;
198
    }
199
 
200
    /**
201
     * Set the field type
202
     * @param int $type
203
     */
204
    public function setType($type) {
205
        $this->type = $type;
206
    }
207
 
208
    /**
209
     * Set the field length
210
     * @param int $length
211
     */
212
    public function setLength($length) {
213
        $this->length = $length;
214
    }
215
 
216
    /**
217
     * Set the field decimals
218
     * @param string
219
     */
220
    public function setDecimals($decimals) {
221
        $this->decimals = $decimals;
222
    }
223
 
224
    /**
225
     * Set the field unsigned
226
     * @deprecated since moodle 2.3
227
     * @param bool $unsigned
228
     */
229
    public function setUnsigned($unsigned=true) {
230
    }
231
 
232
    /**
233
     * Set the field notnull
234
     * @param bool $notnull
235
     */
236
    public function setNotNull($notnull=true) {
237
        $this->notnull = $notnull;
238
    }
239
 
240
    /**
241
     * Set the field sequence
242
     * @param bool $sequence
243
     */
244
    public function setSequence($sequence=true) {
245
        $this->sequence = $sequence;
246
    }
247
 
248
    /**
249
     * Set the field default
250
     * @param mixed $default
251
     */
252
    public function setDefault($default) {
253
        // Check, warn and auto-fix '' (empty) defaults for CHAR NOT NULL columns, changing them
254
        // to NULL so XMLDB will apply the proper default
255
        if ($this->type == XMLDB_TYPE_CHAR && $this->notnull && $default === '') {
256
            $this->errormsg = 'XMLDB has detected one CHAR NOT NULL column (' . $this->name . ") with '' (empty string) as DEFAULT value. This type of columns must have one meaningful DEFAULT declared or none (NULL). XMLDB have fixed it automatically changing it to none (NULL). The process will continue ok and proper defaults will be created accordingly with each DB requirements. Please fix it in source (XML and/or upgrade script) to avoid this message to be displayed.";
257
            $this->debug($this->errormsg);
258
            $default = null;
259
        }
260
        // Check, warn and autofix TEXT|BINARY columns having a default clause (only null is allowed)
261
        if (($this->type == XMLDB_TYPE_TEXT || $this->type == XMLDB_TYPE_BINARY) && $default !== null) {
262
            $this->errormsg = 'XMLDB has detected one TEXT/BINARY column (' . $this->name . ") with some DEFAULT defined. This type of columns cannot have any default value. Please fix it in source (XML and/or upgrade script) to avoid this message to be displayed.";
263
            $this->debug($this->errormsg);
264
            $default = null;
265
        }
266
        $this->default = $default;
267
    }
268
 
269
    /**
270
     * Load data from XML to the table
271
     * @param array $xmlarr
272
     * @return mixed
273
     */
274
    public function arr2xmldb_field($xmlarr) {
275
 
276
        $result = true;
277
 
278
        // Debug the table
279
        // traverse_xmlize($xmlarr);                   //Debug
280
        // print_object ($GLOBALS['traverse_array']);  //Debug
281
        // $GLOBALS['traverse_array']="";              //Debug
282
 
283
        // Process table attributes (name, type, length
284
        // notnull, sequence, decimals, comment, previous, next)
285
        if (isset($xmlarr['@']['NAME'])) {
286
            $this->name = trim($xmlarr['@']['NAME']);
287
        } else {
288
            $this->errormsg = 'Missing NAME attribute';
289
            $this->debug($this->errormsg);
290
            $result = false;
291
        }
292
 
293
        if (isset($xmlarr['@']['TYPE'])) {
294
            // Check for valid type
295
            $type = $this->getXMLDBFieldType(trim($xmlarr['@']['TYPE']));
296
            if ($type) {
297
                $this->type = $type;
298
            } else {
299
                $this->errormsg = 'Invalid TYPE attribute';
300
                $this->debug($this->errormsg);
301
                $result = false;
302
            }
303
        } else {
304
            $this->errormsg = 'Missing TYPE attribute';
305
            $this->debug($this->errormsg);
306
            $result = false;
307
        }
308
 
309
        if (isset($xmlarr['@']['LENGTH'])) {
310
            $length = trim($xmlarr['@']['LENGTH']);
311
            // Check for integer values
312
            if ($this->type == XMLDB_TYPE_INTEGER ||
313
                $this->type == XMLDB_TYPE_NUMBER ||
314
                $this->type == XMLDB_TYPE_CHAR) {
315
                if (!(is_numeric($length)&&(intval($length)==floatval($length)))) {
316
                    $this->errormsg = 'Incorrect LENGTH attribute for int, number or char fields';
317
                    $this->debug($this->errormsg);
318
                    $result = false;
319
                } else if (!$length) {
320
                    $this->errormsg = 'Zero LENGTH attribute';
321
                    $this->debug($this->errormsg);
322
                    $result = false;
323
                }
324
            }
325
            // Remove length from text and binary
326
            if ($this->type == XMLDB_TYPE_TEXT ||
327
                $this->type == XMLDB_TYPE_BINARY) {
328
                $length = null;
329
            }
330
            // Finally, set the length
331
            $this->length = $length;
332
        }
333
 
334
        if (isset($xmlarr['@']['NOTNULL'])) {
335
            $notnull = strtolower(trim($xmlarr['@']['NOTNULL']));
336
            if ($notnull == 'true') {
337
                $this->notnull = true;
338
            } else if ($notnull == 'false') {
339
                $this->notnull = false;
340
            } else {
341
                $this->errormsg = 'Incorrect NOTNULL attribute (true/false allowed)';
342
                $this->debug($this->errormsg);
343
                $result = false;
344
            }
345
        }
346
 
347
        if (isset($xmlarr['@']['SEQUENCE'])) {
348
            $sequence = strtolower(trim($xmlarr['@']['SEQUENCE']));
349
            if ($sequence == 'true') {
350
                $this->sequence = true;
351
            } else if ($sequence == 'false') {
352
                $this->sequence = false;
353
            } else {
354
                $this->errormsg = 'Incorrect SEQUENCE attribute (true/false allowed)';
355
                $this->debug($this->errormsg);
356
                $result = false;
357
            }
358
        }
359
 
360
        if (isset($xmlarr['@']['DEFAULT'])) {
361
            $this->setDefault(trim($xmlarr['@']['DEFAULT']));
362
        }
363
 
364
        $decimals = null;
365
        if (isset($xmlarr['@']['DECIMALS'])) {
366
            $decimals = trim($xmlarr['@']['DECIMALS']);
367
            // Check for integer values
368
            if ($this->type == XMLDB_TYPE_NUMBER ||
369
                $this->type == XMLDB_TYPE_FLOAT) {
370
                if (!(is_numeric($decimals)&&(intval($decimals)==floatval($decimals)))) {
371
                    $this->errormsg = 'Incorrect DECIMALS attribute for number field';
372
                    $this->debug($this->errormsg);
373
                    $result = false;
374
                } else if ($this->length <= $decimals){
375
                    $this->errormsg = 'Incorrect DECIMALS attribute (bigget than length)';
376
                    $this->debug($this->errormsg);
377
                    $result = false;
378
                }
379
            } else {
380
                $this->errormsg = 'Incorrect DECIMALS attribute for non-number field';
381
                $this->debug($this->errormsg);
382
                $result = false;
383
            }
384
        } else {
385
            if ($this->type == XMLDB_TYPE_NUMBER) {
386
                $decimals = 0;
387
            }
388
        }
389
        // Finally, set the decimals
390
        if ($this->type == XMLDB_TYPE_NUMBER ||
391
            $this->type == XMLDB_TYPE_FLOAT) {
392
            $this->decimals = $decimals;
393
        }
394
 
395
        if (isset($xmlarr['@']['COMMENT'])) {
396
            $this->comment = trim($xmlarr['@']['COMMENT']);
397
        }
398
 
399
        // Set some attributes
400
        if ($result) {
401
            $this->loaded = true;
402
        }
403
        $this->calculateHash();
404
        return $result;
405
    }
406
 
407
    /**
408
     * This function returns the correct XMLDB_TYPE_XXX value for the
409
     * string passed as argument
410
     * @param string $type
411
     * @return int
412
     */
413
    public function getXMLDBFieldType($type) {
414
 
415
        $result = XMLDB_TYPE_INCORRECT;
416
 
417
        switch (strtolower($type)) {
418
            case 'int':
419
                $result = XMLDB_TYPE_INTEGER;
420
                break;
421
            case 'number':
422
                $result = XMLDB_TYPE_NUMBER;
423
                break;
424
            case 'float':
425
                $result = XMLDB_TYPE_FLOAT;
426
                break;
427
            case 'char':
428
                $result = XMLDB_TYPE_CHAR;
429
                break;
430
            case 'text':
431
                $result = XMLDB_TYPE_TEXT;
432
                break;
433
            case 'binary':
434
                $result = XMLDB_TYPE_BINARY;
435
                break;
436
            case 'datetime':
437
                $result = XMLDB_TYPE_DATETIME;
438
                break;
439
        }
440
        // Return the normalized XMLDB_TYPE
441
        return $result;
442
    }
443
 
444
    /**
445
     * This function returns the correct name value for the
446
     * XMLDB_TYPE_XXX passed as argument
447
     * @param int $type
448
     * @return string
449
     */
450
    public function getXMLDBTypeName($type) {
451
 
452
        $result = "";
453
 
454
        switch (strtolower($type)) {
455
            case XMLDB_TYPE_INTEGER:
456
                $result = 'int';
457
                break;
458
            case XMLDB_TYPE_NUMBER:
459
                $result = 'number';
460
                break;
461
            case XMLDB_TYPE_FLOAT:
462
                $result = 'float';
463
                break;
464
            case XMLDB_TYPE_CHAR:
465
                $result = 'char';
466
                break;
467
            case XMLDB_TYPE_TEXT:
468
                $result = 'text';
469
                break;
470
            case XMLDB_TYPE_BINARY:
471
                $result = 'binary';
472
                break;
473
            case XMLDB_TYPE_DATETIME:
474
                $result = 'datetime';
475
                break;
476
        }
477
        // Return the normalized name
478
        return $result;
479
    }
480
 
481
    /**
482
     * This function calculate and set the hash of one xmldb_field
483
     * @param bool $recursive
484
     * @return void, modifies $this->hash
485
     */
486
     public function calculateHash($recursive = false) {
487
        if (!$this->loaded) {
488
            $this->hash = null;
489
        } else {
490
            $defaulthash = is_null($this->default) ? '' : sha1($this->default);
491
            $key = $this->name . $this->type . $this->length .
492
                   $this->notnull . $this->sequence .
493
                   $this->decimals . $this->comment . $defaulthash;
494
            $this->hash = md5($key);
495
        }
496
    }
497
 
498
    /**
499
     * This function will output the XML text for one field
500
     * @return string
501
     */
502
    public function xmlOutput() {
503
        $o = '';
504
        $o.= '        <FIELD NAME="' . $this->name . '"';
505
        $o.= ' TYPE="' . $this->getXMLDBTypeName($this->type) . '"';
506
        if ($this->length) {
507
            $o.= ' LENGTH="' . $this->length . '"';
508
        }
509
        if ($this->notnull) {
510
            $notnull = 'true';
511
        } else {
512
            $notnull = 'false';
513
        }
514
        $o.= ' NOTNULL="' . $notnull . '"';
515
        if (!$this->sequence && $this->default !== null) {
516
            $o.= ' DEFAULT="' . $this->default . '"';
517
        }
518
        if ($this->sequence) {
519
            $sequence = 'true';
520
        } else {
521
            $sequence = 'false';
522
        }
523
        $o.= ' SEQUENCE="' . $sequence . '"';
524
        if ($this->decimals !== null) {
525
            $o.= ' DECIMALS="' . $this->decimals . '"';
526
        }
527
        if ($this->comment) {
528
            $o.= ' COMMENT="' . htmlspecialchars($this->comment, ENT_COMPAT) . '"';
529
        }
530
        $o.= '/>' . "\n";
531
 
532
        return $o;
533
    }
534
 
535
    /**
536
     * This function will set all the attributes of the xmldb_field object
537
     * based on information passed in one ADOField
538
     * @param database_column_info $adofield
539
     * @return void, sets $this->type
540
     */
541
    public function setFromADOField($adofield) {
542
 
543
        // Calculate the XMLDB_TYPE
544
        switch (strtolower($adofield->type)) {
545
            case 'int':
546
            case 'tinyint':
547
            case 'smallint':
548
            case 'bigint':
549
            case 'integer':
550
                $this->type = XMLDB_TYPE_INTEGER;
551
                break;
552
            case 'number':
553
            case 'decimal':
554
            case 'dec':
555
            case 'numeric':
556
                $this->type = XMLDB_TYPE_NUMBER;
557
                break;
558
            case 'float':
559
            case 'double':
560
                $this->type = XMLDB_TYPE_FLOAT;
561
                break;
562
            case 'char':
563
            case 'varchar':
564
            case 'enum':
565
                $this->type = XMLDB_TYPE_CHAR;
566
                break;
567
            case 'text':
568
            case 'tinytext':
569
            case 'mediumtext':
570
            case 'longtext':
571
                $this->type = XMLDB_TYPE_TEXT;
572
                break;
573
            case 'blob':
574
            case 'tinyblob':
575
            case 'mediumblob':
576
            case 'longblob':
577
                $this->type = XMLDB_TYPE_BINARY;
578
                break;
579
            case 'datetime':
580
            case 'timestamp':
581
                $this->type = XMLDB_TYPE_DATETIME;
582
                break;
583
            default:
584
                $this->type = XMLDB_TYPE_TEXT;
585
        }
586
        // Calculate the length of the field
587
        if ($adofield->max_length > 0 &&
588
               ($this->type == XMLDB_TYPE_INTEGER ||
589
                $this->type == XMLDB_TYPE_NUMBER  ||
590
                $this->type == XMLDB_TYPE_FLOAT   ||
591
                $this->type == XMLDB_TYPE_CHAR)) {
592
            $this->length = $adofield->max_length;
593
        }
594
        if ($this->type == XMLDB_TYPE_TEXT) {
595
            $this->length = null;
596
        }
597
        if ($this->type == XMLDB_TYPE_BINARY) {
598
            $this->length = null;
599
        }
600
        // Calculate the decimals of the field
601
        if ($adofield->max_length > 0 &&
602
            $adofield->scale &&
603
               ($this->type == XMLDB_TYPE_NUMBER ||
604
                $this->type == XMLDB_TYPE_FLOAT)) {
605
            $this->decimals = $adofield->scale;
606
        }
607
        // Calculate the notnull field
608
        if ($adofield->not_null) {
609
            $this->notnull = true;
610
        }
611
        // Calculate the default field
612
        if ($adofield->has_default) {
613
            $this->default = $adofield->default_value;
614
        }
615
        // Calculate the sequence field
616
        if ($adofield->auto_increment) {
617
            $this->sequence = true;
618
        }
619
        // Some more fields
620
        $this->loaded = true;
621
        $this->changed = true;
622
    }
623
 
624
    /**
625
     * Returns the PHP code needed to define one xmldb_field
626
     * @param bool $includeprevious
627
     * @return string
628
     */
629
    public function getPHP($includeprevious=true) {
630
 
631
        $result = '';
632
 
633
        // The XMLDBTYPE
634
        switch ($this->getType()) {
635
            case XMLDB_TYPE_INTEGER:
636
                $result .= 'XMLDB_TYPE_INTEGER' . ', ';
637
                break;
638
            case XMLDB_TYPE_NUMBER:
639
                $result .= 'XMLDB_TYPE_NUMBER' . ', ';
640
                break;
641
            case XMLDB_TYPE_FLOAT:
642
                $result .= 'XMLDB_TYPE_FLOAT' . ', ';
643
                break;
644
            case XMLDB_TYPE_CHAR:
645
                $result .= 'XMLDB_TYPE_CHAR' . ', ';
646
                break;
647
            case XMLDB_TYPE_TEXT:
648
                $result .= 'XMLDB_TYPE_TEXT' . ', ';
649
                break;
650
            case XMLDB_TYPE_BINARY:
651
                $result .= 'XMLDB_TYPE_BINARY' . ', ';
652
                break;
653
            case XMLDB_TYPE_DATETIME:
654
                $result .= 'XMLDB_TYPE_DATETIME' . ', ';
655
                break;
656
            case XMLDB_TYPE_TIMESTAMP:
657
                $result .= 'XMLDB_TYPE_TIMESTAMP' . ', ';
658
                break;
659
        }
660
        // The length
661
        $length = $this->getLength();
662
        $decimals = $this->getDecimals();
663
        if (!empty($length)) {
664
            $result .= "'" . $length;
665
            if (!empty($decimals)) {
666
                $result .= ', ' . $decimals;
667
            }
668
            $result .= "', ";
669
        } else {
670
            $result .= 'null, ';
671
        }
672
        // Unsigned is not used any more since Moodle 2.3
673
        $result .= 'null, ';
674
        // Not Null
675
        $notnull = $this->getNotnull();
676
        if (!empty($notnull)) {
677
            $result .= 'XMLDB_NOTNULL' . ', ';
678
        } else {
679
            $result .= 'null, ';
680
        }
681
        // Sequence
682
        $sequence = $this->getSequence();
683
        if (!empty($sequence)) {
684
            $result .= 'XMLDB_SEQUENCE' . ', ';
685
        } else {
686
            $result .= 'null, ';
687
        }
688
        // Default
689
        $default =  $this->getDefault();
690
        if ($default !== null && !$this->getSequence()) {
691
            $result .= "'" . $default . "'";
692
        } else {
693
            $result .= 'null';
694
        }
695
        // Previous (decided by parameter)
696
        if ($includeprevious) {
697
            $previous = $this->getPrevious();
698
            if (!empty($previous)) {
699
                $result .= ", '" . $previous . "'";
700
            } else {
701
                $result .= ', null';
702
            }
703
        }
704
        // Return result
705
        return $result;
706
    }
707
 
708
    /**
709
     * Shows info in a readable format
710
     * @return string
711
     */
712
    public function readableInfo() {
713
        $o = '';
714
        // type
715
        $o .= $this->getXMLDBTypeName($this->type);
716
        // length
717
        if ($this->type == XMLDB_TYPE_INTEGER ||
718
            $this->type == XMLDB_TYPE_NUMBER  ||
719
            $this->type == XMLDB_TYPE_FLOAT   ||
720
            $this->type == XMLDB_TYPE_CHAR) {
721
            if ($this->length) {
722
                $o .= ' (' . $this->length;
723
                if ($this->type == XMLDB_TYPE_NUMBER  ||
724
                    $this->type == XMLDB_TYPE_FLOAT) {
725
                    if ($this->decimals !== null) {
726
                        $o .= ', ' . $this->decimals;
727
                    }
728
                }
729
                $o .= ')';
730
            }
731
        }
732
        // not null
733
        if ($this->notnull) {
734
            $o .= ' not null';
735
        }
736
        // default
737
        if ($this->default !== null) {
738
            $o .= ' default ';
739
            if ($this->type == XMLDB_TYPE_CHAR ||
740
                $this->type == XMLDB_TYPE_TEXT) {
741
                    $o .= "'" . $this->default . "'";
742
            } else {
743
                $o .= $this->default;
744
            }
745
        }
746
        // sequence
747
        if ($this->sequence) {
748
            $o .= ' auto-numbered';
749
        }
750
 
751
        return $o;
752
    }
753
 
754
    /**
755
     * Validates the field restrictions.
756
     *
757
     * The error message should not be localised because it is intended for developers,
758
     * end users and admins should never see these problems!
759
     *
760
     * @param xmldb_table $xmldb_table optional when object is table
761
     * @return string null if ok, error message if problem found
762
     */
763
    public function validateDefinition(xmldb_table $xmldb_table=null) {
764
        if (!$xmldb_table) {
765
            return 'Invalid xmldb_field->validateDefinition() call, $xmldb_table is required.';
766
        }
767
 
768
        $name = $this->getName();
769
        if (strlen($name) > self::NAME_MAX_LENGTH) {
770
            return 'Invalid field name in table {'.$xmldb_table->getName().'}: field "'.$this->getName().'" name is too long.'
771
                .' Limit is '.self::NAME_MAX_LENGTH.' chars.';
772
        }
773
        if (!preg_match('/^[a-z][a-z0-9_]*$/', $name)) {
774
            return 'Invalid field name in table {'.$xmldb_table->getName().'}: field "'.$this->getName().'" name includes invalid characters.';
775
        }
776
 
777
        switch ($this->getType()) {
778
            case XMLDB_TYPE_INTEGER:
779
                $length = $this->getLength();
780
                if (!is_number($length) or $length <= 0 or $length > self::INTEGER_MAX_LENGTH) {
781
                    return 'Invalid field definition in table {'.$xmldb_table->getName().'}: XMLDB_TYPE_INTEGER field "'.$this->getName().'" has invalid length';
782
                }
783
                $default = $this->getDefault();
784
                if (!empty($default) and !is_number($default)) {
785
                    return 'Invalid field definition in table {'.$xmldb_table->getName().'}: XMLDB_TYPE_INTEGER field "'.$this->getName().'" has invalid default';
786
                }
787
                break;
788
 
789
            case XMLDB_TYPE_NUMBER:
790
                $maxlength = self::NUMBER_MAX_LENGTH;
791
                $length = $this->getLength();
792
                if (!is_number($length) or $length <= 0 or $length > $maxlength) {
793
                    return 'Invalid field definition in table {'.$xmldb_table->getName().'}: XMLDB_TYPE_NUMBER field "'.$this->getName().'" has invalid length';
794
                }
795
                $decimals = $this->getDecimals();
796
                $decimals = empty($decimals) ? 0 : $decimals; // fix missing decimals
797
                if (!is_number($decimals) or $decimals < 0 or $decimals > $length) {
798
                    return 'Invalid field definition in table {'.$xmldb_table->getName().'}: XMLDB_TYPE_NUMBER field "'.$this->getName().'" has invalid decimals';
799
                }
800
                if ($length - $decimals > self::INTEGER_MAX_LENGTH) {
801
                    return 'Invalid field definition in table {'.$xmldb_table->getName().'}: XMLDB_TYPE_NUMBER field "'.
802
                        $this->getName().'" has too big whole number part';
803
                }
804
                $default = $this->getDefault();
805
                if (!empty($default) and !is_numeric($default)) {
806
                    return 'Invalid field definition in table {'.$xmldb_table->getName().'}: XMLDB_TYPE_NUMBER field "'.$this->getName().'" has invalid default';
807
                }
808
                break;
809
 
810
            case XMLDB_TYPE_FLOAT:
811
                $length = $this->getLength();
812
                $length = empty($length) ? 6 : $length; // weird, it might be better to require something here...
813
                if (!is_number($length) or $length <= 0 or $length > self::FLOAT_MAX_LENGTH) {
814
                    return 'Invalid field definition in table {'.$xmldb_table->getName().'}: XMLDB_TYPE_FLOAT field "'.$this->getName().'" has invalid length';
815
                }
816
                $decimals = $this->getDecimals();
817
                $decimals = empty($decimals) ? 0 : $decimals; // fix missing decimals
818
                if (!is_number($decimals) or $decimals < 0 or $decimals > $length) {
819
                    return 'Invalid field definition in table {'.$xmldb_table->getName().'}: XMLDB_TYPE_FLOAT field "'.$this->getName().'" has invalid decimals';
820
                }
821
                $default = $this->getDefault();
822
                if (!empty($default) and !is_numeric($default)) {
823
                    return 'Invalid field definition in table {'.$xmldb_table->getName().'}: XMLDB_TYPE_FLOAT field "'.$this->getName().'" has invalid default';
824
                }
825
                break;
826
 
827
            case XMLDB_TYPE_CHAR:
828
                if ($this->getLength() > self::CHAR_MAX_LENGTH) {
829
                    return 'Invalid field definition in table {'.$xmldb_table->getName(). '}: XMLDB_TYPE_CHAR field "'.$this->getName().'" is too long.'
830
                           .' Limit is '.self::CHAR_MAX_LENGTH.' chars.';
831
                }
832
                break;
833
 
834
            case XMLDB_TYPE_TEXT:
835
                break;
836
 
837
            case XMLDB_TYPE_BINARY:
838
                break;
839
 
840
            case XMLDB_TYPE_DATETIME:
841
                break;
842
 
843
            case XMLDB_TYPE_TIMESTAMP:
844
                break;
845
        }
846
 
847
        return null;
848
    }
849
}