Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   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   * @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   */
  22  
  23  /**
  24   * This class will compare all the indexes found in the XMLDB definitions
  25   * with the physical DB implementation, reporting about all the missing
  26   * indexes to be created to be 100% ok.
  27   *
  28   * @package    tool_xmldb
  29   * @copyright  2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  30   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  31   */
  32  class check_indexes extends XMLDBCheckAction {
  33  
  34      /**
  35       * Init method, every subclass will have its own
  36       */
  37      function init() {
  38          $this->introstr = 'confirmcheckindexes';
  39          parent::init();
  40  
  41          // Set own core attributes
  42  
  43          // Set own custom attributes
  44  
  45          // Get needed strings
  46          $this->loadStrings(array(
  47              'extraindexesfound' => 'tool_xmldb',
  48              'missing' => 'tool_xmldb',
  49              'key' => 'tool_xmldb',
  50              'index' => 'tool_xmldb',
  51              'missingindexes' => 'tool_xmldb',
  52              'nomissingorextraindexesfound' => 'tool_xmldb',
  53              'yesextraindexesfound' => 'tool_xmldb',
  54              'yesmissingindexesfound' => 'tool_xmldb',
  55          ));
  56      }
  57  
  58      protected function check_table(xmldb_table $xmldb_table, array $metacolumns) {
  59          global $DB;
  60          $dbman = $DB->get_manager();
  61  
  62          $o = '';
  63          $dbindexes = $DB->get_indexes($xmldb_table->getName());
  64          $missing_indexes = array();
  65  
  66          // Keys
  67          if ($xmldb_keys = $xmldb_table->getKeys()) {
  68              $o.='        <ul>';
  69              foreach ($xmldb_keys as $xmldb_key) {
  70                  $o.='            <li>' . $this->str['key'] . ': ' . $xmldb_key->readableInfo() . ' ';
  71                  // Primaries are skipped
  72                  if ($xmldb_key->getType() == XMLDB_KEY_PRIMARY) {
  73                      $o.='<font color="green">' . $this->str['ok'] . '</font></li>';
  74                      continue;
  75                  }
  76                  // If we aren't creating the keys or the key is a XMLDB_KEY_FOREIGN (not underlying index generated
  77                  // automatically by the RDBMS) create the underlying (created by us) index (if doesn't exists)
  78                  if (!$dbman->generator->getKeySQL($xmldb_table, $xmldb_key) || $xmldb_key->getType() == XMLDB_KEY_FOREIGN) {
  79                      // Create the interim index
  80                      $xmldb_index = new xmldb_index('anyname');
  81                      $xmldb_index->setFields($xmldb_key->getFields());
  82                      switch ($xmldb_key->getType()) {
  83                          case XMLDB_KEY_UNIQUE:
  84                          case XMLDB_KEY_FOREIGN_UNIQUE:
  85                              $xmldb_index->setUnique(true);
  86                              break;
  87                          case XMLDB_KEY_FOREIGN:
  88                              $xmldb_index->setUnique(false);
  89                              break;
  90                      }
  91                      // Check if the index exists in DB
  92                      if ($dbman->index_exists($xmldb_table, $xmldb_index)) {
  93                          $o.='<font color="green">' . $this->str['ok'] . '</font>';
  94                          $this->remove_index_from_dbindex($dbindexes, $xmldb_index);
  95                      } else {
  96                          $o.='<font color="red">' . $this->str['missing'] . '</font>';
  97                          // Add the missing index to the list
  98                          $obj = new stdClass();
  99                          $obj->table = $xmldb_table;
 100                          $obj->index = $xmldb_index;
 101                          $missing_indexes[] = $obj;
 102                      }
 103                  }
 104                  $o.='</li>';
 105              }
 106              $o.='        </ul>';
 107          }
 108          // Indexes
 109          if ($xmldb_indexes = $xmldb_table->getIndexes()) {
 110              $o.='        <ul>';
 111              foreach ($xmldb_indexes as $xmldb_index) {
 112                  $o.='            <li>' . $this->str['index'] . ': ' . $xmldb_index->readableInfo() . ' ';
 113                  // Check if the index exists in DB
 114                  if ($dbman->index_exists($xmldb_table, $xmldb_index)) {
 115                      $o.='<font color="green">' . $this->str['ok'] . '</font>';
 116                      $this->remove_index_from_dbindex($dbindexes, $xmldb_index);
 117                  } else {
 118                      $o.='<font color="red">' . $this->str['missing'] . '</font>';
 119                      // Add the missing index to the list
 120                      $obj = new stdClass();
 121                      $obj->table = $xmldb_table;
 122                      $obj->index = $xmldb_index;
 123                      $missing_indexes[] = $obj;
 124                  }
 125                  $o.='</li>';
 126              }
 127              $o.='        </ul>';
 128          }
 129  
 130          // Hack - skip for table 'search_simpledb_index' as this plugin adds indexes dynamically on install
 131          // which are not included in install.xml. See search/engine/simpledb/db/install.php.
 132          if ($xmldb_table->getName() != 'search_simpledb_index') {
 133              foreach ($dbindexes as $indexname => $index) {
 134                  $missing_indexes[] = $indexname;
 135              }
 136          }
 137  
 138          return array($o, $missing_indexes);
 139      }
 140  
 141      protected function display_results(array $missing_indexes) {
 142          global $DB;
 143          $dbman = $DB->get_manager();
 144  
 145          $missingindexes = [];
 146          $extraindexes = [];
 147  
 148          foreach ($missing_indexes as $missingindex) {
 149              if (is_object($missingindex)) {
 150                  $missingindexes[] = $missingindex;
 151              } else {
 152                  $extraindexes[] = $missingindex;
 153              }
 154          }
 155  
 156          $s = '';
 157          $r = '<table class="generaltable boxaligncenter boxwidthwide" border="0" cellpadding="5" cellspacing="0" id="results">';
 158          $r.= '  <tr><td class="generalboxcontent">';
 159          $r.= '    <h2 class="main">' . $this->str['searchresults'] . '</h2>';
 160          $r .= '    <p class="centerpara">' . $this->str['missingindexes'] . ': ' . count($missingindexes) . '</p>';
 161          $r .= '    <p class="centerpara">' . $this->str['extraindexesfound'] . ': ' . count($extraindexes) . '</p>';
 162          $r.= '  </td></tr>';
 163          $r.= '  <tr><td class="generalboxcontent">';
 164  
 165          // If we have found missing indexes or extra indexes inform the user about them.
 166          if (!empty($missingindexes) || !empty($extraindexes)) {
 167              if ($missingindexes) {
 168                  $r.= '    <p class="centerpara">' . $this->str['yesmissingindexesfound'] . '</p>';
 169                  $r.= '        <ul>';
 170                  foreach ($missingindexes as $obj) {
 171                      $xmldb_table = $obj->table;
 172                      $xmldb_index = $obj->index;
 173                      $sqlarr = $dbman->generator->getAddIndexSQL($xmldb_table, $xmldb_index);
 174                      $r.= '            <li>' . $this->str['table'] . ': ' . $xmldb_table->getName() . '. ' .
 175                                                $this->str['index'] . ': ' . $xmldb_index->readableInfo() . '</li>';
 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              }
 184              if ($extraindexes) {
 185                  $r .= '<p class="centerpara">' . $this->str['yesextraindexesfound'] . '</p>';
 186                  $r .= '<ul>';
 187                  foreach ($extraindexes as $ei) {
 188                      $r .= '<li>' . $ei . '</li>';
 189                  }
 190                  $r .= '</ul>';
 191                  $r .= '<hr />';
 192              }
 193          } else {
 194              $r .= '<p class="centerpara">' . $this->str['nomissingorextraindexesfound'] . '</p>';
 195          }
 196          $r.= '  </td></tr>';
 197          $r.= '  <tr><td class="generalboxcontent">';
 198          // Add the complete log message
 199          $r.= '    <p class="centerpara">' . $this->str['completelogbelow'] . '</p>';
 200          $r.= '  </td></tr>';
 201          $r.= '</table>';
 202  
 203          return $r;
 204      }
 205  
 206      /**
 207       * Removes an index from the array $dbindexes if it is found.
 208       *
 209       * @param array $dbindexes
 210       * @param xmldb_index $index
 211       */
 212      private function remove_index_from_dbindex(array &$dbindexes, xmldb_index $index) {
 213          foreach ($dbindexes as $key => $dbindex) {
 214              if ($dbindex['columns'] == $index->getFields()) {
 215                  unset($dbindexes[$key]);
 216              }
 217          }
 218      }
 219  }