joomla_test/libraries/cms/schema/changeset.php

277 lines
6.3 KiB
PHP
Raw Normal View History

2020-01-02 22:20:31 +07:00
<?php
/**
* @package Joomla.Libraries
* @subpackage Schema
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
defined('JPATH_PLATFORM') or die;
jimport('joomla.filesystem.folder');
/**
* Contains a set of JSchemaChange objects for a particular instance of Joomla.
* Each of these objects contains a DDL query that should have been run against
* the database when this database was created or updated. This enables the
* Installation Manager to check that the current database schema is up to date.
*
* @package Joomla.Libraries
* @subpackage Schema
* @since 2.5
*/
class JSchemaChangeset
{
/**
* Array of JSchemaChangeitem objects
*
* @var array
* @since 2.5
*/
protected $changeItems = array();
/**
* JDatabaseDriver object
*
* @var JDatabaseDriver
* @since 2.5
*/
protected $db = null;
/**
* Folder where SQL update files will be found
*
* @var string
*/
protected $folder = null;
/**
* Constructor: builds array of $changeItems by processing the .sql files in a folder.
* The folder for the Joomla core updates is administrator/components/com_admin/sql/updates/<database>.
*
* @param JDatabaseDriver $db The current database object
* @param string $folder The full path to the folder containing the update queries
*
* @since 2.5
*/
public function __construct($db, $folder = null)
{
$this->db = $db;
$this->folder = $folder;
$updateFiles = $this->getUpdateFiles();
$updateQueries = $this->getUpdateQueries($updateFiles);
foreach ($updateQueries as $obj)
{
$this->changeItems[] = JSchemaChangeitem::getInstance($db, $obj->file, $obj->updateQuery);
}
}
/**
* Returns a reference to the JSchemaChangeset object, only creating it if it doesn't already exist.
*
* @param JDatabaseDriver $db The current database object
* @param string $folder The full path to the folder containing the update queries
*
* @return JSchemaChangeset
*
* @since 2.5
*/
public static function getInstance($db, $folder)
{
static $instance;
if (!is_object($instance))
{
$instance = new JSchemaChangeset($db, $folder);
}
return $instance;
}
/**
* Checks the database and returns an array of any errors found.
* Note these are not database errors but rather situations where
* the current schema is not up to date.
*
* @return array Array of errors if any.
*
* @since 2.5
*/
public function check()
{
$errors = array();
foreach ($this->changeItems as $item)
{
if ($item->check() === -2)
{
// Error found
$errors[] = $item;
}
}
return $errors;
}
/**
* Runs the update query to apply the change to the database
*
* @return void
*
* @since 2.5
*/
public function fix()
{
$this->check();
foreach ($this->changeItems as $item)
{
$item->fix();
}
}
/**
* Returns an array of results for this set
*
* @return array associative array of changeitems grouped by unchecked, ok, error, and skipped
*
* @since 2.5
*/
public function getStatus()
{
$result = array('unchecked' => array(), 'ok' => array(), 'error' => array(), 'skipped' => array());
foreach ($this->changeItems as $item)
{
switch ($item->checkStatus)
{
case 0:
$result['unchecked'][] = $item;
break;
case 1:
$result['ok'][] = $item;
break;
case -2:
$result['error'][] = $item;
break;
case -1:
$result['skipped'][] = $item;
break;
}
}
return $result;
}
/**
* Gets the current database schema, based on the highest version number.
* Note that the .sql files are named based on the version and date, so
* the file name of the last file should match the database schema version
* in the #__schemas table.
*
* @return string the schema version for the database
*
* @since 2.5
*/
public function getSchema()
{
$updateFiles = $this->getUpdateFiles();
$result = new SplFileInfo(array_pop($updateFiles));
return $result->getBasename('.sql');
}
/**
* Get list of SQL update files for this database
*
* @return array list of sql update full-path names
*
* @since 2.5
*/
private function getUpdateFiles()
{
// Get the folder from the database name
$sqlFolder = $this->db->name;
if ($sqlFolder == 'mysqli')
{
$sqlFolder = 'mysql';
}
elseif ($sqlFolder == 'sqlsrv')
{
$sqlFolder = 'sqlazure';
}
// Default folder to core com_admin
if (!$this->folder)
{
$this->folder = JPATH_ADMINISTRATOR . '/components/com_admin/sql/updates/';
}
return JFolder::files(
$this->folder . '/' . $sqlFolder, '\.sql$', 1, true, array('.svn', 'CVS', '.DS_Store', '__MACOSX'), array('^\..*', '.*~'), true
);
}
/**
* Get array of SQL queries
*
* @param array $sqlfiles Array of .sql update filenames.
*
* @return array Array of stdClass objects where:
* file=filename,
* update_query = text of SQL update query
*
* @since 2.5
*/
private function getUpdateQueries(array $sqlfiles)
{
// Hold results as array of objects
$result = array();
foreach ($sqlfiles as $file)
{
$buffer = file_get_contents($file);
// Create an array of queries from the sql file
$queries = JDatabaseDriver::splitSql($buffer);
foreach ($queries as $query)
{
if ($trimmedQuery = $this->trimQuery($query))
{
$fileQueries = new stdClass;
$fileQueries->file = $file;
$fileQueries->updateQuery = $trimmedQuery;
$result[] = $fileQueries;
}
}
}
return $result;
}
/**
* Trim comment and blank lines out of a query string
*
* @param string $query query string to be trimmed
*
* @return string String with leading comment lines removed
*
* @since 3.1
*/
private function trimQuery($query)
{
$query = trim($query);
while (substr($query, 0, 1) == '#' || substr($query, 0, 2) == '--' || substr($query, 0, 2) == '/*')
{
$endChars = (substr($query, 0, 1) == '#' || substr($query, 0, 2) == '--') ? "\n" : "*/";
if ($position = strpos($query, $endChars))
{
$query = trim(substr($query, $position + strlen($endChars)));
}
else
{
// If no newline, the rest of the file is a comment, so return an empty string.
return '';
}
}
return trim($query);
}
}