From 7b2a71802be257531c611313152a1af9c5bb9e8d Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 16 Jul 2017 12:07:59 +0200 Subject: [PATCH] Do some TODO on modulebuilder module. --- htdocs/admin/triggers.php | 21 +-- htdocs/core/boxes/modules_boxes.php | 127 ++++++++++++++++++ htdocs/core/class/interfaces.class.php | 4 +- htdocs/core/lib/functions.lib.php | 7 +- ..._modBlockedlog_ActionsBlockedLog.class.php | 4 +- htdocs/langs/en_US/modulebuilder.lang | 11 +- htdocs/modulebuilder/index.php | 99 +++++++++++++- htdocs/modulebuilder/template/ChangeLog.md | 5 + .../boxes/{mybox.php => mymodulewidget1.php} | 43 +++--- .../core/modules/modMyModule.class.php | 16 +-- .../template/langs/en_US/mymodule.lang | 4 +- .../template/langs/fr_FR/mymodule.lang | 4 +- .../test/phpunit/MyModuleFunctionalTest.php | 4 +- 13 files changed, 297 insertions(+), 52 deletions(-) create mode 100644 htdocs/modulebuilder/template/ChangeLog.md rename htdocs/modulebuilder/template/core/boxes/{mybox.php => mymodulewidget1.php} (83%) diff --git a/htdocs/admin/triggers.php b/htdocs/admin/triggers.php index 0dddfb3c4af..58ca4e0eded 100644 --- a/htdocs/admin/triggers.php +++ b/htdocs/admin/triggers.php @@ -27,6 +27,10 @@ $langs->load("admin"); if (!$user->admin) accessforbidden(); +$sortfield='file'; +$sortorder='ASC'; + + /* * Action */ @@ -50,20 +54,21 @@ print "
\n"; $interfaces = new Interfaces($db); $triggers = $interfaces->getTriggersList(); +$param = ''; $align = ''; print '
'; -print ' - - - - - -'; +print '
'.$langs->trans("File").''.$langs->trans("Active").' 
'; +print ''; +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 ''; $var=True; foreach ($triggers as $trigger) { - + print ''; print ''; print ''; diff --git a/htdocs/core/boxes/modules_boxes.php b/htdocs/core/boxes/modules_boxes.php index d83f0e80cba..9c496964942 100644 --- a/htdocs/core/boxes/modules_boxes.php +++ b/htdocs/core/boxes/modules_boxes.php @@ -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 '
'.$langs->trans("Error").' : '.$langs->trans("ErrorDuplicateWidget",$modName,"").'
'; + } + 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.'."
\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 =''.$langs->trans("Description").':
'; + $text.=$objMod->boxlabel.'
'; + $text.='
'.$langs->trans("Status").':
'; + if ($disabledbymodule == 2) $text.=$langs->trans("HooksDisabledAsModuleDisabled",$module).'
'; + + $widget[$j]['info'] = $text; + } + $j++; + } + return $widget; + } + + } diff --git a/htdocs/core/class/interfaces.class.php b/htdocs/core/class/interfaces.class.php index d7dce8613db..ef64ac8d8e5 100644 --- a/htdocs/core/class/interfaces.class.php +++ b/htdocs/core/class/interfaces.class.php @@ -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; diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 386009f2370..fae3c4eae5e 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -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
\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.=''; } diff --git a/htdocs/core/triggers/interface_50_modBlockedlog_ActionsBlockedLog.class.php b/htdocs/core/triggers/interface_50_modBlockedlog_ActionsBlockedLog.class.php index 9d57c3f85fe..39dae7c209e 100644 --- a/htdocs/core/triggers/interface_50_modBlockedlog_ActionsBlockedLog.class.php +++ b/htdocs/core/triggers/interface_50_modBlockedlog_ActionsBlockedLog.class.php @@ -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. diff --git a/htdocs/langs/en_US/modulebuilder.lang b/htdocs/langs/en_US/modulebuilder.lang index 76a12a45c57..91035a6ab97 100644 --- a/htdocs/langs/en_US/modulebuilder.lang +++ b/htdocs/langs/en_US/modulebuilder.lang @@ -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 manual development is here). 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): %s ModuleBuilderDesc3=Generated/editable modules found: %s (they are detected as editable when the file %s exists in root of module directory). NewModule=New module @@ -44,4 +44,11 @@ ConfirmDeleteProperty=Are you sure you want to delete the property %s'.img_picto($langs->trans("Edit"), 'edit').''; print '
'; + print ' '.$langs->trans("ChangeLog").' : '.$pathtochangelog.''; + print ' '.img_picto($langs->trans("Edit"), 'edit').''; + print '
'; + print '
'; print '
'; @@ -794,7 +799,7 @@ elseif (! empty($module)) print '

'; - + // Readme file print_fiche_titre($langs->trans("ReadmeFile")); print '
'; @@ -802,6 +807,16 @@ elseif (! empty($module)) print $moduleobj->getDescLong(); + print '

'; + + // ChangeLog + print_fiche_titre($langs->trans("ChangeLog")); + + print '
'; + print '
'; + + print $moduleobj->getChangeLog(); + print '
'; } 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 '
'; print ' '.$langs->trans("ClassFile").' : '.$pathtoclass.''; print ' '.img_picto($langs->trans("Edit"), 'edit').''; print '
'; print ' '.$langs->trans("ApiClassFile").' : '.$pathtoapi.''; print ' '.img_picto($langs->trans("Edit"), 'edit').''; + print '
'; + print ' '.$langs->trans("SqlFile").' : '.$pathtosql.''; + print ' '.img_picto($langs->trans("Edit"), 'edit').''; + print '
'; + print ' '.$langs->trans("SqlFileKey").' : '.$pathtosqlkey.''; + print ' '.img_picto($langs->trans("Edit"), 'edit').''; print '
'; print '
'; print ' '.$langs->trans("PageForList").' : '.$pathtolist.''; @@ -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 ' '.$langs->trans("HooksFile").' : '.$pathtohook.''; + print ' '.img_picto($langs->trans("Edit"), 'edit').''; + print '
'; + } + else + { + $fullpathoffile=dol_buildpath($file, 0); + $content = file_get_contents($fullpathoffile); + + // New module + print '
'; + print ''; + print ''; + print ''; + print ''; + print ''; + + $doleditor=new DolEditor('editfilecontent', $content, '', '600', 'Full', 'In', true, false, false, 0, '99%'); + print $doleditor->Create(1, '', false); + print '
'; + print '
'; + print ''; + print '   '; + print ''; + print '
'; + + print ''; + } } if ($tab == 'triggers') @@ -1155,7 +1208,7 @@ elseif (! empty($module)) { $pathtofile = $trigger['relpath']; - print ' '.$langs->trans("TriggerFile").' : '.$pathtofile.''; + print ' '.$langs->trans("TriggersFile").' : '.$pathtofile.''; print ' '.img_picto($langs->trans("Edit"), 'edit').''; print '
'; } @@ -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 ' '.$langs->trans("WidgetFile").' : '.$pathtofile.''; + print ' '.img_picto($langs->trans("Edit"), 'edit').''; + print '
'; + } + } + else + { + $fullpathoffile=dol_buildpath($file, 0); + + $content = file_get_contents($fullpathoffile); + + // New module + print '
'; + print ''; + print ''; + print ''; + print ''; + print ''; + + $doleditor=new DolEditor('editfilecontent', $content, '', '600', 'Full', 'In', true, false, false, 0, '99%'); + print $doleditor->Create(1, '', false); + print '
'; + print '
'; + print ''; + print '   '; + print ''; + print '
'; + + print ''; + } } if ($tab == 'buildpackage') diff --git a/htdocs/modulebuilder/template/ChangeLog.md b/htdocs/modulebuilder/template/ChangeLog.md new file mode 100644 index 00000000000..0f04e316f58 --- /dev/null +++ b/htdocs/modulebuilder/template/ChangeLog.md @@ -0,0 +1,5 @@ +# CHANGELOG FOR DOLIBARR ERP CRM + +## 1.0 +Initial version + diff --git a/htdocs/modulebuilder/template/core/boxes/mybox.php b/htdocs/modulebuilder/template/core/boxes/mymodulewidget1.php similarity index 83% rename from htdocs/modulebuilder/template/core/boxes/mybox.php rename to htdocs/modulebuilder/template/core/boxes/mymodulewidget1.php index 3b3fedcca08..85592006a14 100644 --- a/htdocs/modulebuilder/template/core/boxes/mybox.php +++ b/htdocs/modulebuilder/template/core/boxes/mymodulewidget1.php @@ -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' => '

Another text

', - // 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' => '

Another text

', + // 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' => '' ) ), ); diff --git a/htdocs/modulebuilder/template/core/modules/modMyModule.class.php b/htdocs/modulebuilder/template/core/modules/modMyModule.class.php index cd3fb22be80..d91b4c6a495 100644 --- a/htdocs/modulebuilder/template/core/modules/modMyModule.class.php +++ b/htdocs/modulebuilder/template/core/modules/modMyModule.class.php @@ -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 diff --git a/htdocs/modulebuilder/template/langs/en_US/mymodule.lang b/htdocs/modulebuilder/template/langs/en_US/mymodule.lang index 478d589a7e6..e09e396dce0 100644 --- a/htdocs/modulebuilder/template/langs/en_US/mymodule.lang +++ b/htdocs/modulebuilder/template/langs/en_US/mymodule.lang @@ -44,5 +44,5 @@ MyPageName = My page name # # Sample box # -MyBox = My box -MyBoxDescription = My box description \ No newline at end of file +MyWidget = My widget +MyWidgetDescription = My widget description \ No newline at end of file diff --git a/htdocs/modulebuilder/template/langs/fr_FR/mymodule.lang b/htdocs/modulebuilder/template/langs/fr_FR/mymodule.lang index c946ad6691c..aa271536edf 100644 --- a/htdocs/modulebuilder/template/langs/fr_FR/mymodule.lang +++ b/htdocs/modulebuilder/template/langs/fr_FR/mymodule.lang @@ -44,5 +44,5 @@ MyPageName = Nom de ma page # # Box d'exemple # -MyBox = Ma boîte -MyBoxDescription = Description de ma boîte \ No newline at end of file +MyWidget = Mon widget +MyWidgetDescription = Description de mon widget diff --git a/htdocs/modulebuilder/template/test/phpunit/MyModuleFunctionalTest.php b/htdocs/modulebuilder/template/test/phpunit/MyModuleFunctionalTest.php index 547b48a32af..a70cc9bee8d 100644 --- a/htdocs/modulebuilder/template/test/phpunit/MyModuleFunctionalTest.php +++ b/htdocs/modulebuilder/template/test/phpunit/MyModuleFunctionalTest.php @@ -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" );
'.$trigger['picto'].''.$trigger['file'].'