From cb317ddc1190803e054dfdc5c3ab83a1165b4cc2 Mon Sep 17 00:00:00 2001 From: Milen Karaganski Date: Mon, 27 Apr 2026 15:53:59 +0300 Subject: [PATCH] Refactor modulebuilder setup UI for numbering and document models (#38008) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Refactor module setup UI to group numbering and document models into single sections Avoid duplicate “Numbering models” and “Document models” blocks per object Render one section per type with grouped rows per object Add pre-checks to skip sections when no models are available Fix document model filtering per object (avoid cross-listing) Reset file list per directory scan to prevent duplicates * FIX CI Error `Error: If condition is always false.` and `Error: Unreachable statement - code above always terminates.` * - Remove duplicate `Access control` statement - Replace `header(...);return;` with ``header(...);exit;`` * Fix PHP Stan errors --- htdocs/modulebuilder/template/admin/setup.php | 488 ++++++++++-------- 1 file changed, 273 insertions(+), 215 deletions(-) diff --git a/htdocs/modulebuilder/template/admin/setup.php b/htdocs/modulebuilder/template/admin/setup.php index 294e714ecf5..2e5bb383c20 100644 --- a/htdocs/modulebuilder/template/admin/setup.php +++ b/htdocs/modulebuilder/template/admin/setup.php @@ -102,12 +102,6 @@ if (!class_exists('FormSetup')) { } $formSetup = new FormSetup($db); -// Access control -if (!$user->admin) { - accessforbidden(); -} - - // Enter here all parameters in your setup page // Setup conf for selection of an URL @@ -263,7 +257,7 @@ if ($action == 'updateMask') { if ($module->write_file($tmpobject, $langs) > 0) { header("Location: ".DOL_URL_ROOT."/document.php?modulepart=mymodule-".strtolower($tmpobjectkey)."&file=SPECIMEN.pdf"); - return; + exit; } else { setEventMessages($module->error, null, 'errors'); dol_syslog($module->error, LOG_ERR); @@ -357,134 +351,184 @@ if (!empty($formSetup->items)) { } +$refGenerationObjects = array(); +$docGenerationObjects = array(); + foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) { if (!empty($myTmpObjectArray['includerefgeneration'])) { - // Numbering models + $refGenerationObjects[$myTmpObjectKey] = $myTmpObjectArray; + } - $setupnotempty++; + if (!empty($myTmpObjectArray['includedocgeneration'])) { + $docGenerationObjects[$myTmpObjectKey] = $myTmpObjectArray; + } +} - print load_fiche_titre($langs->trans("NumberingModules", $myTmpObjectArray['label']), '', ''); +// Numbering models +if (!empty($refGenerationObjects)) { + $setupnotempty++; + + print load_fiche_titre($langs->trans("NumberingModules"), '', ''); + + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''."\n"; + + clearstatcache(); + + foreach ($refGenerationObjects as $myTmpObjectKey => $myTmpObjectArray) { + if (empty($myTmpObjectArray['includerefgeneration'])) { + continue; + } - print '
'.$langs->trans("Name").''.$langs->trans("Description").''.$langs->trans("Example").''.$langs->trans("Status").''.$langs->trans("ShortInfo").'
'; print ''; - print ''; - print ''; - print ''; - print ''; - print ''; + print ''; print ''."\n"; - clearstatcache(); - foreach ($dirmodels as $reldir) { $dir = dol_buildpath($reldir."core/modules/".$moduledir); - if (is_dir($dir)) { - $handle = opendir($dir); - if (is_resource($handle)) { - while (($file = readdir($handle)) !== false) { - if (strpos($file, 'mod_'.strtolower($myTmpObjectKey).'_') === 0 && substr($file, dol_strlen($file) - 3, 3) == 'php') { - $file = substr($file, 0, dol_strlen($file) - 4); - - require_once $dir.'/'.$file.'.php'; - - $module = new $file($db); - '@phan-var-force ModeleNumRefMyObject $module'; - - // Show modules according to features level - if ($module->version == 'development' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 2) { - continue; - } - if ($module->version == 'experimental' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 1) { - continue; - } - - if ($module->isEnabled()) { - dol_include_once('/'.$moduledir.'/class/'.strtolower($myTmpObjectKey).'.class.php'); - - print ''; - - // Show example of numbering model - print ''."\n"; - - print ''; - - $className = $myTmpObjectArray['class']; - $mytmpinstance = new $className($db); - '@phan-var-force MyObject $mytmpinstance'; - $mytmpinstance->initAsSpecimen(); - - // Info - $htmltooltip = ''; - $htmltooltip .= ''.$langs->trans("Version").': '.$module->getVersion().'
'; - - $nextval = $module->getNextValue($mytmpinstance); - if ("$nextval" != $langs->trans("NotAvailable")) { // Keep " on nextval - $htmltooltip .= ''.$langs->trans("NextValue").': '; - if ($nextval) { - if (preg_match('/^Error/', $nextval) || $nextval == 'NotConfigured') { - $nextval = $langs->trans($nextval); - } - $htmltooltip .= $nextval.'
'; - } else { - $htmltooltip .= $langs->trans($module->error).'
'; - } - } - - print ''; - - print "\n"; - } - } - } - closedir($handle); - } + if (!is_dir($dir)) { + continue; } + + $handle = opendir($dir); + if (!is_resource($handle)) { + continue; + } + + while (($file = readdir($handle)) !== false) { + if (strpos($file, 'mod_'.strtolower($myTmpObjectKey).'_') !== 0 || substr($file, dol_strlen($file) - 3, 3) != 'php') { + continue; + } + + $file = substr($file, 0, dol_strlen($file) - 4); + + require_once $dir.'/'.$file.'.php'; + + $module = new $file($db); + '@phan-var-force ModeleNumRefMyObject $module'; + + if ($module->version == 'development' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 2) { + continue; + } + if ($module->version == 'experimental' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 1) { + continue; + } + if (!$module->isEnabled()) { + continue; + } + + dol_include_once('/'.$moduledir.'/class/'.strtolower($myTmpObjectKey).'.class.php'); + + print ''; + + print ''."\n"; + + print ''; + + $className = $myTmpObjectArray['class']; + $mytmpinstance = new $className($db); + '@phan-var-force MyObject $mytmpinstance'; + $mytmpinstance->initAsSpecimen(); + + $htmltooltip = ''; + $htmltooltip .= ''.$langs->trans("Version").': '.$module->getVersion().'
'; + + $nextval = $module->getNextValue($mytmpinstance); + if ("$nextval" != $langs->trans("NotAvailable")) { + $htmltooltip .= ''.$langs->trans("NextValue").': '; + if ($nextval) { + if (preg_match('/^Error/', $nextval) || $nextval == 'NotConfigured') { + $nextval = $langs->trans($nextval); + } + $htmltooltip .= $nextval.'
'; + } else { + $htmltooltip .= $langs->trans($module->error).'
'; + } + } + + print ''; + + print "\n"; + } + + closedir($handle); } - print "
'.$langs->trans("Name").''.$langs->trans("Description").''.$langs->trans("Example").''.$langs->trans("Status").''.$langs->trans("ShortInfo").''.$langs->trans($myTmpObjectArray['label']).'
'.$module->getName($langs)."\n"; - print $module->info($langs); - print ''; - $tmp = $module->getExample(); - if (preg_match('/^Error/', $tmp)) { - $langs->load("errors"); - print '
'.$langs->trans($tmp).'
'; - } elseif ($tmp == 'NotConfigured') { - print $langs->trans($tmp); - } else { - print $tmp; - } - print '
'; - $constforvar = 'MYMODULE_'.strtoupper($myTmpObjectKey).'_ADDON'; - $defaultifnotset = 'thevaluetousebydefault'; - $activenumberingmodel = getDolGlobalString($constforvar, $defaultifnotset); - if ($activenumberingmodel == $file) { - print img_picto($langs->trans("Activated"), 'switch_on'); - } else { - print ''; - print img_picto($langs->trans("Disabled"), 'switch_off'); - print ''; - } - print ''; - print $form->textwithpicto('', $htmltooltip, 1, 'info'); - print '
'.$module->getName($langs)."\n"; + print $module->info($langs); + print ''; + $tmp = $module->getExample(); + if (preg_match('/^Error/', $tmp)) { + $langs->load("errors"); + print '
'.$langs->trans($tmp).'
'; + } elseif ($tmp == 'NotConfigured') { + print $langs->trans($tmp); + } else { + print $tmp; + } + print '
'; + $constforvar = 'MYMODULE_'.strtoupper($myTmpObjectKey).'_ADDON'; + $defaultifnotset = 'thevaluetousebydefault'; + $activenumberingmodel = getDolGlobalString($constforvar, $defaultifnotset); + + if ($activenumberingmodel == $file) { + print img_picto($langs->trans("Activated"), 'switch_on'); + } else { + print ''; + print img_picto($langs->trans("Disabled"), 'switch_off'); + print ''; + } + print ''; + print $form->textwithpicto('', $htmltooltip, 1, 'info'); + print '

\n"; + + print '
'."\n"; } - if (!empty($myTmpObjectArray['includedocgeneration'])) { - /* - * Document templates generators - */ - $setupnotempty++; + print "
\n"; +} + +// Document templates generators +if (!empty($docGenerationObjects)) { + $setupnotempty++; + + print load_fiche_titre($langs->trans("DocumentModules"), '', ''); + + print ''."\n"; + print ''."\n"; + print ''; + print ''; + print '\n"; + print '\n"; + print ''; + print ''; + print "\n"; + + clearstatcache(); + + foreach ($docGenerationObjects as $myTmpObjectKey => $myTmpObjectArray) { + if (empty($myTmpObjectArray['includedocgeneration'])) { + continue; + } + $type = strtolower($myTmpObjectKey); - print load_fiche_titre($langs->trans("DocumentModules", $myTmpObjectKey), '', ''); + print ''; + print ''; + print ''."\n"; - // Load array def with activated templates $def = array(); - // TODO Replace with $def = getListOfModels($db, $type); + $sql = "SELECT nom"; $sql .= " FROM ".$db->prefix()."document_model"; $sql .= " WHERE type = '".$db->escape($type)."'"; $sql .= " AND entity = ".$conf->entity; + $resql = $db->query($sql); if ($resql) { $i = 0; @@ -498,125 +542,139 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) { dol_print_error($db); } - print '
'.$langs->trans("Name").''.$langs->trans("Description").''.$langs->trans("Status")."'.$langs->trans("Default")."'.$langs->trans("ShortInfo").''.$langs->trans("Preview").'
'.$langs->trans($myTmpObjectArray['label']).'
'."\n"; - print ''."\n"; - print ''; - print ''; - print '\n"; - print '\n"; - print ''; - print ''; - print "\n"; - - clearstatcache(); - foreach ($dirmodels as $reldir) { foreach (array('', '/doc') as $valdir) { $realpath = $reldir."core/modules/".$moduledir.$valdir; $dir = dol_buildpath($realpath); - if (is_dir($dir)) { - $handle = opendir($dir); - if (is_resource($handle)) { - $filelist = array(); - while (($file = readdir($handle)) !== false) { - $filelist[] = $file; - } - closedir($handle); - arsort($filelist); + if (!is_dir($dir)) { + continue; + } - foreach ($filelist as $file) { - if (preg_match('/\.modules\.php$/i', $file) && preg_match('/^(pdf_|doc_)/', $file)) { - if (file_exists($dir.'/'.$file)) { - $name = substr($file, 4, dol_strlen($file) - 16); - $className = substr($file, 0, dol_strlen($file) - 12); + $handle = opendir($dir); + if (!is_resource($handle)) { + continue; + } - require_once $dir.'/'.$file; - $module = new $className($db); - '@phan-var-force ModelePDFMyObject $module'; + $filelist = array(); - $modulequalified = 1; - if ($module->version == 'development' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 2) { - $modulequalified = 0; - } - if ($module->version == 'experimental' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 1) { - $modulequalified = 0; - } + while (($file = readdir($handle)) !== false) { + $filelist[] = $file; + } + closedir($handle); - if ($modulequalified) { - print ''; + arsort($filelist); - // Active - if (in_array($name, $def)) { - print ''; - } else { - print '"; - } - - // Default - print ''; - - // Info - $htmltooltip = ''.$langs->trans("Name").': '.$module->name; - $htmltooltip .= '
'.$langs->trans("Type").': '.($module->type ? $module->type : $langs->trans("Unknown")); - if ($module->type == 'pdf') { - $htmltooltip .= '
'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur; - } - $htmltooltip .= '
'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file; - - $htmltooltip .= '

'.$langs->trans("FeaturesSupported").':'; - $htmltooltip .= '
'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1); - $htmltooltip .= '
'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1); - - print ''; - - // Preview - print ''; - - print "\n"; - } - } - } - } + foreach ($filelist as $file) { + if (!preg_match('/\.modules\.php$/i', $file) || !preg_match('/^(pdf_|doc_)/', $file)) { + continue; } + + if (!preg_match('/_'.preg_quote($type, '/').'(_odt)?\.modules\.php$/i', $file)) { + continue; + } + + if (!file_exists($dir.'/'.$file)) { + continue; + } + + $name = substr($file, 4, dol_strlen($file) - 16); + $className = substr($file, 0, dol_strlen($file) - 12); + + require_once $dir.'/'.$file; + + $module = new $className($db); + '@phan-var-force ModelePDFMyObject $module'; + + $modulequalified = 1; + if ($module->version == 'development' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 2) { + $modulequalified = 0; + } + if ($module->version == 'experimental' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 1) { + $modulequalified = 0; + } + + if (!$modulequalified) { + continue; + } + + print ''; + + if (in_array($name, $def)) { + print ''; + } else { + print '"; + } + + print ''; + + $htmltooltip = ''.$langs->trans("Name").': '.$module->name; + $htmltooltip .= '
'.$langs->trans("Type").': '.($module->type ? $module->type : $langs->trans("Unknown")); + + if ($module->type == 'pdf') { + $htmltooltip .= '
'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur; + } + + $htmltooltip .= '
'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file; + $htmltooltip .= '

'.$langs->trans("FeaturesSupported").':'; + $htmltooltip .= '
'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1); + $htmltooltip .= '
'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1); + + print ''; + + print ''; + + print "\n"; } } } - print '
'.$langs->trans("Name").''.$langs->trans("Description").''.$langs->trans("Status")."'.$langs->trans("Default")."'.$langs->trans("ShortInfo").''.$langs->trans("Preview").'
'; - print(empty($module->name) ? $name : $module->name); - print "\n"; - if (method_exists($module, 'info')) { - print $module->info($langs); // @phan-suppress-current-line PhanUndeclaredMethod - } else { - print $module->description; - } - print ''."\n"; - print ''; - print img_picto($langs->trans("Enabled"), 'switch_on'); - print ''; - print ''."\n"; - print 'scandir).'&label='.urlencode($module->name).'">'.img_picto($langs->trans("Disabled"), 'switch_off').''; - print "'; - $constforvar = 'MYMODULE_'.strtoupper($myTmpObjectKey).'_ADDON_PDF'; - if (getDolGlobalString($constforvar) == $name) { - //print img_picto($langs->trans("Default"), 'on'); - // Even if choice is the default value, we allow to disable it. Replace this with previous line if you need to disable unset - print 'scandir).'&label='.urlencode($module->name).'&type='.urlencode($type).'" alt="'.$langs->trans("Disable").'">'.img_picto($langs->trans("Enabled"), 'on').''; - } else { - print 'scandir).'&label='.urlencode($module->name).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"), 'off').''; - } - print ''; - print $form->textwithpicto('', $htmltooltip, 1, 'info'); - print ''; - if ($module->type == 'pdf') { - $newname = preg_replace('/_'.preg_quote(strtolower($myTmpObjectKey), '/').'/', '', $name); - print ''.img_object($langs->trans("Preview"), 'pdf').''; - } else { - print img_object($langs->transnoentitiesnoconv("PreviewNotAvailable"), 'generic'); - } - print '
'; + print(empty($module->name) ? $name : $module->name); + print "\n"; + + if (method_exists($module, 'info')) { + print $module->info($langs); // @phan-suppress-current-line PhanUndeclaredMethod + } else { + print $module->description; + } + + print ''."\n"; + print ''; + print img_picto($langs->trans("Enabled"), 'switch_on'); + print ''; + print ''."\n"; + print 'scandir).'&label='.urlencode($module->name).'&type='.urlencode($type).'">'; + print img_picto($langs->trans("Disabled"), 'switch_off'); + print ''; + print "'; + $constforvar = 'MYMODULE_'.strtoupper($myTmpObjectKey).'_ADDON_PDF'; + + if (getDolGlobalString($constforvar) == $name) { + print 'scandir).'&label='.urlencode($module->name).'&type='.urlencode($type).'" alt="'.$langs->trans("Disable").'">'; + print img_picto($langs->trans("Enabled"), 'on'); + print ''; + } else { + print 'scandir).'&label='.urlencode($module->name).'&type='.urlencode($type).'" alt="'.$langs->trans("Default").'">'; + print img_picto($langs->trans("Disabled"), 'off'); + print ''; + } + + print ''; + print $form->textwithpicto('', $htmltooltip, 1, 'info'); + print ''; + if ($module->type == 'pdf') { + $newname = preg_replace('/_'.preg_quote($type, '/').'/', '', $name); + print ''; + print img_object($langs->trans("Preview"), 'pdf'); + print ''; + } else { + print img_object($langs->transnoentitiesnoconv("PreviewNotAvailable"), 'generic'); + } + print '
'; + print '
'."\n"; } + + print ''; } if (empty($setupnotempty)) {