Skip to content

Commit

Permalink
Update db replace to replace strings in PHP
Browse files Browse the repository at this point in the history
  • Loading branch information
petersistrom authored and brendanheywood committed Dec 11, 2024
1 parent 88f33f9 commit 7135475
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 60 deletions.
95 changes: 36 additions & 59 deletions classes/helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -276,10 +276,10 @@ private static function build_search_query(db_search $search, string $table, dat

static $supportedtablemappings = [
'course_sections' => ['t.id as id, section', ''],
'book_chapters' => ['t.bookid as id, t.id as chapterid,', 'LEFT JOIN {book} t2 ON t.bookid = t2.id'],
'book_chapters' => ['t.bookid as moduleid, t.id as id,', 'LEFT JOIN {book} t2 ON t.bookid = t2.id'],
'forum_posts' => ['t.id as id,', 'LEFT JOIN {forum_discussions} t2 ON t.discussion = t2.id
LEFT JOIN {forum} f ON t2.forum = f.id'],
'lesson_pages' => ['t.lessonid as id, t.id as pageid,', 'LEFT JOIN {lesson} t2 ON t.lessonid = t2.id'],
'lesson_pages' => ['t.lessonid as moduleid, t.id as id,', 'LEFT JOIN {lesson} t2 ON t.lessonid = t2.id'],
];

$regex = $search->get('regex');
Expand Down Expand Up @@ -606,14 +606,14 @@ public static function find_link_function($table, $column) {
foreach ($modules as $module) {
$modulefunctions[$module->name] = function($record) use ($module) {
global $DB;
$coursemodule = $DB->get_record('course_modules', ['module' => $module->id, 'instance' => $record->id], 'id');
$coursemodule = $DB->get_record('course_modules', ['module' => $module->id, 'instance' => ($record->moduleid ?? $record->id)], 'id');
if (empty($coursemodule)) {
return null;
} else if ($module->name == 'book' && isset($record->chapterid)) {
$url = new \moodle_url("/mod/{$module->name}/view.php", ['id' => $coursemodule->id, 'chapterid' => $record->chapterid]);
} else if ($module->name == 'book' && isset($record->moduleid)) {
$url = new \moodle_url("/mod/{$module->name}/view.php", ['id' => $coursemodule->id, 'chapterid' => $record->id]);
return $url->out(false);
} else if ($module->name == 'lesson' && isset($record->pageid)) {
$url = new \moodle_url("/mod/{$module->name}/view.php", ['id' => $coursemodule->id, 'pageid' => $record->pageid]);
} else if ($module->name == 'lesson' && isset($record->moduleid)) {
$url = new \moodle_url("/mod/{$module->name}/view.php", ['id' => $coursemodule->id, 'pageid' => $record->id]);
return $url->out(false);
} else {
$url = new \moodle_url("/mod/{$module->name}/view.php", ['id' => $coursemodule->id]);
Expand Down Expand Up @@ -657,61 +657,35 @@ public static function find_link_function($table, $column) {
* @param int $id The id of the record to restrict the search.
*/
public static function replace_text_in_a_record(string $table, string $columnname,
string $search, string $replace, int $id) {
string $search, string $replace, int $id) : bool {
global $DB;

$column = self::get_column_info($table, $columnname);
self::replace_all_text($table, $column, $search, $replace, ' AND id = ?', [$id]);
}

/**
* A clone of the core function replace_all_text.
* We have optional id parameter to restrict the search.
*
* @since Moodle 2.6.1
* @param string $table name of the table
* @param database_column_info $column
* @param string $search text to search for
* @param string $replace text to replace with
* @param string $wheresql additional where clause
* @param array $whereparams parameters for the where clause
*/
private static function replace_all_text($table, database_column_info $column, string $search, string $replace,
string $wheresql = '', array $whereparams = []) {
global $DB;
// Enclose the column name by the proper quotes if it's a reserved word.
$columnname = $DB->get_manager()->generator->getEncQuoted($column->name);

$record = $DB->get_record($table, array('id' => $id), $columnname);

if (!$DB->replace_all_text_supported()) {
throw new moodle_exception(get_string('errorreplacetextnotsupported', 'tool_advancedreplace'));
if (!$record) {
mtrace(get_string('errorreplacingstringnorecord', 'tool_advancedreplace',
['id' => $id, 'table' => $table, 'column' => $columnname]));
return false;
}

// Enclose the column name by the proper quotes if it's a reserved word.
$columnname = $DB->get_manager()->generator->getEncQuoted($column->name);
$escapedsearchstring = str_replace("\n", "\r\n", $search);

$searchsql = $DB->sql_like($columnname, '?');
$searchparam = '%'.$DB->sql_like_escape($search).'%';

// Additional where clause.
$searchsql .= $wheresql;
$params = array_merge([$search, $replace, $searchparam], $whereparams);

switch ($column->meta_type) {
case 'C':
if (core_text::strlen($search) < core_text::strlen($replace)) {
$colsize = $column->max_length;
$sql = "UPDATE {".$table."}
SET $columnname = " . $DB->sql_substr("REPLACE(" . $columnname . ", ?, ?)", 1, $colsize) . "
WHERE $searchsql";
break;
}
// Otherwise, do not break and use the same query as in the 'X' case.
case 'X':
$sql = "UPDATE {".$table."}
SET $columnname = REPLACE($columnname, ?, ?)
WHERE $searchsql";
break;
default:
throw new moodle_exception(get_string('errorcolumntypenotsupported', 'tool_advancedreplace'));
}
$DB->execute($sql, $params);
if (str_contains($record->$columnname, $search)) {
$newstring = str_replace($search, $replace, $record->$columnname);
return $DB->set_field($table, $columnname, $newstring, array('id' => $id));
} else if (str_contains($record->$columnname, $escapedsearchstring)) {
$newstring = str_replace($escapedsearchstring, $replace, $record->$columnname);
return $DB->set_field($table, $columnname, $newstring, array('id' => $id));
} else {
mtrace(get_string('errorreplacingstring', 'tool_advancedreplace',
['id' => $id, 'table' => $table, 'column' => $columnname]));
return false;
}
}

/**
Expand Down Expand Up @@ -809,14 +783,17 @@ public static function handle_replace_csv(string $data, string $type = 'db') {
$csvimport->init();
$rowcount = 0;
$rowskip = 0;
$rowerror = 0;
while ($record = $csvimport->next()) {
if (empty($record[$replaceindex])) {
// Skip if 'replace' is empty.
$rowskip++;
} else if ($type == 'db') {
// Replace the string.
self::replace_text_in_a_record($record[$tableindex], $record[$columnindex],
$record[$matchindex], $record[$replaceindex], $record[$idindex]);
if (!self::replace_text_in_a_record($record[$tableindex], $record[$columnindex],
$record[$matchindex], $record[$replaceindex], $record[$idindex])) {
$rowerror++;
}
} else if ($type == 'files') {
$filerecord = [
'contextid' => $record[$contextidindex],
Expand All @@ -836,11 +813,11 @@ public static function handle_replace_csv(string $data, string $type = 'db') {

// Update the progress bar.
$rowcount++;
$progress->update_full(100 * $rowcount / $contentcount, "Processed $rowcount records. Skipped $rowskip records.");
$progress->update_full(100 * $rowcount / $contentcount, "Processed $rowcount records. Skipped $rowskip records. Error replacing $rowerror records.");
}

// Show progress.
$progress->update_full('100', "Processed $rowcount records. Skipped $rowskip records.");
$progress->update_full('100', "Processed $rowcount records. Skipped $rowskip records. Error replacing $rowerror records.");

$csvimport->cleanup();
$csvimport->close();
Expand Down
3 changes: 2 additions & 1 deletion lang/en/tool_advancedreplace.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
$string['errorinvalidparam'] = 'Invalid parameter.';
$string['errormissingfields'] = 'The following fields are missing: {$a}';
$string['errorregexnotsupported'] = 'Regular expression searches are not supported by this database.';
$string['errorreplacetextnotsupported'] = 'Replace all text is not supported by this database.';
$string['errorreplacingstring'] = 'Skipped record -> Table: [{$a->table}] id: [{$a->id}] column: [{$a->column}] Search string does not match database entry.';
$string['errorreplacingstringnorecord'] = 'Skipped record does not exist in database -> Table: [{$a->table}] id: [{$a->id}] column: [{$a->column}].';
$string['errorsearchmethod'] = 'Please choose one of the search methods: plain text or regular expression.';
$string['errorreplacingfile'] = 'Error replacing string: [{$a->replace}] in file: [{$a->filename}]';
$string['errorreplacingfilenotfound'] = 'Error replacing string, file: [{$a->filename}] no found';
Expand Down

0 comments on commit 7135475

Please sign in to comment.