Skip to content
This repository was archived by the owner on Oct 22, 2020. It is now read-only.
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 216 additions & 0 deletions bin/update_fields.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
#!/usr/bin/php
<?php
/*
Updates objects field names

When template fields are modified and their names are changed, objects
based on that template are not automatically updated to take up the
new field names. This script should be used after a template field name
has been modified in order to update objects.

Options:
-c: core
-t: comma separated list of template ids (optional)
-f: field names to update, a comma separated list of
field name changes where each item is a pair of the old and
new field name separated by a full colon (:)
-h --help: prints usage information

Note! if no template id is specifed the updated will be made to ALL objects

Examples:

php update_fields.php -c mycore -t 1123,230 -f age:victim_age,sex:gender
php update_fields.php -c mycore -f name:first_name

After running this script, you should update the solr prepared date and reindex the solr core.


*/

namespace CB;

ini_set('max_execution_time', 0);

// include cron init script
// sets up the environment and also
// the DB based on the selected core
$cronPath = realpath(
dirname(__FILE__) . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'sys' . DIRECTORY_SEPARATOR .
'crons' . DIRECTORY_SEPARATOR
) . DIRECTORY_SEPARATOR;

$cron_id = 'dummy';
include $cronPath.'init.php';

\CB\Config::setFlag('disableActivityLog', true);

run();

function run () {
$opts = getopt('c:f:t:h');
if (isset($opts['h'])) {
printUsage();
return;
}

if (!isset($opts['f']) || empty($opts['f'])) {
println('You have not specified fields to update.');
printUsage();
return;
}
$ts = null;
if (!isset($opts['t']) || empty($opts['t'])) {
$ans = readline('No templates specified. Do you want to update ALL templates? (y/n) ');
if ($ans != 'y') {
println('Aborted.');
return;
}
}
else {
$ts = parseTemplates($opts['t']);
}
$fs = parseFields($opts['f']);
println("Updating objects...");
$updater = new FieldUpdater($fs, $ts);
$updater->updateObjects();
println('Done');
println("Now update solr prepared data and reindex the solr core");
}


class FieldUpdater {

private $templateIds;
private $fields;

/**
* @param array $fs mapping of old field names to new names
* @param array $ts list of template ids
*/
function __construct ($fs, $ts=null) {
$this->templateIds = $ts;
$this->fields = $fs;
}

/**
* Fetches and updates objects
* based on the set template ids and field
* names to udpate
*/
public function updateObjects () {
$res = $this->fetchObjectIds();
while ($row = $res->fetch_assoc()) {
$this->updateObject($row);
}
}

/**
* update the object with the specified id
* @param array $row db row with id and data fields
*/
public function updateObject ($row) {
$data = json_decode($row['data'], true);
if (empty($data)) {
println("Empty data for object ".$row['id']);
return;
}
foreach ($this->fields as $old=>$new) {
if (array_key_exists($old, $data)) {
$data[$new] = $data[$old];
unset($data[$old]);
}
}
$this->saveToDb($row['id'], $data);
}

/**
* fetch object ids from the db
* @return resource the db cursor
*/
private function fetchObjectIds () {
$q = $this->buildQuery();
return DB\dbQuery($q);
}

/**
* builds sql query to use for fetching
* objects based on the specified templates
* @return string
*/
private function buildQuery () {
$q = "SELECT o.id, o.data
FROM objects o";
if (!empty($this->templateIds)) {
$ids = implode(',', $this->templateIds);
$q .= " JOIN tree t on o.id=t.id AND t.template_id in (".$ids.")";
}
return $q;
}

/**
* persists object data in db
* @param mixed $id id of the object to update
* @param array $data
*/
private function saveToDb ($id, $data) {
$data = json_encode($data);
$q = "UPDATE objects SET data=$2
WHERE id=$1";
DB\dbQuery($q, [$id, $data]);
}
}

/**
* parses the templates string arg and returns
* an array of template ids
* @param string $t comma separated list of template
* ids: id1,id2,id3
* @return array
*/
function parseTemplates ($t) {
return explode(',', $t);
}

/**
* parses the fields string arg and returns
* an array mapping old fields to new fields
* @param string $f string-encoded list old to new fields
* mapping in the form oldName1:newName1,oldName2:newName2
* @return array associative array mapping old field names
* to new names
*/
function parseFields ($f) {
$pairs = explode(',', $f);
return array_reduce($pairs, function($res, $item) {
$oldNew = explode(':', $item);
$res[$oldNew[0]] = $oldNew[1];
return $res;
}, []);
}

/**
* prints helpful usage info
*/
function printUsage() {
println('php update_fields.php -c <core> -f <fields> -t <templates>');
println('Options:');
println('-c : the Casebox core name without the cb_ prefix');
println('-f : list of fields to updated in the form oldName1:newName1,oldName2:newName2');
println('-t (optional): comma-separated list of template ids');
println('Note: If option -t is provided, only objects from those templates will be updated,'
.' otherwise ALL objects will be updated.');
println();
println("Example:");
println("php update_fields.php -c demo -f age:victim_age,sex:gender -t 3849,1234");
}

/**
* ouputs the specified string followed by a new line
* @param string $s
*/
function println ($s='') {
echo "$s\n";
}