. * * @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); } }