Proyectos de Subversion Moodle

Rev

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