[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/src/Schema/ -> ChangeSet.php (source)

   1  <?php
   2  
   3  /**
   4   * Joomla! Content Management System
   5   *
   6   * @copyright  (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
   7   * @license    GNU General Public License version 2 or later; see LICENSE.txt
   8   */
   9  
  10  namespace Joomla\CMS\Schema;
  11  
  12  use Joomla\CMS\Filesystem\Folder;
  13  use Joomla\Database\DatabaseDriver;
  14  
  15  // phpcs:disable PSR1.Files.SideEffects
  16  \defined('JPATH_PLATFORM') or die;
  17  // phpcs:enable PSR1.Files.SideEffects
  18  
  19  /**
  20   * Contains a set of JSchemaChange objects for a particular instance of Joomla.
  21   * Each of these objects contains a DDL query that should have been run against
  22   * the database when this database was created or updated. This enables the
  23   * Installation Manager to check that the current database schema is up to date.
  24   *
  25   * @since  2.5
  26   */
  27  class ChangeSet
  28  {
  29      /**
  30       * Array of ChangeItem objects
  31       *
  32       * @var    ChangeItem[]
  33       * @since  2.5
  34       */
  35      protected $changeItems = array();
  36  
  37      /**
  38       * DatabaseDriver object
  39       *
  40       * @var    DatabaseDriver
  41       * @since  2.5
  42       */
  43      protected $db = null;
  44  
  45      /**
  46       * Folder where SQL update files will be found
  47       *
  48       * @var    string
  49       * @since  2.5
  50       */
  51      protected $folder = null;
  52  
  53      /**
  54       * The singleton instance of this object
  55       *
  56       * @var    ChangeSet
  57       * @since  3.5.1
  58       */
  59      protected static $instance;
  60  
  61      /**
  62       * Constructor: builds array of $changeItems by processing the .sql files in a folder.
  63       * The folder for the Joomla core updates is `administrator/components/com_admin/sql/updates/<database>`.
  64       *
  65       * @param   DatabaseDriver  $db      The current database object
  66       * @param   string          $folder  The full path to the folder containing the update queries
  67       *
  68       * @since   2.5
  69       */
  70      public function __construct($db, $folder = null)
  71      {
  72          $this->db = $db;
  73          $this->folder = $folder;
  74          $updateFiles = $this->getUpdateFiles();
  75  
  76          // If no files were found nothing more we can do - continue
  77          if ($updateFiles === false) {
  78              return;
  79          }
  80  
  81          $updateQueries = $this->getUpdateQueries($updateFiles);
  82  
  83          foreach ($updateQueries as $obj) {
  84              $this->changeItems[] = ChangeItem::getInstance($db, $obj->file, $obj->updateQuery);
  85          }
  86  
  87          // If on mysql, add a query at the end to check for utf8mb4 conversion status
  88          if ($this->db->getServerType() === 'mysql') {
  89              // Check if the #__utf8_conversion table exists
  90              $this->db->setQuery('SHOW TABLES LIKE ' . $this->db->quote($this->db->getPrefix() . 'utf8_conversion'));
  91  
  92              try {
  93                  $rows = $this->db->loadRowList(0);
  94  
  95                  $tableExists = \count($rows);
  96              } catch (\RuntimeException $e) {
  97                  $tableExists = 0;
  98              }
  99  
 100              // If the table exists add a change item for utf8mb4 conversion to the end
 101              if ($tableExists > 0) {
 102                  // Let the update query do nothing
 103                  $tmpSchemaChangeItem = ChangeItem::getInstance(
 104                      $db,
 105                      'database.php',
 106                      'UPDATE ' . $this->db->quoteName('#__utf8_conversion')
 107                      . ' SET ' . $this->db->quoteName('converted') . ' = '
 108                      . $this->db->quoteName('converted') . ';'
 109                  );
 110  
 111                  // Set to not skipped
 112                  $tmpSchemaChangeItem->checkStatus = 0;
 113  
 114                  // Set the check query
 115                  $tmpSchemaChangeItem->queryType = 'UTF8_CONVERSION_UTF8MB4';
 116  
 117                  $tmpSchemaChangeItem->checkQuery = 'SELECT '
 118                      . $this->db->quoteName('converted')
 119                      . ' FROM ' . $this->db->quoteName('#__utf8_conversion')
 120                      . ' WHERE ' . $this->db->quoteName('converted') . ' = 5';
 121  
 122                  // Set expected records from check query
 123                  $tmpSchemaChangeItem->checkQueryExpected = 1;
 124  
 125                  $tmpSchemaChangeItem->msgElements = array();
 126  
 127                  $this->changeItems[] = $tmpSchemaChangeItem;
 128              }
 129          }
 130      }
 131  
 132      /**
 133       * Returns a reference to the ChangeSet object, only creating it if it doesn't already exist.
 134       *
 135       * @param   DatabaseDriver  $db      The current database object
 136       * @param   string          $folder  The full path to the folder containing the update queries
 137       *
 138       * @return  ChangeSet
 139       *
 140       * @since   2.5
 141       */
 142      public static function getInstance($db, $folder = null)
 143      {
 144          if (!\is_object(static::$instance)) {
 145              static::$instance = new static($db, $folder);
 146          }
 147  
 148          return static::$instance;
 149      }
 150  
 151      /**
 152       * Checks the database and returns an array of any errors found.
 153       * Note these are not database errors but rather situations where
 154       * the current schema is not up to date.
 155       *
 156       * @return   array Array of errors if any.
 157       *
 158       * @since    2.5
 159       */
 160      public function check()
 161      {
 162          $errors = array();
 163  
 164          foreach ($this->changeItems as $item) {
 165              if ($item->check() === -2) {
 166                  // Error found
 167                  $errors[] = $item;
 168              }
 169          }
 170  
 171          return $errors;
 172      }
 173  
 174      /**
 175       * Runs the update query to apply the change to the database
 176       *
 177       * @return  void
 178       *
 179       * @since   2.5
 180       */
 181      public function fix()
 182      {
 183          $this->check();
 184  
 185          foreach ($this->changeItems as $item) {
 186              $item->fix();
 187          }
 188      }
 189  
 190      /**
 191       * Returns an array of results for this set
 192       *
 193       * @return  array  associative array of changeitems grouped by unchecked, ok, error, and skipped
 194       *
 195       * @since   2.5
 196       */
 197      public function getStatus()
 198      {
 199          $result = array('unchecked' => array(), 'ok' => array(), 'error' => array(), 'skipped' => array());
 200  
 201          foreach ($this->changeItems as $item) {
 202              switch ($item->checkStatus) {
 203                  case 0:
 204                      $result['unchecked'][] = $item;
 205                      break;
 206                  case 1:
 207                      $result['ok'][] = $item;
 208                      break;
 209                  case -2:
 210                      $result['error'][] = $item;
 211                      break;
 212                  case -1:
 213                      $result['skipped'][] = $item;
 214                      break;
 215              }
 216          }
 217  
 218          return $result;
 219      }
 220  
 221      /**
 222       * Gets the current database schema, based on the highest version number.
 223       * Note that the .sql files are named based on the version and date, so
 224       * the file name of the last file should match the database schema version
 225       * in the #__schemas table.
 226       *
 227       * @return  string  the schema version for the database
 228       *
 229       * @since   2.5
 230       */
 231      public function getSchema()
 232      {
 233          $updateFiles = $this->getUpdateFiles();
 234  
 235          // No schema files found - abort and return empty string
 236          if (empty($updateFiles)) {
 237              return '';
 238          }
 239  
 240          $result = new \SplFileInfo(array_pop($updateFiles));
 241  
 242          return $result->getBasename('.sql');
 243      }
 244  
 245      /**
 246       * Get list of SQL update files for this database
 247       *
 248       * @return  array|boolean  list of sql update full-path names. False if directory doesn't exist
 249       *
 250       * @since   2.5
 251       */
 252      private function getUpdateFiles()
 253      {
 254          // Get the folder from the database name
 255          $sqlFolder = $this->db->getServerType();
 256  
 257          // For `mssql` server types, convert the type to `sqlazure`
 258          if ($sqlFolder === 'mssql') {
 259              $sqlFolder = 'sqlazure';
 260          }
 261  
 262          // Default folder to core com_admin
 263          if (!$this->folder) {
 264              $this->folder = JPATH_ADMINISTRATOR . '/components/com_admin/sql/updates/';
 265          }
 266  
 267          // We don't want to enqueue an error if the directory doesn't exist - this can be handled elsewhere/
 268          // So bail here.
 269          if (!is_dir($this->folder . '/' . $sqlFolder)) {
 270              return [];
 271          }
 272  
 273          return Folder::files(
 274              $this->folder . '/' . $sqlFolder,
 275              '\.sql$',
 276              1,
 277              true,
 278              array('.svn', 'CVS', '.DS_Store', '__MACOSX'),
 279              array('^\..*', '.*~'),
 280              true
 281          );
 282      }
 283  
 284      /**
 285       * Get array of SQL queries
 286       *
 287       * @param   array  $sqlfiles  Array of .sql update filenames.
 288       *
 289       * @return  array  Array of \stdClass objects where:
 290       *                    file=filename,
 291       *                    update_query = text of SQL update query
 292       *
 293       * @since   2.5
 294       */
 295      private function getUpdateQueries(array $sqlfiles)
 296      {
 297          // Hold results as array of objects
 298          $result = array();
 299  
 300          foreach ($sqlfiles as $file) {
 301              $buffer = file_get_contents($file);
 302  
 303              // Create an array of queries from the sql file
 304              $queries = DatabaseDriver::splitSql($buffer);
 305  
 306              foreach ($queries as $query) {
 307                  $fileQueries = new \stdClass();
 308                  $fileQueries->file = $file;
 309                  $fileQueries->updateQuery = $query;
 310                  $result[] = $fileQueries;
 311              }
 312          }
 313  
 314          return $result;
 315      }
 316  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer