Search This Blog

Friday, April 12, 2013

Reading Exported SugarCRM Modules

I recently had the need to re-create exported SugarCRM modules.
I had exported the modules from a Sugar Online instance with the plan to import them into a hosted SugarCRM instance.
However more time than I expected had passed and version details changed, so the modules would not import.
The modules were not heavily customised, so I decided to look at the exported module files and re-create them.
I wrote a php cli script that give the path to an exported extract module, will list the fields:

John-Reidys-MacBook-2:$ php dumpfields.php Jobs2012_12_19_190139
Modules found:
JOB_Jobs
read module JOB_Jobs: 
module: JOB_Jobs
fields count: 13
    date client_advised_date                    
checkbox completed                             1
    date completed_date                         
 varchar estimated_time                 255
 varchar estimated_time_code             20
currency invoice_amount                  26
currency currency_id                     36
    date invoice_date                           
dropdown job_status                     
[complete->"complete" domain_not_ready->"domain not ready" in_production->"in production" incomplete->"incomplete" on_hold->"on hold" ready->"ready" ]
    date loaded_to_search_date                  
    date loaded_to_server_date                  
    date start_date                             
     int job_number                             


The code does the following:
Checks the arguments passed:

if ($argc == 1 ) {
echo "Usage: {$argv[0]} <module-path> <module-name>\n";
exit(1);
}
$modulePath=$argv[1];
if (!file_exists($modulePath) || is_file($modulePath) ) {
echo "{$argv[0]}: bad module-path {$modulePath}\n";
exit(1);
}

$basedir = $modulePath.'/SugarModules/';
$moduleDir=$basedir.'/modules/';

if (!file_exists($basedir) || is_file($basedir) 
     || !file_exists($moduleDir) || is_file($moduleDir) ) {
echo "{$argv[0]}: bad structure cannot find SugarModules or modules sub directories  module-path: {$modulePath}\n";
exit(1);
}

This is an example of a cli php script - which can be very useful for php programers who need to do scripting.

Argument Handling.

1 or 2 arguments are expected - the path to the module package and the module itself.
The module path is checked and then the expected sub folders in the module.
Then if the module name is not specified, they are listed and the user asked if they want to read the first module:

$moduleName='';
if ($argc == 2) {
  echo "Modules found:\n";
  $handle=opendir($moduleDir);
while (false !== ($entry = readdir($handle))) {
   if (!is_file($entry) && $entry != '.' && $entry != '..') {
    echo "$entry\n";
    if (! $moduleName) $moduleName = $entry;
   }
}
if ($moduleName) {
echo "read module {$moduleName}: ";
 $handle = fopen ("php://stdin","r");
 $line = fgets($handle);

 if(trim($line) != 'yes' && trim($line) != 'y' && trim($line) !=''){
    echo "ABORTING!\n";
    exit(0);
 }

} else {
  exit(1);
}
}
Entering 'y', 'yes' or enter will continue.

Read the Vardefs

Next the variable definitions for the module itself are read.

require $basedir.'modules/'.$moduleName.'/vardefs.php';
require $basedir.'modules/'.$moduleName.'/language/en_us.lang.php';
require $basedir.'language/application/en_us.lang.php';

class VardefManager{
    static $custom_disabled_modules = array();
    static $linkFields;

    /**
     * this method is called within a vardefs.php file which extends from a SugarObject.
     * It is meant to load the vardefs from the SugarObject.
     */
    static function createVardef($module, $object, $templates = array('default'), $object_name = false)
    {
}
}




The included class and static method - createVarDef is invoked by the vardefs.php, this currently does nothing, however the following code could be moved inside it.

Print the Fields

The fields and some of the details are then printed:


$fields = $dictionary[$moduleName]['fields'];
printf("module: %s\n", $moduleName);
$maxfieldlen=0;
foreach($fields as $fieldname => $fielddef) $maxfieldlen = strlen($fieldname) > $maxfieldlen ? strlen($fieldname) : $maxfieldlen;
echo "fields count: ". count($fields)."\n";
$fieldNameFmt="-{$maxfieldlen}.{$maxfieldlen}";
foreach($fields as $fieldname => $fielddef) {
switch($fielddef['type']) {
case 'date':
case 'datetime':
case 'bool':
case 'int':
  printf("%8.8s %{$fieldNameFmt}s %8.8s %8.8s", $fielddef['type']=='bool'?'checkbox':$fielddef['type'], $fieldname, $fielddef['required'], isset($fielddef['default'])?isset($fielddef['default']) : '');
break;
case 'enum':
  printf("%8.8s %{$fieldNameFmt}s %8.8s ", 'dropdown', $fieldname, $fielddef['required']);
  $enumList = $app_list_strings[$fielddef['options']];
$maxEnumValuelen=$maxEnumLablelen=0;
foreach($enumList as $enumValue => $enumLabel) {
$maxEnumValuelen = strlen($enumValue) > $maxEnumValuelen ? strlen($enumValue) : $maxEnumValuelen;
$maxEnumLablelen = strlen($enumLabel) > $maxEnumLablelen ? strlen($enumLabel) : $maxEnumLablelen;
  }
  printf("\n\t[");
$enumValueFmt=""; //"{$maxEnumValuelen}.{$maxEnumValuelen}";
$enumLableFmt="-";//"-{$maxEnumLablelen}.{$maxEnumLablelen}";
  foreach($enumList as $enumValue => $enumLabel) {
    $enumLabelpp = "\"${enumLabel}\"";
printf("%{$enumValueFmt}s->%{$enumLableFmt}s ", $enumValue, $enumLabelpp);
}
  printf("]");
  
break;
default:
  printf("%8.8s %{$fieldNameFmt}s %8.8s %3.3d", $fielddef['type'], $fieldname, $fielddef['required'],isset($fielddef['len'])?$fielddef['len']:$fielddef['size']);
break;
}

echo "\n";
}


This could be extended and made smarter to print more information, however for my purposes it was enough.

The complete script.



<?php

if ($argc == 1 ) {
echo "Usage: {$argv[0]} <module-path> <module-name>\n";
exit(1);
}
$modulePath=$argv[1];
if (!file_exists($modulePath) || is_file($modulePath) ) {
echo "{$argv[0]}: bad module-path {$modulePath}\n";
exit(1);
}

$basedir = $modulePath.'/SugarModules/';
$moduleDir=$basedir.'/modules/';

if (!file_exists($basedir) || is_file($basedir) 
     || !file_exists($moduleDir) || is_file($moduleDir) ) {
echo "{$argv[0]}: bad structure cannot find SugarModules or modules sub directories  module-path: {$modulePath}\n";
exit(1);
}

$moduleName='';
if ($argc == 2) {
  echo "Modules found:\n";
  $handle=opendir($moduleDir);
while (false !== ($entry = readdir($handle))) {
   if (!is_file($entry) && $entry != '.' && $entry != '..') {
    echo "$entry\n";
    if (! $moduleName) $moduleName = $entry;
   }
}
if ($moduleName) {
echo "read module {$moduleName}: ";
 $handle = fopen ("php://stdin","r");
 $line = fgets($handle);

 if(trim($line) != 'yes' && trim($line) != 'y' && trim($line) !=''){
    echo "ABORTING!\n";
    exit(0);
 }

} else {
  exit(1);
}
}


require $basedir.'modules/'.$moduleName.'/vardefs.php';
require $basedir.'modules/'.$moduleName.'/language/en_us.lang.php';
require $basedir.'language/application/en_us.lang.php';

class VardefManager{
    static $custom_disabled_modules = array();
    static $linkFields;

    /**
     * this method is called within a vardefs.php file which extends from a SugarObject.
     * It is meant to load the vardefs from the SugarObject.
     */
    static function createVardef($module, $object, $templates = array('default'), $object_name = false)
    {
}
}



$fields = $dictionary[$moduleName]['fields'];
printf("module: %s\n", $moduleName);
$maxfieldlen=0;
foreach($fields as $fieldname => $fielddef) $maxfieldlen = strlen($fieldname) > $maxfieldlen ? strlen($fieldname) : $maxfieldlen;
echo "fields count: ". count($fields)."\n";
$fieldNameFmt="-{$maxfieldlen}.{$maxfieldlen}";
foreach($fields as $fieldname => $fielddef) {
switch($fielddef['type']) {
case 'date':
case 'datetime':
case 'bool':
case 'int':
  printf("%8.8s %{$fieldNameFmt}s %8.8s %8.8s", $fielddef['type']=='bool'?'checkbox':$fielddef['type'], $fieldname, $fielddef['required'], isset($fielddef['default'])?isset($fielddef['default']) : '');
break;
case 'enum':
  printf("%8.8s %{$fieldNameFmt}s %8.8s ", 'dropdown', $fieldname, $fielddef['required']);
  $enumList = $app_list_strings[$fielddef['options']];
$maxEnumValuelen=$maxEnumLablelen=0;
foreach($enumList as $enumValue => $enumLabel) {
$maxEnumValuelen = strlen($enumValue) > $maxEnumValuelen ? strlen($enumValue) : $maxEnumValuelen;
$maxEnumLablelen = strlen($enumLabel) > $maxEnumLablelen ? strlen($enumLabel) : $maxEnumLablelen;
  }
  printf("\n\t[");
$enumValueFmt=""; //"{$maxEnumValuelen}.{$maxEnumValuelen}";
$enumLableFmt="-";//"-{$maxEnumLablelen}.{$maxEnumLablelen}";
  foreach($enumList as $enumValue => $enumLabel) {
    $enumLabelpp = "\"${enumLabel}\"";
printf("%{$enumValueFmt}s->%{$enumLableFmt}s ", $enumValue, $enumLabelpp);
}
  printf("]");
  
break;
default:
  printf("%8.8s %{$fieldNameFmt}s %8.8s %3.3d", $fielddef['type'], $fieldname, $fielddef['required'],isset($fielddef['len'])?$fielddef['len']:$fielddef['size']);
break;
}

echo "\n";
}
?>



2 comments:

  1. Nice work, that script looks pretty interesting. You should throw it on github so it'd be easier to work with and for everyone to collaborate on.

    ReplyDelete
  2. Will do, I have some other code on here that I will put up on Git,

    ReplyDelete