Refactor modulebuilder setup UI for numbering and document models (#38008)

* 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
This commit is contained in:
Milen Karaganski 2026-04-27 15:53:59 +03:00 committed by GitHub
parent 8ccb7dfd16
commit cb317ddc11
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -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 '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<td>'.$langs->trans("Name").'</td>';
print '<td>'.$langs->trans("Description").'</td>';
print '<td class="nowrap">'.$langs->trans("Example").'</td>';
print '<td class="center" width="60">'.$langs->trans("Status").'</td>';
print '<td class="center" width="16">'.$langs->trans("ShortInfo").'</td>';
print '</tr>'."\n";
clearstatcache();
foreach ($refGenerationObjects as $myTmpObjectKey => $myTmpObjectArray) {
if (empty($myTmpObjectArray['includerefgeneration'])) {
continue;
}
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<td>'.$langs->trans("Name").'</td>';
print '<td>'.$langs->trans("Description").'</td>';
print '<td class="nowrap">'.$langs->trans("Example").'</td>';
print '<td class="center" width="60">'.$langs->trans("Status").'</td>';
print '<td class="center" width="16">'.$langs->trans("ShortInfo").'</td>';
print '<td colspan="5"><strong>'.$langs->trans($myTmpObjectArray['label']).'</strong></td>';
print '</tr>'."\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 '<tr class="oddeven"><td>'.$module->getName($langs)."</td><td>\n";
print $module->info($langs);
print '</td>';
// Show example of numbering model
print '<td class="nowrap">';
$tmp = $module->getExample();
if (preg_match('/^Error/', $tmp)) {
$langs->load("errors");
print '<div class="error">'.$langs->trans($tmp).'</div>';
} elseif ($tmp == 'NotConfigured') {
print $langs->trans($tmp);
} else {
print $tmp;
}
print '</td>'."\n";
print '<td class="center">';
$constforvar = 'MYMODULE_'.strtoupper($myTmpObjectKey).'_ADDON';
$defaultifnotset = 'thevaluetousebydefault';
$activenumberingmodel = getDolGlobalString($constforvar, $defaultifnotset);
if ($activenumberingmodel == $file) {
print img_picto($langs->trans("Activated"), 'switch_on');
} else {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=setmod&token='.newToken().'&object='.strtolower($myTmpObjectKey).'&value='.urlencode($file).'">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a>';
}
print '</td>';
$className = $myTmpObjectArray['class'];
$mytmpinstance = new $className($db);
'@phan-var-force MyObject $mytmpinstance';
$mytmpinstance->initAsSpecimen();
// Info
$htmltooltip = '';
$htmltooltip .= ''.$langs->trans("Version").': <b>'.$module->getVersion().'</b><br>';
$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.'<br>';
} else {
$htmltooltip .= $langs->trans($module->error).'<br>';
}
}
print '<td class="center">';
print $form->textwithpicto('', $htmltooltip, 1, 'info');
print '</td>';
print "</tr>\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 '<tr class="oddeven"><td>'.$module->getName($langs)."</td><td>\n";
print $module->info($langs);
print '</td>';
print '<td class="nowrap">';
$tmp = $module->getExample();
if (preg_match('/^Error/', $tmp)) {
$langs->load("errors");
print '<div class="error">'.$langs->trans($tmp).'</div>';
} elseif ($tmp == 'NotConfigured') {
print $langs->trans($tmp);
} else {
print $tmp;
}
print '</td>'."\n";
print '<td class="center">';
$constforvar = 'MYMODULE_'.strtoupper($myTmpObjectKey).'_ADDON';
$defaultifnotset = 'thevaluetousebydefault';
$activenumberingmodel = getDolGlobalString($constforvar, $defaultifnotset);
if ($activenumberingmodel == $file) {
print img_picto($langs->trans("Activated"), 'switch_on');
} else {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=setmod&token='.newToken().'&object='.urlencode(strtolower($myTmpObjectKey)).'&value='.urlencode($file).'">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a>';
}
print '</td>';
$className = $myTmpObjectArray['class'];
$mytmpinstance = new $className($db);
'@phan-var-force MyObject $mytmpinstance';
$mytmpinstance->initAsSpecimen();
$htmltooltip = '';
$htmltooltip .= ''.$langs->trans("Version").': <b>'.$module->getVersion().'</b><br>';
$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.'<br>';
} else {
$htmltooltip .= $langs->trans($module->error).'<br>';
}
}
print '<td class="center">';
print $form->textwithpicto('', $htmltooltip, 1, 'info');
print '</td>';
print "</tr>\n";
}
closedir($handle);
}
print "</table><br>\n";
print '<tr><td colspan="5"><br></td></tr>'."\n";
}
if (!empty($myTmpObjectArray['includedocgeneration'])) {
/*
* Document templates generators
*/
$setupnotempty++;
print "</table><br>\n";
}
// Document templates generators
if (!empty($docGenerationObjects)) {
$setupnotempty++;
print load_fiche_titre($langs->trans("DocumentModules"), '', '');
print '<table class="noborder centpercent">'."\n";
print '<tr class="liste_titre">'."\n";
print '<td>'.$langs->trans("Name").'</td>';
print '<td>'.$langs->trans("Description").'</td>';
print '<td class="center" width="60">'.$langs->trans("Status")."</td>\n";
print '<td class="center" width="60">'.$langs->trans("Default")."</td>\n";
print '<td class="center" width="38">'.$langs->trans("ShortInfo").'</td>';
print '<td class="center" width="38">'.$langs->trans("Preview").'</td>';
print "</tr>\n";
clearstatcache();
foreach ($docGenerationObjects as $myTmpObjectKey => $myTmpObjectArray) {
if (empty($myTmpObjectArray['includedocgeneration'])) {
continue;
}
$type = strtolower($myTmpObjectKey);
print load_fiche_titre($langs->trans("DocumentModules", $myTmpObjectKey), '', '');
print '<tr class="liste_titre">';
print '<td colspan="6"><strong>'.$langs->trans($myTmpObjectArray['label']).'</strong></td>';
print '</tr>'."\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 '<table class="noborder centpercent">'."\n";
print '<tr class="liste_titre">'."\n";
print '<td>'.$langs->trans("Name").'</td>';
print '<td>'.$langs->trans("Description").'</td>';
print '<td class="center" width="60">'.$langs->trans("Status")."</td>\n";
print '<td class="center" width="60">'.$langs->trans("Default")."</td>\n";
print '<td class="center" width="38">'.$langs->trans("ShortInfo").'</td>';
print '<td class="center" width="38">'.$langs->trans("Preview").'</td>';
print "</tr>\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 '<tr class="oddeven"><td width="100">';
print(empty($module->name) ? $name : $module->name);
print "</td><td>\n";
if (method_exists($module, 'info')) {
print $module->info($langs); // @phan-suppress-current-line PhanUndeclaredMethod
} else {
print $module->description;
}
print '</td>';
arsort($filelist);
// Active
if (in_array($name, $def)) {
print '<td class="center">'."\n";
print '<a href="'.$_SERVER["PHP_SELF"].'?action=del&token='.newToken().'&value='.urlencode($name).'">';
print img_picto($langs->trans("Enabled"), 'switch_on');
print '</a>';
print '</td>';
} else {
print '<td class="center">'."\n";
print '<a href="'.$_SERVER["PHP_SELF"].'?action=set&token='.newToken().'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'">'.img_picto($langs->trans("Disabled"), 'switch_off').'</a>';
print "</td>";
}
// Default
print '<td class="center">';
$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 '<a href="'.$_SERVER["PHP_SELF"].'?action=unsetdoc&token='.newToken().'&object='.urlencode(strtolower($myTmpObjectKey)).'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'&amp;type='.urlencode($type).'" alt="'.$langs->trans("Disable").'">'.img_picto($langs->trans("Enabled"), 'on').'</a>';
} else {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=setdoc&token='.newToken().'&object='.urlencode(strtolower($myTmpObjectKey)).'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"), 'off').'</a>';
}
print '</td>';
// Info
$htmltooltip = ''.$langs->trans("Name").': '.$module->name;
$htmltooltip .= '<br>'.$langs->trans("Type").': '.($module->type ? $module->type : $langs->trans("Unknown"));
if ($module->type == 'pdf') {
$htmltooltip .= '<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
}
$htmltooltip .= '<br>'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file;
$htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
$htmltooltip .= '<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
$htmltooltip .= '<br>'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1);
print '<td class="center">';
print $form->textwithpicto('', $htmltooltip, 1, 'info');
print '</td>';
// Preview
print '<td class="center">';
if ($module->type == 'pdf') {
$newname = preg_replace('/_'.preg_quote(strtolower($myTmpObjectKey), '/').'/', '', $name);
print '<a href="'.$_SERVER["PHP_SELF"].'?action=specimen&module='.urlencode($newname).'&object='.urlencode($myTmpObjectKey).'">'.img_object($langs->trans("Preview"), 'pdf').'</a>';
} else {
print img_object($langs->transnoentitiesnoconv("PreviewNotAvailable"), 'generic');
}
print '</td>';
print "</tr>\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 '<tr class="oddeven"><td width="100">';
print(empty($module->name) ? $name : $module->name);
print "</td><td>\n";
if (method_exists($module, 'info')) {
print $module->info($langs); // @phan-suppress-current-line PhanUndeclaredMethod
} else {
print $module->description;
}
print '</td>';
if (in_array($name, $def)) {
print '<td class="center">'."\n";
print '<a href="'.$_SERVER["PHP_SELF"].'?action=del&token='.newToken().'&object='.urlencode($type).'&value='.urlencode($name).'&type='.urlencode($type).'">';
print img_picto($langs->trans("Enabled"), 'switch_on');
print '</a>';
print '</td>';
} else {
print '<td class="center">'."\n";
print '<a href="'.$_SERVER["PHP_SELF"].'?action=set&token='.newToken().'&object='.urlencode($type).'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'&type='.urlencode($type).'">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a>';
print "</td>";
}
print '<td class="center">';
$constforvar = 'MYMODULE_'.strtoupper($myTmpObjectKey).'_ADDON_PDF';
if (getDolGlobalString($constforvar) == $name) {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=unsetdoc&token='.newToken().'&object='.urlencode($type).'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'&amp;type='.urlencode($type).'" alt="'.$langs->trans("Disable").'">';
print img_picto($langs->trans("Enabled"), 'on');
print '</a>';
} else {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=setdoc&token='.newToken().'&object='.urlencode($type).'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'&type='.urlencode($type).'" alt="'.$langs->trans("Default").'">';
print img_picto($langs->trans("Disabled"), 'off');
print '</a>';
}
print '</td>';
$htmltooltip = ''.$langs->trans("Name").': '.$module->name;
$htmltooltip .= '<br>'.$langs->trans("Type").': '.($module->type ? $module->type : $langs->trans("Unknown"));
if ($module->type == 'pdf') {
$htmltooltip .= '<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
}
$htmltooltip .= '<br>'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file;
$htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
$htmltooltip .= '<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
$htmltooltip .= '<br>'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1);
print '<td class="center">';
print $form->textwithpicto('', $htmltooltip, 1, 'info');
print '</td>';
print '<td class="center">';
if ($module->type == 'pdf') {
$newname = preg_replace('/_'.preg_quote($type, '/').'/', '', $name);
print '<a href="'.$_SERVER["PHP_SELF"].'?action=specimen&module='.urlencode($newname).'&object='.urlencode($type).'">';
print img_object($langs->trans("Preview"), 'pdf');
print '</a>';
} else {
print img_object($langs->transnoentitiesnoconv("PreviewNotAvailable"), 'generic');
}
print '</td>';
print "</tr>\n";
}
}
}
print '</table>';
print '<tr><td colspan="6"><br></td></tr>'."\n";
}
print '</table>';
}
if (empty($setupnotempty)) {