Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
issue #152 - support any Moodle DB
* lib/mergeusertool.php:
   * revisited to clean SQLs for db-based queries
   * simplified settings management
   * removed warning on duplicated entries on grade items
* .travis.yml:
   * updated to latest version of moodle-plugin-ci projecte (renamed)
   * optimized to use specific service versions on every Travis matrix
* lang/en/tool_mergeusers.php:
   * remove unused string
  • Loading branch information
jpahullo committed Aug 14, 2019
1 parent 7f7a6ce commit e6bd107
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 108 deletions.
51 changes: 36 additions & 15 deletions .travis.yml
@@ -1,37 +1,58 @@
language: php

sudo: required
sudo: true

addons:
firefox: "47.0.1"
postgresql: "9.3"
apt:
packages:
- oracle-java8-installer
- oracle-java8-set-default
- openjdk-8-jre-headless

cache:
directories:
- $HOME/.composer/cache
- $HOME/.npm

php:
- 7.0
- 7.1

env:
global:
- MOODLE_BRANCH=MOODLE_34_STABLE
matrix:
- DB=pgsql
- DB=mysqli
# Alternate tests - 3.4 -> master on mysql/postgres and php.
matrix:
include:
- php: 7.0
env: DB=pgsql MOODLE_BRANCH=MOODLE_34_STABLE
services: postgresql
addons:
- postgresql: "9.4"
- php: 7.0
env: DB=mysqli MOODLE_BRANCH=MOODLE_35_STABLE
services: mysql
addons:
- mysql: "5.7"
- php: 7.2
env: DB=pgsql MOODLE_BRANCH=MOODLE_36_STABLE
services: postgresql
addons:
- postgresql: "9.4"
- php: 7.2
env: DB=mysqli MOODLE_BRANCH=MOODLE_37_STABLE
services: mysql
addons:
- mysql: "5.7"
- php: 7.3
env: DB=pgsql MOODLE_BRANCH=MOODLE_37_STABLE
services: postgresql
addons:
- postgresql: "9.4"
- php: 7.3
env: DB=pgsql MOODLE_BRANCH=master
services: postgresql
addons:
- postgresql: "9.4"

before_install:
- phpenv config-rm xdebug.ini
- nvm install 8.9
- nvm use 8.9
- cd ../..
- composer create-project -n --no-dev --prefer-dist moodlerooms/moodle-plugin-ci ci ^2
- composer create-project -n --no-dev --prefer-dist blackboard-open-source/moodle-plugin-ci ci ^2
- export PATH="$(cd ci/bin; pwd):$(cd ci/vendor/bin; pwd):$PATH"

install:
Expand Down
1 change: 0 additions & 1 deletion lang/en/tool_mergeusers.php
Expand Up @@ -46,7 +46,6 @@
to that problem, repeat the merging action to complete it with success.';
$string['tableskipped'] = 'For logging or security reasons we are skipping <strong>{$a}</strong>.
<br />To remove these entries, delete the old user once this script has run successfully.';
$string['errordatabase'] = 'Error: Database type {$a} not supported.';
$string['invaliduser'] = 'Invalid user';
$string['cligathering:description'] = "Introduce pairs of user's id to merge the first one into the\n
second one. The first user id (fromid) will 'lose' all its data to be 'migrated'\n
Expand Down
122 changes: 30 additions & 92 deletions lib/mergeusertool.php
Expand Up @@ -55,12 +55,6 @@
*/
class MergeUserTool
{

/**
* @var bool true if current database is supported; false otherwise.
*/
protected $supportedDatabase;

/**
* @var array associative array showing the user-related fields per database table,
* without the $CFG->prefix on each.
Expand Down Expand Up @@ -129,35 +123,13 @@ class MergeUserTool
*/
public function __construct(tool_mergeusers_config $config = null, tool_mergeusers_logger $logger = null)
{
global $CFG;

$this->logger = (is_null($logger)) ? new tool_mergeusers_logger() : $logger;
$config = (is_null($config)) ? tool_mergeusers_config::instance() : $config;
$this->supportedDatabase = true;

$this->checkTransactionSupport();

switch ($CFG->dbtype) {
case 'sqlsrv':
case 'mssql':
$this->sqlListTables = "SELECT name FROM sys.Tables WHERE name LIKE '" .
$CFG->prefix . "%' AND type = 'U' ORDER BY name";
break;
case 'mysqli':
case 'mariadb':
$this->sqlListTables = "SHOW TABLES like '" . $CFG->prefix . "%'";
break;
case 'pgsql':
$this->sqlListTables = "SELECT table_name FROM information_schema.tables WHERE table_name LIKE '" .
$CFG->prefix . "%' AND table_schema = 'public'";
break;
default:
$this->supportedDatabase = false;
$this->sqlListTables = "";
}

// these are tables we don't want to modify due to logging or security reasons.
// we flip key<-->value to accelerate lookups.
// These are tables we don't want to modify due to logging or security reasons.
// We flip key<-->value to accelerate lookups.
$this->tablesToSkip = array_flip($config->exceptions);
$excluded = explode(',', get_config('tool_mergeusers', 'excluded_exceptions'));
$excluded = array_flip($excluded);
Expand All @@ -167,16 +139,11 @@ public function __construct(tool_mergeusers_config $config = null, tool_mergeuse
}
}

// these are special cases, corresponding to tables with compound indexes that
// need a special treatment.
// These are special cases, corresponding to tables with compound indexes that need a special treatment.
$this->tablesWithCompoundIndex = $config->compoundindexes;

// Initializes user-related field names.
$userFieldNames = array();
foreach ($config->userfieldnames as $tablename => $fields) {
$userFieldNames[$tablename] = "'" . implode("','", $fields) . "'";
}
$this->userFieldNames = $userFieldNames;
$this->userFieldNames = $config->userfieldnames;

// Load available TableMerger tools.
$tableMergers = array();
Expand All @@ -194,7 +161,7 @@ public function __construct(tool_mergeusers_config $config = null, tool_mergeuse
new moodle_url('/admin/tool/mergeusers/index.php'), $class);
}
}
// append any additional table to skip.
// Append any additional table to skip.
$tablesProcessedByTableMergers = array_merge($tablesProcessedByTableMergers, $tm->getTablesToSkip());
$tableMergers[$tableName] = $tm;
}
Expand All @@ -204,11 +171,7 @@ public function __construct(tool_mergeusers_config $config = null, tool_mergeuse
$this->alwaysRollback = !empty($config->alwaysRollback);
$this->debugdb = !empty($config->debugdb);

// this will abort execution if local database is not supported.
$this->checkDatabaseSupport();

// initializes the list of fields and tables to check in the current database,
// given the local configuration.
// Initializes the list of fields and tables to check in the current database, given the local configuration.
$this->init();
}

Expand Down Expand Up @@ -258,14 +221,9 @@ public function merge($toid, $fromid)
*/
private function _merge($toid, $fromid)
{
global $CFG, $DB;
global $DB;

// initial checks.
// database type is supported?
if (!$this->supportedDatabase) {
return array(false, array(get_string('errordatabase', 'tool_mergeusers', $CFG->dbtype)));
}

// are they the same?
if ($fromid == $toid) {
// yes. do nothing.
Expand Down Expand Up @@ -366,27 +324,26 @@ private function _merge($toid, $fromid)
*/
private function init()
{
global $CFG, $DB;
global $DB;

$userFieldsPerTable = array();

$tableNames = $DB->get_records_sql($this->sqlListTables);
$prefixLength = strlen($CFG->prefix);
// Name of tables comes without db prefix.
$tableNames = $DB->get_tables(false);

foreach ($tableNames as $fullTableName => $toIgnore) {
foreach ($tableNames as $tableName) {

if (!trim($fullTableName)) {
//This section should never be executed due to the way Moodle returns its resultsets
// Skipping due to blank table name
if (!trim($tableName)) {
// This section should never be executed due to the way Moodle returns its resultsets.
// Skipping due to blank table name.
continue;
} else {
$tableName = substr($fullTableName, $prefixLength);
// table specified to be excluded.
// Table specified to be excluded.
if (isset($this->tablesToSkip[$tableName])) {
$this->tablesSkipped[$tableName] = $fullTableName;
$this->tablesSkipped[$tableName] = $tableName;
continue;
}
// table specified to be processed additionally by a TableMerger.
// Table specified to be processed additionally by a TableMerger.
if (isset($this->tablesProcessedByTableMergers[$tableName])) {
continue;
}
Expand All @@ -397,10 +354,11 @@ private function init()
$this->userFieldNames[$tableName] :
$this->userFieldNames['default'];

$currentFields = $this->getCurrentUserFieldNames($fullTableName, $userFields);
$arrayUserFields = array_flip($userFields);
$currentFields = $this->getCurrentUserFieldNames($tableName, $arrayUserFields);

if ($currentFields !== false) {
$userFieldsPerTable[$tableName] = array_values($currentFields);
$userFieldsPerTable[$tableName] = $currentFields;
}
}

Expand Down Expand Up @@ -436,25 +394,6 @@ private function init()
$this->tablesWithCompoundIndex = $existingCompoundIndexes;
}

/**
* Check whether current Moodle's database type is supported.
* If it is not supported, it aborts the execution with an error message, checking whether
* it is on a CLI script or on web.
*/
private function checkDatabaseSupport()
{
global $CFG;

if (!$this->supportedDatabase) {
if (CLI_SCRIPT) {
cli_error('Error: ' . __METHOD__ . ':: ' . get_string('errordatabase', 'tool_mergeusers', $CFG->dbtype));
} else {
print_error('errordatabase', 'tool_mergeusers', new moodle_url('/admin/tool/mergeusers/index.php'),
$CFG->dbtype);
}
}
}

/**
* Checks whether the current database supports transactions.
* If settings of this plugin are set up to allow only transactions,
Expand Down Expand Up @@ -492,16 +431,15 @@ public function checkTransactionSupport()
*/
private function getCurrentUserFieldNames($tableName, $userFields)
{
global $CFG, $DB;
return $DB->get_fieldset_sql("
SELECT DISTINCT column_name
FROM
INFORMATION_SCHEMA.Columns
WHERE
TABLE_NAME = ? AND
(TABLE_SCHEMA = ? OR TABLE_CATALOG=?) AND
COLUMN_NAME IN (" . $userFields . ")",
array($tableName, $CFG->dbname, $CFG->dbname));
global $DB;
$columns = $DB->get_columns($tableName,false);
$usercolumns = [];
foreach($columns as $column) {
if (isset($userFields[$column->name])) {
$usercolumns[$column->name] = $column->name;
}
}
return $usercolumns;
}

/**
Expand All @@ -512,7 +450,7 @@ private function updateGrades($toid, $fromid) {
global $DB, $CFG;
require_once($CFG->libdir.'/gradelib.php');

$sql = "SELECT iteminstance, itemmodule, courseid
$sql = "SELECT DISTINCT gi.iteminstance, gi.itemmodule, gi.courseid
FROM {grade_grades} gg
INNER JOIN {grade_items} gi on gg.itemid = gi.id
WHERE itemtype = 'mod' AND (gg.userid = :toid OR gg.userid = :fromid)";
Expand Down

0 comments on commit e6bd107

Please sign in to comment.