1<?php
2
3/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
4
5/**
6 * This class provides methods for building a DB generation script,
7 * getting a full overview on abstract table definitions and more...
8 *
9 * @author  Alex Killing <alex.killing@gmx.de>
10 * @version $Id: class.ilDBUpdate.php 18649 2009-01-21 09:59:23Z akill $
11 * @ingroup ServicesDatabase
12 */
13class ilDBGenerator
14{
15
16    /**
17     * @var string
18     */
19    protected $target_encoding = 'UTF-8';
20    /**
21     * @var array
22     */
23    protected $whitelist = array();
24    /**
25     * @var array
26     */
27    protected $blacklist = array();
28    /**
29     * @var array
30     */
31    protected $tables = array();
32    /**
33     * @var array
34     */
35    protected $filter = array();
36
37
38    /**
39     * Constructor
40     */
41    public function __construct()
42    {
43        global $DIC;
44        $ilDB = $DIC->database();
45
46        $this->manager = $ilDB->loadModule(ilDBConstants::MODULE_MANAGER);
47        $this->reverse = $ilDB->loadModule(ilDBConstants::MODULE_REVERSE);
48        $this->il_db = $ilDB;
49        include_once("./Services/Database/classes/class.ilDBAnalyzer.php");
50        $this->analyzer = new ilDBAnalyzer();
51
52        $this->allowed_attributes = $ilDB->getAllowedAttributes();
53    }
54
55    /**
56     * @return array
57     * @deprecated abstraction_progress is no longer used in ILIAS
58     */
59    public static function lookupAbstractedTables()
60    {
61        global $DIC;
62        $ilDB = $DIC->database();
63
64        $query = "SELECT DISTINCT(table_name) FROM abstraction_progress ";
65        $res = $ilDB->query($query);
66        $names = array();
67        while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
68            $names[] = $row->table_name;
69        }
70
71        // tables that have been already created in an abstracted
72        // way or tables that have been renamed after being abstracted
73        // (see db_update script)
74        $abs_tables = array_merge($names, array(
75            'acc_access_key',
76            'acc_user_access_key',
77            'ldap_rg_mapping',
78            'page_anchor',
79            'qpl_question_orderinghorizontal',
80            'qpl_question_fileupload',
81            'chat_smilies',
82            'style_color',
83            'style_template_class',
84            'style_template',
85            'page_style_usage',
86            'style_setting',
87            'page_editor_settings',
88            'mep_data',
89            'license_data',
90            'loginname_history',
91            'mep_item',
92            'qpl_a_cloze',
93            'qpl_a_imagemap',
94            'qpl_a_matching',
95            'qpl_num_range',
96            'qpl_qst_cloze',
97            'qpl_qst_essay',
98            'qpl_qst_fileupload',
99            'qpl_qst_flash',
100            'qpl_qst_horder',
101            'qpl_qst_imagemap',
102            'qpl_qst_javaapplet',
103            'qpl_qst_matching',
104            'qpl_qst_mc',
105            'qpl_qst_numeric',
106            'qpl_qst_ordering',
107            'qpl_qst_sc',
108            'qpl_qst_textsubset',
109            'qpl_qst_type',
110            'qpl_sol_sug',
111            'udf_text',
112            'udf_clob',
113            'xmlnestedsettmp',
114            'cache_text',
115            'cache_clob',
116            'qpl_a_errortext',
117            'qpl_qst_errortext',
118            'tst_rnd_cpy',
119            'tst_rnd_qpl_title',
120            'qpl_a_mdef',
121        ));
122
123        return $abs_tables;
124    }
125
126
127    /**
128     * Set the desired target encoding
129     * If the target encoding os different from UTF-8
130     * all text values will be shortened to length of
131     * of the current text field
132     *
133     * E.g:
134     * il_meta_keyword keyword(4000) target encoding: UTF16
135     *
136     * =>
137     * <code>
138     * $value = mb_convert_encoding($value,'UTF-8','UTF-16');
139     * $value = mb_strcut($value,0,4000,'UTF16');
140     * $value = mb_convert_encoding($value,'UTF-16','UTF-8');
141     * </code>
142     *
143     *
144     * @param object $a_encoding
145     * @return
146     */
147    public function setTargetEncoding($a_encoding)
148    {
149        $this->target_encoding = $a_encoding;
150    }
151
152
153    /**
154     * Returns the target encoding
155     *
156     * @return string
157     */
158    public function getTargetEncoding()
159    {
160        return $this->target_encoding;
161    }
162
163
164    /**
165     * Set Table Black List.
166     * (Tables that should not be included in the processing)
167     *
168     * @param    array $a_blacklist Table Black List
169     */
170    public function setBlackList($a_blacklist)
171    {
172        $this->blacklist = $a_blacklist;
173    }
174
175
176    /**
177     * Get Table Black List.
178     *
179     * @return    array    Table Black List
180     */
181    public function getBlackList()
182    {
183        return $this->blacklist;
184    }
185
186
187    /**
188     * Set Table White List.
189     * Per default all tables are included in the processing. If a white
190     * list ist provided, only them will be used.
191     *
192     * @param    array $a_whitelist Table White List
193     */
194    public function setWhiteList($a_whitelist)
195    {
196        $this->whitelist = $a_whitelist;
197    }
198
199
200    /**
201     * Get Table White List.
202     *
203     * @return    array    Table White List
204     */
205    public function getWhiteList()
206    {
207        return $this->whitelist;
208    }
209
210
211    /**
212     * @param $a_filter
213     * @param $a_value
214     */
215    public function setFilter($a_filter, $a_value)
216    {
217        $this->filter[$a_filter] = $a_value;
218    }
219
220
221    /**
222     * @return array
223     */
224    public function getTables()
225    {
226        $r = $this->manager->listTables();
227        $this->tables = $r;
228
229        return $this->tables;
230    }
231
232
233    /**
234     * Check whether a table should be processed or not
235     */
236    public function checkProcessing($a_table)
237    {
238        // check black list
239        if (in_array($a_table, $this->blacklist)) {
240            return false;
241        }
242
243        // check white list
244        if (count($this->whitelist) > 0 && !in_array($a_table, $this->whitelist)) {
245            return false;
246        }
247
248        return true;
249    }
250
251
252    protected function openFile($a_path)
253    {
254        if (1) {
255            $file = fopen($a_path, "w");
256            $start .= "\t" . 'global $ilDB;' . "\n\n";
257            fwrite($file, $start);
258
259            return $file;
260        }
261
262        $file = fopen($a_path, "w");
263        $start = '<?php' . "\n" . 'function setupILIASDatabase()' . "\n{\n";
264        $start .= "\t" . 'global $ilDB;' . "\n\n";
265        fwrite($file, $start);
266
267        return $file;
268    }
269
270
271    protected function closeFile($fp)
272    {
273        if (1) {
274            #fwrite ($fp, $end);
275            fclose($fp);
276
277            return;
278        }
279
280        $end = "\n}\n?>\n";
281        fwrite($fp, $end);
282        fclose($fp);
283    }
284
285
286    /**
287     * Build DB generation script
288     *
289     * @param    string        output filename, if no filename is given, script is echoed
290     */
291    public function buildDBGenerationScript($a_filename = "")
292    {
293        if (@is_dir($a_filename)) {
294            $isDirectory = true;
295            $path = $a_filename;
296        } else {
297            $isDirectory = false;
298            $path = '';
299        }
300
301        $file = "";
302        if ($a_filename != "" and !$isDirectory) {
303            $file = fopen($a_filename, "w");
304
305            $start = '<?php' . "\n" . 'function setupILIASDatabase()' . "\n{\n";
306            $start .= "\t" . 'global $ilDB;' . "\n\n";
307            fwrite($file, $start);
308        } elseif ($isDirectory) {
309            ;
310        } else {
311            echo "<pre>";
312        }
313
314        $this->getTables();
315
316        foreach ($this->tables as $table) {
317            if ($this->checkProcessing($table)) {
318                if ($a_filename != "") {
319                    flush();
320                }
321
322                if ($isDirectory) {
323                    $file = $this->openFile($path . '/' . $table);
324                }
325
326                // create table statement
327                $this->buildCreateTableStatement($table, $file);
328
329                // primary key
330                $this->buildAddPrimaryKeyStatement($table, $file);
331
332                // indices
333                $this->buildAddIndexStatements($table, $file);
334
335                // constraints (currently unique keys)
336                $this->buildAddUniqueConstraintStatements($table, $file);
337
338                // auto increment sequence
339                $this->buildCreateSequenceStatement($table, $file);
340
341                if (in_array($table, array('usr_session_stats', 'usr_session_raw'))) {
342                    continue;
343                }
344
345                // inserts
346                if ($isDirectory) {
347                    $this->buildInsertStatement($table, $path);
348                #$this->buildInsertStatementsXML($table,$path);
349                } else {
350                    $this->buildInsertStatements($table, $file);
351                }
352
353                if ($isDirectory) {
354                    $this->closeFile($file);
355                }
356            } else {
357                if ($a_filename != "") {
358                    echo "<br><b>missing: " . $table . "</b>";
359                    flush();
360                }
361            }
362        }
363
364        // sequence(s) without table (of same name)
365        $this->buildSingularSequenceStatement($file);
366
367        if ($a_filename == "") {
368            echo "</pre>";
369        } elseif (!$isDirectory) {
370            $end = "\n}\n?>\n";
371            $ok = fwrite($file, $end);
372            var_dump($ok);
373            fclose($file);
374        }
375    }
376
377
378    /**
379     * Build CreateTable statement
380     *
381     * @param    string        table name
382     * @param    file          file resource or empty string
383     */
384    public function buildCreateTableStatement($a_table, $a_file = "")
385    {
386        $fields = $this->analyzer->getFieldInformation($a_table, true);
387        $this->fields = $fields;
388        $create_st = "\n\n//\n// " . $a_table . "\n//\n";
389        $create_st .= '$fields = array (' . "\n";
390        $f_sep = "";
391        foreach ($fields as $f => $def) {
392            $create_st .= "\t" . $f_sep . '"' . $f . '" => array (' . "\n";
393            $f_sep = ",";
394            $a_sep = "";
395            foreach ($def as $k => $v) {
396                if ($k != "nativetype" && $k != "alt_types" && $k != "autoincrement" && !is_null($v)) {
397                    switch ($k) {
398                        case "notnull":
399                        case "unsigned":
400                        case "fixed":
401                            $v = $v ? "true" : "false";
402                            break;
403
404                        case "default":
405                        case "type":
406                            $v = '"' . $v . '"';
407                            break;
408
409                        default:
410                            break;
411                    }
412                    $create_st .= "\t\t" . $a_sep . '"' . $k . '" => ' . $v . "\n";
413                    $a_sep = ",";
414                }
415            }
416            $create_st .= "\t" . ')' . "\n";
417        }
418        $create_st .= ');' . "\n";
419        $create_st .= '$ilDB->createTable("' . $a_table . '", $fields);' . "\n";
420
421        if ($a_file == "") {
422            echo $create_st;
423        } else {
424            fwrite($a_file, $create_st);
425        }
426    }
427
428
429    /**
430     * Build AddPrimaryKey statement
431     *
432     * @param    string        table name
433     * @param    file          file resource or empty string
434     */
435    public function buildAddPrimaryKeyStatement($a_table, $a_file = "")
436    {
437        $pk = $this->analyzer->getPrimaryKeyInformation($a_table);
438
439        if (is_array($pk["fields"]) && count($pk["fields"]) > 0) {
440            $pk_st = "\n" . '$pk_fields = array(';
441            $sep = "";
442            foreach ($pk["fields"] as $f => $pos) {
443                $pk_st .= $sep . '"' . $f . '"';
444                $sep = ",";
445            }
446            $pk_st .= ");\n";
447            $pk_st .= '$ilDB->addPrimaryKey("' . $a_table . '", $pk_fields);' . "\n";
448
449            if ($a_file == "") {
450                echo $pk_st;
451            } else {
452                fwrite($a_file, $pk_st);
453            }
454        }
455    }
456
457
458    /**
459     * Build AddIndex statements
460     *
461     * @param    string        table name
462     * @param    file          file resource or empty string
463     */
464    public function buildAddIndexStatements($a_table, $a_file = "")
465    {
466        $ind = $this->analyzer->getIndicesInformation($a_table, true);
467
468        if (is_array($ind)) {
469            foreach ($ind as $i) {
470                if ($i["fulltext"]) {
471                    $ft = ", true";
472                } else {
473                    $ft = ", false";
474                }
475                $in_st = "\n" . '$in_fields = array(';
476                $sep = "";
477                foreach ($i["fields"] as $f => $pos) {
478                    $in_st .= $sep . '"' . $f . '"';
479                    $sep = ",";
480                }
481                $in_st .= ");\n";
482                $in_st .= '$ilDB->addIndex("' . $a_table . '", $in_fields, "' . $i["name"] . '"' . $ft . ');' . "\n";
483
484                if ($a_file == "") {
485                    echo $in_st;
486                } else {
487                    fwrite($a_file, $in_st);
488                }
489            }
490        }
491    }
492
493
494    /**
495     * Build AddUniqueConstraint statements
496     *
497     * @param    string        table name
498     * @param    file          file resource or empty string
499     */
500    public function buildAddUniqueConstraintStatements($a_table, $a_file = "")
501    {
502        $con = $this->analyzer->getConstraintsInformation($a_table, true);
503
504        if (is_array($con)) {
505            foreach ($con as $i) {
506                $in_st = "\n" . '$in_fields = array(';
507                $sep = "";
508                foreach ($i["fields"] as $f => $pos) {
509                    $in_st .= $sep . '"' . $f . '"';
510                    $sep = ",";
511                }
512                $in_st .= ");\n";
513                $in_st .= '$ilDB->addUniqueConstraint("' . $a_table . '", $in_fields, "' . $i["name"] . '");' . "\n";
514
515                if ($a_file == "") {
516                    echo $in_st;
517                } else {
518                    fwrite($a_file, $in_st);
519                }
520            }
521        }
522    }
523
524
525    /**
526     * Build CreateSequence statement
527     *
528     * @param    string        table name
529     * @param    file          file resource or empty string
530     */
531    public function buildCreateSequenceStatement($a_table, $a_file = "")
532    {
533        $seq = $this->analyzer->hasSequence($a_table);
534        if ($seq !== false) {
535            $seq_st = "\n" . '$ilDB->createSequence("' . $a_table . '", ' . (int) $seq . ');' . "\n";
536
537            if ($a_file == "") {
538                echo $seq_st;
539            } else {
540                fwrite($a_file, $seq_st);
541            }
542        }
543    }
544
545
546    /**
547     * Build CreateSequence statement (if not belonging to table)
548     *
549     * @param    file        file resource or empty string
550     */
551    public function buildSingularSequenceStatement($a_file = "")
552    {
553        $r = $this->manager->listSequences();
554
555        foreach ($r as $seq) {
556            if (!in_array($seq, $this->tables)) {
557                // 12570
558                if ($seq == "sahs_sc13_seq") {
559                    continue;
560                }
561
562                $create_st = "\n" . '$ilDB->createSequence("' . $seq . '");' . "\n";
563
564                if ($a_file == "") {
565                    echo $create_st;
566                } else {
567                    fwrite($a_file, $create_st);
568                }
569            }
570        }
571    }
572
573
574    /**
575     * Write seerialized insert data to array
576     *
577     * @param object $a_table
578     * @param object $a_basedir
579     * @return
580     */
581    public function buildInsertStatement($a_table, $a_basedir)
582    {
583        global $DIC;
584        $ilLogger = $DIC->logger()->root();
585
586        $ilLogger->log('Starting export of:' . $a_table);
587
588        $set = $this->il_db->query("SELECT * FROM " . $this->il_db->quoteIdentifier($a_table));
589        $row = 0;
590
591        umask(0000);
592        mkdir($a_basedir . '/' . $a_table . '_inserts', fileperms($a_basedir));
593
594        $filenum = 1;
595        while ($rec = $this->il_db->fetchAssoc($set)) {
596            $values = array();
597            foreach ($rec as $f => $v) {
598                if ($this->fields[$f]['type'] == 'text' and $this->fields[$f]['length'] >= 1000) {
599                    $v = $this->shortenText($a_table, $f, $v, $this->fields[$f]['length']);
600                }
601
602                $values[$f] = array(
603                    $this->fields[$f]['type'],
604                    $v,
605                );
606            }
607
608            $rows[$a_table][$row++] = $values;
609
610            if ($row >= 1000) {
611                $ilLogger->log('Writing insert statements after 1000 lines...');
612                $fp = fopen($a_basedir . '/' . $a_table . '_inserts/' . $filenum++ . '.data', 'w');
613                fwrite($fp, serialize((array) $rows));
614                fclose($fp);
615
616                $row = 0;
617                unset($rows);
618            }
619        }
620        if ($rows) {
621            $fp = fopen($a_basedir . '/' . $a_table . '_inserts/' . $filenum++ . '.data', 'w');
622            fwrite($fp, serialize((array) $rows) . "\n");
623            fclose($fp);
624        }
625
626        $ilLogger->log('Finished export of: ' . $a_table);
627        if (function_exists('memory_get_usage')) {
628            $ilLogger->log('Memory usage: ' . memory_get_usage(true));
629        }
630
631        return true;
632    }
633
634
635    /**
636     *
637     * @param object $a_table
638     * @param object $a_file [optional]
639     * @return
640     */
641    public function buildInsertStatementsXML($a_table, $a_basedir)
642    {
643        include_once './Services/Xml/classes/class.ilXmlWriter.php';
644        $w = new ilXmlWriter();
645        $w->xmlStartTag('Table', array( 'name' => $a_table ));
646
647        $set = $this->il_db->query("SELECT * FROM " . $this->il_db->quoteIdentifier($a_table));
648        $ins_st = "";
649        $first = true;
650        while ($rec = $this->il_db->fetchAssoc($set)) {
651            #$ilLog->write('Num: '.$num++);
652            $w->xmlStartTag('Row');
653
654            $fields = array();
655            $types = array();
656            $values = array();
657            foreach ($rec as $f => $v) {
658                if ($this->fields[$f]['type'] == 'text' and $this->fields[$f]['length'] >= 1000) {
659                    $v = $this->shortenText($a_table, $f, $v, $this->fields[$f]['length']);
660                }
661
662                $w->xmlElement('Value', array(
663                        'name' => $f,
664                        'type' => $this->fields[$f]['type'],
665                    ), $v);
666            }
667
668            $w->xmlEndTag('Row');
669        }
670        $w->xmlEndTag('Table');
671
672        $w->xmlDumpFile($a_basedir . '/' . $a_table . '.xml', false);
673    }
674
675
676    /**
677     * Build Insert statements
678     *
679     * @param    string        table name
680     * @param    file          file resource or empty string
681     */
682    public function buildInsertStatements($a_table, $a_file = "")
683    {
684        if ($a_table == "lng_data") {
685            return;
686        }
687
688        $set = $this->il_db->query("SELECT * FROM " . $this->il_db->quoteIdentifier($a_table));
689        $ins_st = "";
690        $first = true;
691        while ($rec = $this->il_db->fetchAssoc($set)) {
692            $fields = array();
693            $types = array();
694            $values = array();
695            $i_str = array();
696            foreach ($rec as $f => $v) {
697                $fields[] = $f;
698                $types[] = '"' . $this->fields[$f]["type"] . '"';
699                $v = str_replace('\\', '\\\\', $v);
700                $values[] = "'" . str_replace("'", "\'", $v) . "'";
701                $i_str[] = "'" . $f . "' => array('" . $this->fields[$f]["type"] . "', '" . str_replace("'", "\'", $v) . "')";
702            }
703            $fields_str = "(" . implode(",", $fields) . ")";
704            $types_str = "array(" . implode(",", $types) . ")";
705            $values_str = "array(" . implode(",", $values) . ")";
706            $ins_st = "\n" . '$ilDB->insert("' . $a_table . '", array(' . "\n";
707            $ins_st .= implode(", ", $i_str) . "));\n";
708            //$ins_st.= "\t".$fields_str."\n";
709            //$ins_st.= "\t".'VALUES '."(%s".str_repeat(",%s", count($fields) - 1).')"'.",\n";
710            //$ins_st.= "\t".$types_str.','.$values_str.');'."\n";
711
712            if ($a_file == "") {
713                echo $ins_st;
714            } else {
715                fwrite($a_file, $ins_st);
716            }
717            $ins_st = "";
718        }
719    }
720
721
722    /**
723     * Get table definition overview in HTML
724     *
725     * @param    string        output filename, if no filename is given, script is echoed
726     */
727    public function getHTMLOverview($a_filename = "")
728    {
729        $tpl = new ilTemplate("tpl.db_overview.html", true, true, "Services/Database");
730
731        $this->getTables();
732        $cnt = 1;
733        foreach ($this->tables as $table) {
734            if ($this->checkProcessing($table)) {
735                // create table statement
736                if ($this->addTableToOverview($table, $tpl, $cnt)) {
737                    $cnt++;
738                }
739            }
740        }
741
742        $tpl->setVariable("TXT_TITLE", "ILIAS Abstract DB Tables (" . ILIAS_VERSION . ")");
743
744        if ($a_filename == "") {
745            echo $tpl->get();
746        }
747    }
748
749
750    /**
751     * Add table to overview template
752     */
753    public function addTableToOverview($a_table, $a_tpl, $a_cnt)
754    {
755        $fields = $this->analyzer->getFieldInformation($a_table);
756        $indices = $this->analyzer->getIndicesInformation($a_table);
757        $constraints = $this->analyzer->getConstraintsInformation($a_table);
758        $pk = $this->analyzer->getPrimaryKeyInformation($a_table);
759        $auto = $this->analyzer->getAutoIncrementField($a_table);
760        $has_sequence = $this->analyzer->hasSequence($a_table);
761
762        // table filter
763        if (isset($this->filter["has_sequence"])) {
764            if ((!$has_sequence && $auto == "" && $this->filter["has_sequence"])
765                || (($has_sequence || $auto != "") && !$this->filter["has_sequence"])
766            ) {
767                return false;
768            }
769        }
770
771        // indices
772        $indices_output = false;
773        if (is_array($indices) && count($indices) > 0 && !$this->filter["skip_indices"]) {
774            foreach ($indices as $index => $def) {
775                $f2 = array();
776                foreach ($def["fields"] as $f => $pos) {
777                    $f2[] = $f;
778                }
779                $a_tpl->setCurrentBlock("index");
780                $a_tpl->setVariable("VAL_INDEX", $def["name"]);
781                $a_tpl->setVariable("VAL_FIELDS", implode(", ", $f2));
782                $a_tpl->parseCurrentBlock();
783                $indices_output = true;
784            }
785            $a_tpl->setCurrentBlock("index_table");
786            $a_tpl->parseCurrentBlock();
787        }
788
789        // constraints
790        $constraints_output = false;
791        if (is_array($constraints) && count($constraints) > 0 && !$this->filter["skip_constraints"]) {
792            foreach ($constraints as $index => $def) {
793                $f2 = array();
794                foreach ($def["fields"] as $f => $pos) {
795                    $f2[] = $f;
796                }
797                $a_tpl->setCurrentBlock("constraint");
798                $a_tpl->setVariable("VAL_CONSTRAINT", $def["name"]);
799                $a_tpl->setVariable("VAL_CTYPE", $def["type"]);
800                $a_tpl->setVariable("VAL_CFIELDS", implode(", ", $f2));
801                $a_tpl->parseCurrentBlock();
802                $constraints_output = true;
803            }
804            $a_tpl->setCurrentBlock("constraint_table");
805            $a_tpl->parseCurrentBlock();
806        }
807
808        // fields
809        $fields_output = false;
810        foreach ($fields as $field => $def) {
811            // field filter
812            if (isset($this->filter["alt_types"])) {
813                if (($def["alt_types"] == "" && $this->filter["alt_types"])
814                    || ($def["alt_types"] != "" && !$this->filter["alt_types"])
815                ) {
816                    continue;
817                }
818            }
819            if (isset($this->filter["type"])) {
820                if ($def["type"] != $this->filter["type"]) {
821                    continue;
822                }
823            }
824            if (isset($this->filter["nativetype"])) {
825                if ($def["nativetype"] != $this->filter["nativetype"]) {
826                    continue;
827                }
828            }
829            if (isset($this->filter["unsigned"])) {
830                if ($def["unsigned"] != $this->filter["unsigned"]) {
831                    continue;
832                }
833            }
834
835            $a_tpl->setCurrentBlock("field");
836            if (empty($pk["fields"][$field])) {
837                $a_tpl->setVariable("VAL_FIELD", strtolower($field));
838            } else {
839                $a_tpl->setVariable("VAL_FIELD", "<u>" . strtolower($field) . "</u>");
840            }
841            $a_tpl->setVariable("VAL_TYPE", $def["type"]);
842            $a_tpl->setVariable("VAL_LENGTH", (!is_null($def["length"])) ? $def["length"] : "&nbsp;");
843
844            if (strtolower($def["default"]) == "current_timestamp") {
845                //$def["default"] = "0000-00-00 00:00:00";
846                unset($def["default"]);
847            }
848
849            $a_tpl->setVariable("VAL_DEFAULT", (!is_null($def["default"])) ? $def["default"] : "&nbsp;");
850            $a_tpl->setVariable("VAL_NOT_NULL", (!is_null($def["notnull"])) ? (($def["notnull"]) ? "true" : "false") : "&nbsp;");
851            $a_tpl->setVariable("VAL_FIXED", (!is_null($def["fixed"])) ? (($def["fixed"]) ? "true" : "false") : "&nbsp;");
852            $a_tpl->setVariable("VAL_UNSIGNED", (!is_null($def["unsigned"])) ? (($def["unsigned"]) ? "true" : "false") : "&nbsp;");
853            $a_tpl->setVariable("VAL_ALTERNATIVE_TYPES", ($def["alt_types"] != "") ? $def["alt_types"] : "&nbsp;");
854            $a_tpl->setVariable("VAL_NATIVETYPE", ($def["nativetype"] != "") ? $def["nativetype"] : "&nbsp;");
855            $a_tpl->parseCurrentBlock();
856            $fields_output = true;
857        }
858
859        if ($fields_output) {
860            $a_tpl->setCurrentBlock("field_table");
861            $a_tpl->parseCurrentBlock();
862        }
863
864        // table information
865        if ($indices_output || $fields_output || $constraints_output) {
866            $a_tpl->setCurrentBlock("table");
867            $a_tpl->setVariable("TXT_TABLE_NAME", strtolower($a_table));
868            if ($has_sequence || $auto != "") {
869                $a_tpl->setVariable("TXT_SEQUENCE", "Has Sequence");
870            } else {
871                $a_tpl->setVariable("TXT_SEQUENCE", "No Sequence");
872            }
873            $a_tpl->setVariable("VAL_CNT", (int) $a_cnt);
874            $a_tpl->parseCurrentBlock();
875
876            return true;
877        }
878
879        return false;
880    }
881
882
883    /**
884     * Shorten text depending on target encoding
885     *
886     * @param string $table
887     * @param string $field
888     * @param string $a_value
889     * @param int $a_size
890     * @return string
891     */
892    protected function shortenText($table, $field, $a_value, $a_size)
893    {
894        global $DIC;
895        $ilLogger = $DIC->logger()->root();
896
897        if ($this->getTargetEncoding() == 'UTF-8') {
898            return $a_value;
899        }
900        // Convert to target encoding
901        $shortened = mb_convert_encoding($a_value, $this->getTargetEncoding(), 'UTF-8');
902        // Shorten
903        include_once './Services/Utilities/classes/class.ilStr.php';
904        $shortened = ilStr::shortenText($shortened, 0, $a_size, $this->getTargetEncoding());
905        // Convert back to UTF-8
906        $shortened = mb_convert_encoding($shortened, 'UTF-8', $this->getTargetEncoding());
907
908        if (strlen($a_value) != strlen($shortened)) {
909            $ilLogger->log('Table        : ' . $table);
910            $ilLogger->log('Field        : ' . $field);
911            $ilLogger->log('Type         : ' . $this->fields[$field]['type']);
912            $ilLogger->log('Length       : ' . $this->fields[$field]['length']);
913            $ilLogger->log('Before       : ' . $a_value);
914            $ilLogger->log('Shortened    : ' . $shortened);
915            $ilLogger->log('Strlen Before: ' . strlen($a_value));
916            $ilLogger->log('Strlen After : ' . strlen($shortened));
917        }
918
919        return $shortened;
920    }
921}
922