Do some TODO on modulebuilder module.

This commit is contained in:
Laurent Destailleur 2017-07-16 12:07:59 +02:00
parent 84d76f26f2
commit 7b2a71802b
13 changed files with 297 additions and 52 deletions

View File

@ -27,6 +27,10 @@ $langs->load("admin");
if (!$user->admin) accessforbidden();
$sortfield='file';
$sortorder='ASC';
/*
* Action
*/
@ -50,20 +54,21 @@ print "<br>\n";
$interfaces = new Interfaces($db);
$triggers = $interfaces->getTriggersList();
$param = ''; $align = '';
print '<div class="div-table-responsive-no-min">';
print '<table class="noborder">
<tr class="liste_titre">
<td colspan="2">'.$langs->trans("File").'</td>
<td align="center">'.$langs->trans("Active").'</td>
<td align="center">&nbsp;</td>
</tr>
';
print '<table class="noborder">';
print '<tr class="liste_titre">';
print getTitleFieldOfList($langs->trans("File"), 0, $_SERVER["PHP_SELF"], 'file', "", $param, ($align?'align="'.$align.'"':''), $sortfield, $sortorder, '', 1)."\n";
print getTitleFieldOfList('', 0, $_SERVER["PHP_SELF"], 'none', "", $param, '', $sortfield, $sortorder, '', 1)."\n";
print getTitleFieldOfList($langs->trans("Active"), 0, $_SERVER["PHP_SELF"], 'active', "", $param, 'align="center"', $sortfield, $sortorder, '', 1)."\n";
print getTitleFieldOfList('', 0, $_SERVER["PHP_SELF"], 'none', "", $param, ($align?'align="'.$align.'"':''), $sortfield, $sortorder, '', 1)."\n";
print '</tr>';
$var=True;
foreach ($triggers as $trigger)
{
print '<tr class="oddeven">';
print '<td valign="top" width="14" align="center">'.$trigger['picto'].'</td>';
print '<td class="tdtop">'.$trigger['file'].'</td>';

View File

@ -375,6 +375,133 @@ class ModeleBoxes // Can't be abtract as it is instantiated to build "empty"
return '';
}
/**
* Return list of widget. Function used by admin page htdoc/admin/widget.
* List is sorted by widget filename so by priority to run.
*
* @param array $forcedirwidget null=All default directories. This parameter is used by modulebuilder module only.
* @return array Array list of widget
*/
static function getWidgetsList($forcedirwidget=null)
{
global $conf, $langs, $db;
$files = array();
$fullpath = array();
$relpath = array();
$iscoreorexternal = array();
$modules = array();
$orders = array();
$i = 0;
$dirwidget=array_merge(array('/core/boxes/'));
if (is_array($forcedirwidget))
{
$dirwidget=$forcedirwidget;
}
foreach($dirwidget as $reldir)
{
$dir=dol_buildpath($reldir,0);
$newdir=dol_osencode($dir);
// Check if directory exists (we do not use dol_is_dir to avoid loading files.lib.php at each call)
if (! is_dir($newdir)) continue;
$handle=opendir($newdir);
if (is_resource($handle))
{
while (($file = readdir($handle))!==false)
{
if (is_readable($newdir.'/'.$file) && preg_match('/^(.+)\.php/',$file,$reg))
{
if (preg_match('/\.back$/',$file)) continue;
$part1=$reg[1];
$modName = ucfirst($reg[1]);
//print "file=$file"; print "modName=$modName"; exit;
if (in_array($modName,$modules))
{
$langs->load("errors");
print '<div class="error">'.$langs->trans("Error").' : '.$langs->trans("ErrorDuplicateWidget",$modName,"").'</div>';
}
else
{
try {
include_once $newdir.'/'.$file;
}
catch(Exception $e)
{
print $e->getMessage();
}
}
$files[$i] = $file;
$fullpath[$i] = $dir.'/'.$file;
$relpath[$i] = preg_replace('/^\//','',$reldir).'/'.$file;
$iscoreorexternal[$i] = ($reldir == '/core/boxes/'?'internal':'external');
$modules[$i] = $modName;
$orders[$i] = $part1; // Set sort criteria value
$i++;
}
}
closedir($handle);
}
}
asort($orders);
$widget = array();
$j = 0;
// Loop on each widget
foreach ($orders as $key => $value)
{
$modName = $modules[$key];
if (empty($modName)) continue;
if (! class_exists($modName))
{
print 'Error: A widget file was found but its class "'.$modName.'" was not found.'."<br>\n";
continue;
}
$objMod = new $modName($db);
if (is_object($objMod))
{
// Define disabledbyname and disabledbymodule
$disabledbyname=0;
$module='';
// Check if widget file is disabled by name
if (preg_match('/NORUN$/i',$files[$key])) $disabledbyname=1;
// We set info of modules
$widget[$j]['picto'] = $objMod->picto?img_object('',$objMod->picto):img_object('','generic');
$widget[$j]['file'] = $files[$key];
$widget[$j]['fullpath'] = $fullpath[$key];
$widget[$j]['relpath'] = $relpath[$key];
$widget[$j]['iscoreorexternal'] = $iscoreorexternal[$key];
//$widget[$j]['version'] = $objMod->getVersion();
$widget[$j]['status'] = img_picto($langs->trans("Active"),'tick');
if ($disabledbyname > 0 || $disabledbymodule > 1) $widget[$j]['status'] = '';
$text ='<b>'.$langs->trans("Description").':</b><br>';
$text.=$objMod->boxlabel.'<br>';
$text.='<br><b>'.$langs->trans("Status").':</b><br>';
if ($disabledbymodule == 2) $text.=$langs->trans("HooksDisabledAsModuleDisabled",$module).'<br>';
$widget[$j]['info'] = $text;
}
$j++;
}
return $widget;
}
}

View File

@ -231,7 +231,7 @@ class Interfaces
*/
function getTriggersList($forcedirtriggers=null)
{
global $conf, $langs;
global $conf, $langs, $db;
$files = array();
$fullpath = array();
@ -311,7 +311,7 @@ class Interfaces
continue;
}
$objMod = new $modName($this->db);
$objMod = new $modName($db);
// Define disabledbyname and disabledbymodule
$disabledbyname=0;

View File

@ -3292,9 +3292,10 @@ function print_liste_field_titre($name, $file="", $field="", $begin="", $morepar
* @param string $sortfield Current field used to sort (Ex: 'd.datep,d.id')
* @param string $sortorder Current sort order (Ex: 'asc,desc')
* @param string $prefix Prefix for css. Use space after prefix to add your own CSS tag.
* @param string $disablesortlink 1=Disable sort link
* @return string
*/
function getTitleFieldOfList($name, $thead=0, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="")
function getTitleFieldOfList($name, $thead=0, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $disablesortlink=0)
{
global $conf, $langs;
//print "$name, $file, $field, $begin, $options, $moreattrib, $sortfield, $sortorder<br>\n";
@ -3318,7 +3319,7 @@ function getTitleFieldOfList($name, $thead=0, $file="", $field="", $begin="", $m
if ($field1 && ($sortfield1 == $field1 || $sortfield1 == preg_replace("/^[^\.]+\./","",$field1))) $out.= '<'.$tag.' class="'.$prefix.'liste_titre_sel" '. $moreattrib.'>';
else $out.= '<'.$tag.' class="'.$prefix.'liste_titre" '. $moreattrib.'>';
if (empty($thead) && $field) // If this is a sort field
if (empty($thead) && $field && empty($disablesortlink)) // If this is a sort field
{
$options=preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i','',$moreparam);
$options=preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i','',$options);
@ -3339,7 +3340,7 @@ function getTitleFieldOfList($name, $thead=0, $file="", $field="", $begin="", $m
$out.=$langs->trans($name);
if (empty($thead) && $field) // If this is a sort field
if (empty($thead) && $field && empty($disablesortlink)) // If this is a sort field
{
$out.='</a>';
}

View File

@ -30,9 +30,9 @@ require_once DOL_DOCUMENT_ROOT.'/blockedlog/class/blockedlog.class.php';
class InterfaceActionsBlockedLog extends DolibarrTriggers
{
public $family = 'system';
public $description = "Triggers of this module add blocklog.";
public $description = "Triggers of this module add action for BlockedLog module.";
public $version = self::VERSION_DOLIBARR;
public $picto = 'system';
public $picto = 'technic';
/**
* Function called on Dolibarrr payment or invoice event.

View File

@ -1,7 +1,7 @@
# Dolibarr language file - Source file is en_US - loan
ModuleBuilderDesc=This tools must be used by experienced users or developers. It gives you utilities to build or edit your own module (Documentation for alternative <a href="%s" target="_blank">manual development is here</a>).
EnterNameOfModuleDesc=Enter name of the module/application to create with no spaces. Use uppercase to separate words (For example: MyModule, EcommerceForShop, SyncWithMySystem...)
EnterNameOfObjectDesc=Enter name of the object to create with no spaces. Use uppercase to separate words (For example: MyObject, Student, Teacher...)
EnterNameOfObjectDesc=Enter name of the object to create with no spaces. Use uppercase to separate words (For example: MyObject, Student, Teacher...). The CRUD class file, but also API file, pages to list/add/edit/delete object and SQL files will be generated.
ModuleBuilderDesc2=Path where modules are generated/edited (first alternative directory defined into %s): <strong>%s</strong>
ModuleBuilderDesc3=Generated/editable modules found: <strong>%s</strong> (they are detected as editable when the file <strong>%s</strong> exists in root of module directory).
NewModule=New module
@ -44,4 +44,11 @@ ConfirmDeleteProperty=Are you sure you want to delete the property <strong>%s</s
NotNull=Not NULL
SearchAll=Used for 'search all'
DatabaseIndex=Database index
FileAlreadyExists=File %s already exists
FileAlreadyExists=File %s already exists
TriggersFile=File for triggers code
HooksFile=File for hooks code
WidgetFile=Widget file
ReadmeFile=Readme file
ChangeLog=ChangeLog file
SqlFile=Sql file
SqlFileKey=Sql file for keys

View File

@ -719,6 +719,7 @@ elseif (! empty($module))
{
$pathtofile = $modulelowercase.'/core/modules/mod'.$module.'.class.php';
$pathtofilereadme = $modulelowercase.'/README.md';
$pathtochangelog = $modulelowercase.'/ChangeLog.md';
if ($action != 'editfile' || empty($file))
{
@ -730,6 +731,10 @@ elseif (! empty($module))
print ' <a href="'.$_SERVER['PHP_SELF'].'?tab='.$tab.'&module='.$module.'&action=editfile&file='.urlencode($pathtofilereadme).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
print '<br>';
print '<span class="fa fa-file"></span> '.$langs->trans("ChangeLog").' : <strong>'.$pathtochangelog.'</strong>';
print ' <a href="'.$_SERVER['PHP_SELF'].'?tab='.$tab.'&module='.$module.'&action=editfile&file='.urlencode($pathtochangelog).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
print '<br>';
print '<br>';
print '<br>';
@ -794,7 +799,7 @@ elseif (! empty($module))
print '<br><br>';
// Readme file
print_fiche_titre($langs->trans("ReadmeFile"));
print '<div class="underbanner clearboth"></div>';
@ -802,6 +807,16 @@ elseif (! empty($module))
print $moduleobj->getDescLong();
print '<br><br>';
// ChangeLog
print_fiche_titre($langs->trans("ChangeLog"));
print '<div class="underbanner clearboth"></div>';
print '<div class="fichecenter">';
print $moduleobj->getChangeLog();
print '</div>';
}
else
@ -959,12 +974,20 @@ elseif (! empty($module))
$pathtoapi = strtolower($module).'/class/api_'.strtolower($tabobj).'.class.php';
$pathtolist = strtolower($module).'/'.strtolower($tabobj).'_list.php';
$pathtocard = strtolower($module).'/'.strtolower($tabobj).'_card.php';
$pathtosql = strtolower($module).'/sql/llx_'.strtolower($tabobj).'.sql';
$pathtosqlkey = strtolower($module).'/sql/llx_'.strtolower($tabobj).'.key.sql';
print '<div class="fichehalfleft">';
print '<span class="fa fa-file"></span> '.$langs->trans("ClassFile").' : <strong>'.$pathtoclass.'</strong>';
print ' <a href="'.$_SERVER['PHP_SELF'].'?tab='.$tab.'&module='.$module.'&action=editfile&file='.urlencode($pathtoclass).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
print '<br>';
print '<span class="fa fa-file"></span> '.$langs->trans("ApiClassFile").' : <strong>'.$pathtoapi.'</strong>';
print ' <a href="'.$_SERVER['PHP_SELF'].'?tab='.$tab.'&module='.$module.'&action=editfile&file='.urlencode($pathtoapi).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
print '<br>';
print '<span class="fa fa-file"></span> '.$langs->trans("SqlFile").' : <strong>'.$pathtosql.'</strong>';
print ' <a href="'.$_SERVER['PHP_SELF'].'?tab='.$tab.'&module='.$module.'&action=editfile&file='.urlencode($pathtosql).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
print '<br>';
print '<span class="fa fa-file"></span> '.$langs->trans("SqlFileKey").' : <strong>'.$pathtosqlkey.'</strong>';
print ' <a href="'.$_SERVER['PHP_SELF'].'?tab='.$tab.'&module='.$module.'&action=editfile&file='.urlencode($pathtosqlkey).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
print '</div>';
print '<div class="fichehalfleft">';
print '<span class="fa fa-file"></span> '.$langs->trans("PageForList").' : <strong>'.$pathtolist.'</strong>';
@ -1138,8 +1161,38 @@ elseif (! empty($module))
if ($tab == 'hooks')
{
print $langs->trans("FeatureNotYetAvailable");
if ($action != 'editfile' || empty($file))
{
$pathtohook = strtolower($module).'/class/actions_'.strtolower($module).'.class.php';
print '<span class="fa fa-file"></span> '.$langs->trans("HooksFile").' : <strong>'.$pathtohook.'</strong>';
print ' <a href="'.$_SERVER['PHP_SELF'].'?tab='.$tab.'&module='.$module.'&action=editfile&file='.urlencode($pathtohook).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
print '<br>';
}
else
{
$fullpathoffile=dol_buildpath($file, 0);
$content = file_get_contents($fullpathoffile);
// New module
print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
print '<input type="hidden" name="action" value="savefile">';
print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
print '<input type="hidden" name="tab" value="'.$tab.'">';
print '<input type="hidden" name="module" value="'.$module.'">';
$doleditor=new DolEditor('editfilecontent', $content, '', '600', 'Full', 'In', true, false, false, 0, '99%');
print $doleditor->Create(1, '', false);
print '<br>';
print '<center>';
print '<input type="submit" class="button" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
print ' &nbsp; ';
print '<input type="submit" class="button" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
print '</center>';
print '</form>';
}
}
if ($tab == 'triggers')
@ -1155,7 +1208,7 @@ elseif (! empty($module))
{
$pathtofile = $trigger['relpath'];
print '<span class="fa fa-file"></span> '.$langs->trans("TriggerFile").' : <strong>'.$pathtofile.'</strong>';
print '<span class="fa fa-file"></span> '.$langs->trans("TriggersFile").' : <strong>'.$pathtofile.'</strong>';
print ' <a href="'.$_SERVER['PHP_SELF'].'?tab='.$tab.'&module='.$module.'&action=editfile&file='.urlencode($pathtofile).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
print '<br>';
}
@ -1189,8 +1242,46 @@ elseif (! empty($module))
if ($tab == 'widgets')
{
print $langs->trans("FeatureNotYetAvailable");
require_once DOL_DOCUMENT_ROOT.'/core/boxes/modules_boxes.php';
$widgets = ModeleBoxes::getWidgetsList(array('/'.strtolower($module).'/core/boxes'));
if ($action != 'editfile' || empty($file))
{
foreach ($widgets as $widget)
{
$pathtofile = $widget['relpath'];
print '<span class="fa fa-file"></span> '.$langs->trans("WidgetFile").' : <strong>'.$pathtofile.'</strong>';
print ' <a href="'.$_SERVER['PHP_SELF'].'?tab='.$tab.'&module='.$module.'&action=editfile&file='.urlencode($pathtofile).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
print '<br>';
}
}
else
{
$fullpathoffile=dol_buildpath($file, 0);
$content = file_get_contents($fullpathoffile);
// New module
print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
print '<input type="hidden" name="action" value="savefile">';
print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
print '<input type="hidden" name="tab" value="'.$tab.'">';
print '<input type="hidden" name="module" value="'.$module.'">';
$doleditor=new DolEditor('editfilecontent', $content, '', '600', 'Full', 'In', true, false, false, 0, '99%');
print $doleditor->Create(1, '', false);
print '<br>';
print '<center>';
print '<input type="submit" class="button" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
print ' &nbsp; ';
print '<input type="submit" class="button" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
print '</center>';
print '</form>';
}
}
if ($tab == 'buildpackage')

View File

@ -0,0 +1,5 @@
# CHANGELOG FOR DOLIBARR ERP CRM
## 1.0
Initial version

View File

@ -17,9 +17,9 @@
*/
/**
* \file core/boxes/mybox.php
* \file modulebuilder/template/core/boxes/mymodulewidget1.php
* \ingroup mymodule
* \brief Example box definition.
* \brief Widget provided by MyModule
*
* Put detailed description here.
*/
@ -33,12 +33,12 @@ include_once DOL_DOCUMENT_ROOT . "/core/boxes/modules_boxes.php";
* Warning: for the box to be detected correctly by dolibarr,
* the filename should be the lowercase classname
*/
class MyBox extends ModeleBoxes
class mymodulewidget1 extends ModeleBoxes
{
/**
* @var string Alphanumeric ID. Populated by the constructor.
*/
public $boxcode = "mybox";
public $boxcode = "mymodulebox";
/**
* @var string Box icon (in configuration page)
@ -90,7 +90,7 @@ class MyBox extends ModeleBoxes
parent::__construct($db, $param);
$this->boxlabel = $langs->transnoentitiesnoconv("MyBox");
$this->boxlabel = $langs->transnoentitiesnoconv("MyWidget");
$this->param = $param;
@ -114,7 +114,7 @@ class MyBox extends ModeleBoxes
//include_once DOL_DOCUMENT_ROOT . "/mymodule/class/mymodule.class.php";
// Populate the head at runtime
$text = $langs->trans("MyBoxDescription", $max);
$text = $langs->trans("MyModuleBoxDescription", $max);
$this->info_box_head = array(
// Title text
'text' => $text,
@ -142,18 +142,21 @@ class MyBox extends ModeleBoxes
'tr' => 'align="left"',
// HTML properties of the TD element
'td' => '',
// Fist line logo
'logo' => 'mymodule@mymodule',
// Main text
'text' => 'My text',
// Secondary text
'text2' => '<p><strong>Another text</strong></p>',
// Unformatted text, usefull to load javascript elements
'textnoformat' => '',
// Main text for content of cell
'text' => 'First cell of first line',
// Link on 'text' and 'logo' elements
'url' => 'http://example.com',
// Link's target HTML property
'target' => '_blank',
// Fist line logo (deprecated. Include instead logo html code into text or text2, and set asis property to true to avoid HTML cleaning)
//'logo' => 'monmodule@monmodule',
// Unformatted text, added after text. Usefull to add/load javascript code
'textnoformat' => '',
// Main text for content of cell (other method)
//'text2' => '<p><strong>Another text</strong></p>',
// Truncates 'text' element to the specified character length, 0 = disabled
'maxlength' => 0,
// Prevents HTML cleaning (and truncation)
@ -164,19 +167,27 @@ class MyBox extends ModeleBoxes
1 => array( // Another column
// No TR for n≠0
'td' => '',
'text' => 'Another cell',
'text' => 'Second cell',
)
),
1 => array( // Another line
0 => array( // TR
'tr' => 'align="left"',
'text' => 'Another line'
),
1 => array( // TR
'tr' => 'align="left"',
'text' => ''
)
),
2 => array( // Another line
0 => array( // TR
'tr' => 'align="left"',
'text' => 'Yet another line'
'text' => ''
),
0 => array( // TR
'tr' => 'align="left"',
'text' => ''
)
),
);

View File

@ -173,15 +173,13 @@ class modMyModule extends DolibarrModules
*/
// Boxes
// Add here list of php file(s) stored in core/boxes that contains class to show a widget.
$this->boxes = array(); // List of boxes
// Example:
//$this->boxes=array(
// 0=>array('file'=>'myboxa.php@mymodule','note'=>'','enabledbydefaulton'=>'Home'),
// 1=>array('file'=>'myboxb.php@mymodule','note'=>''),
// 2=>array('file'=>'myboxc.php@mymodule','note'=>'')
//);
// Boxes/Widgets
// Add here list of php file(s) stored in mymodule/core/boxes that contains class to show a widget.
$this->boxes = array(
0=>array('file'=>'mymodulewidget1.php@mymodule','note'=>'Widget provided by MyModule','enabledbydefaulton'=>'Home'),
//1=>array('file'=>'mymodulewidget2.php@mymodule','note'=>'Widget provided by MyModule'),
//2=>array('file'=>'mymodulewidget3.php@mymodule','note'=>'Widget provided by MyModule')
);
// Cronjobs

View File

@ -44,5 +44,5 @@ MyPageName = My page name
#
# Sample box
#
MyBox = My box
MyBoxDescription = My box description
MyWidget = My widget
MyWidgetDescription = My widget description

View File

@ -44,5 +44,5 @@ MyPageName = Nom de ma page
#
# Box d'exemple
#
MyBox = Ma boîte
MyBoxDescription = Description de ma boîte
MyWidget = Mon widget
MyWidgetDescription = Description de mon widget

View File

@ -231,7 +231,7 @@ class MyModuleFunctionalTest extends \PHPUnit_Extensions_Selenium2TestCase
{
$this->url('/admin/boxes.php');
$this->authenticate();
return $this->assertContains('mybox', $this->source(), "Box enabled");
return $this->assertContains('mymodulewidget1', $this->source(), "Box enabled");
}
/**
@ -244,7 +244,7 @@ class MyModuleFunctionalTest extends \PHPUnit_Extensions_Selenium2TestCase
$this->url('/admin/triggers.php');
$this->authenticate();
return $this->assertContains(
'interface_99_modMyModule_MyTrigger.class.php',
'interface_99_modMyModule_MyModuleTriggers.class.php',
$this->byTag('body')->text(),
"Trigger declared"
);