MDL-63252 tool_xmldb: convert default to float to avoid false positives
[moodle.git] / admin / tool / xmldb / actions / check_defaults / check_defaults.class.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * @package    tool_xmldb
19  * @copyright  2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
20  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
21  */
23 defined('MOODLE_INTERNAL') || die();
25 /**
26  * This class will check all the default values existing in the DB
27  * match those specified in the xml specs
28  * and providing one SQL script to fix all them.
29  *
30  * @package    tool_xmldb
31  * @copyright  2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
32  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33  */
34 class check_defaults extends XMLDBCheckAction {
36     /**
37      * Init method, every subclass will have its own
38      */
39     public function init() {
40         $this->introstr = 'confirmcheckdefaults';
41         parent::init();
43         // Set own core attributes.
45         // Set own custom attributes.
47         // Get needed strings.
48         $this->loadStrings(array(
49             'wrongdefaults' => 'tool_xmldb',
50             'nowrongdefaultsfound' => 'tool_xmldb',
51             'yeswrongdefaultsfound' => 'tool_xmldb',
52             'expected' => 'tool_xmldb',
53             'actual' => 'tool_xmldb',
54         ));
55     }
57     protected function check_table(xmldb_table $xmldbtable, array $metacolumns) {
58         $o = '';
59         $wrongfields = array();
61         // Get and process XMLDB fields.
62         if ($xmldbfields = $xmldbtable->getFields()) {
63             $o .= '        <ul>';
64             foreach ($xmldbfields as $xmldbfield) {
66                 // Get the default value for the field.
67                 $xmldbdefault = $xmldbfield->getDefault();
69                 // Char fields with not null currently have default '' when actually installed.
70                 if ($xmldbdefault === null && $xmldbfield->getType() === XMLDB_TYPE_CHAR &&
71                         $xmldbfield->getNotNull()) {
72                     $xmldbdefault = '';
73                 }
74                 if ($xmldbdefault !== null) {
75                     $xmldbdefault = (string)$xmldbdefault;
76                 }
78                 // If the metadata for that column doesn't exist or 'id' field found, skip.
79                 if (!isset($metacolumns[$xmldbfield->getName()]) or $xmldbfield->getName() == 'id') {
80                     continue;
81                 }
83                 // To variable for better handling.
84                 $metacolumn = $metacolumns[$xmldbfield->getName()];
86                 // Going to check this field in DB.
87                 $o .= '            <li>' . $this->str['field'] . ': ' . $xmldbfield->getName() . ' ';
89                 // Get the value of the physical default (or blank if there isn't one).
90                 if ($metacolumn->has_default == 1) {
91                     $physicaldefault = $metacolumn->default_value;
92                 } else {
93                     $physicaldefault = null;
94                 }
96                 // For number fields there are issues with type differences, so let's convert
97                 // everything to a float.
98                 if ($xmldbfield->getType() === XMLDB_TYPE_NUMBER) {
99                     if ($physicaldefault !== null) {
100                         $physicaldefault = (float) $physicaldefault;
101                     }
102                     if ($xmldbdefault !== null) {
103                         $xmldbdefault = (float) $xmldbdefault;
104                     }
105                 }
107                 // There *is* a default and it's wrong.
108                 if ($physicaldefault !== $xmldbdefault) {
109                     $xmldbtext = self::display_default($xmldbdefault);
110                     $physicaltext = self::display_default($physicaldefault);
111                     $info = "({$this->str['expected']} {$xmldbtext}, {$this->str['actual']} {$physicaltext})";
112                     $o .= '<font color="red">' . $this->str['wrong'] . " $info</font>";
113                     // Add the wrong field to the list.
114                     $obj = new stdClass();
115                     $obj->table = $xmldbtable;
116                     $obj->field = $xmldbfield;
117                     $obj->physicaldefault = $physicaldefault;
118                     $obj->xmldbdefault = $xmldbdefault;
119                     $wrongfields[] = $obj;
120                 } else {
121                     $o .= '<font color="green">' . $this->str['ok'] . '</font>';
122                 }
123                 $o .= '</li>';
124             }
125             $o .= '        </ul>';
126         }
128         return array($o, $wrongfields);
129     }
131     /**
132      * Converts a default value suitable for display.
133      *
134      * @param string|null $defaultvalue Default value
135      * @return string Displayed version
136      */
137     protected static function display_default($defaultvalue) {
138         if ($defaultvalue === null) {
139             return '-';
140         } else {
141             return "'" . s($defaultvalue) . "'";
142         }
143     }
145     protected function display_results(array $wrongfields) {
146         global $DB;
147         $dbman = $DB->get_manager();
149         $s = '';
150         $r = '<table class="generaltable boxaligncenter boxwidthwide" border="0" cellpadding="5" cellspacing="0" id="results">';
151         $r .= '  <tr><td class="generalboxcontent">';
152         $r .= '    <h2 class="main">' . $this->str['searchresults'] . '</h2>';
153         $r .= '    <p class="centerpara">' . $this->str['wrongdefaults'] . ': ' . count($wrongfields) . '</p>';
154         $r .= '  </td></tr>';
155         $r .= '  <tr><td class="generalboxcontent">';
157         // If we have found wrong defaults inform about them.
158         if (count($wrongfields)) {
159             $r .= '    <p class="centerpara">' . $this->str['yeswrongdefaultsfound'] . '</p>';
160             $r .= '        <ul>';
161             foreach ($wrongfields as $obj) {
162                 $xmldbtable = $obj->table;
163                 $xmldbfield = $obj->field;
164                 $physicaltext = self::display_default($obj->physicaldefault);
165                 $xmldbtext = self::display_default($obj->xmldbdefault);
167                 // Get the alter table command.
168                 $sqlarr = $dbman->generator->getAlterFieldSQL($xmldbtable, $xmldbfield);
170                 $r .= '            <li>' . $this->str['table'] . ': ' . $xmldbtable->getName() . '. ' .
171                         $this->str['field'] . ': ' . $xmldbfield->getName() . ', ' .
172                         $this->str['expected'] . ' ' . $xmldbtext . ' ' .
173                         $this->str['actual'] . ' ' . $physicaltext . '</li>';
174                 // Add to output if we have sentences.
175                 if ($sqlarr) {
176                     $sqlarr = $dbman->generator->getEndedStatements($sqlarr);
177                     $s .= '<code>' . str_replace("\n", '<br />', implode('<br />', $sqlarr)) . '</code><br />';
178                 }
179             }
180             $r .= '        </ul>';
181             // Add the SQL statements (all together).
182             $r .= '<hr />' . $s;
183         } else {
184             $r .= '    <p class="centerpara">' . $this->str['nowrongdefaultsfound'] . '</p>';
185         }
186         $r .= '  </td></tr>';
187         $r .= '  <tr><td class="generalboxcontent">';
188         // Add the complete log message.
189         $r .= '    <p class="centerpara">' . $this->str['completelogbelow'] . '</p>';
190         $r .= '  </td></tr>';
191         $r .= '</table>';
193         return $r;
194     }