N°9144 Fix static analysis issues (#885)

* N°9144 Fix static analysis issues with phpstan
* up to level 1 for all setup files
* up to level 5 for all wizardsteps
This commit is contained in:
Timmy38
2026-04-23 14:08:22 +02:00
committed by GitHub
parent fc2cb86122
commit d0ddb35f8d
27 changed files with 71 additions and 72 deletions

View File

@@ -152,9 +152,9 @@ try {
$sConfigFile = utils::GetConfigFilePath(ITOP_DEFAULT_ENV);
if (file_exists($sConfigFile) && !is_writable($sConfigFile) && $oStep->RequiresWritableConfig()) {
$sRelativePath = utils::GetConfigFilePathRelative(ITOP_DEFAULT_ENV);
$oPage->error("<b>Error:</b> the configuration file '".$sRelativePath."' already exists and cannot be overwritten.");
$oPage->p("The wizard cannot modify the configuration file for you. If you want to upgrade ".ITOP_APPLICATION.", make sure that the file '<b>".$sRelativePath."</b>' can be modified by the web server.");
$oPage->output();
$sErrorMsg = "<b>Error:</b> the configuration file '".$sRelativePath."' already exists and cannot be overwritten.";
$sErrorMsg .= "The wizard cannot modify the configuration file for you. If you want to upgrade ".ITOP_APPLICATION.", make sure that the file '<b>".$sRelativePath."</b>' can be modified by the web server.";
throw new Exception($sErrorMsg);
} else {
$oStep->AsyncAction($oPage, $sActionCode, $aParams);
}
@@ -180,9 +180,5 @@ try {
}
if (function_exists('memory_get_peak_usage')) {
if ($sOperation == 'file') {
SetupLog::Info("loading file '$sFileName', peak memory usage. ".memory_get_peak_usage());
} else {
SetupLog::Info("operation '$sOperation', peak memory usage. ".memory_get_peak_usage());
}
SetupLog::Info("operation '$sOperation', peak memory usage. ".memory_get_peak_usage());
}

View File

@@ -136,7 +136,7 @@ class DBBackup
/**
* Create a normalized backup name, depending on the current date/time and Database
*
* @param string sMySQLBinDir Name and path, eventually containing itop placeholders + time formatting specs
* @param string $sMySQLBinDir Name and path, eventually containing itop placeholders + time formatting specs
*/
public function SetMySQLBinDir($sMySQLBinDir)
{

View File

@@ -29,7 +29,7 @@ if (!class_exists('DOMDocument')) {
*/
class DOMDocument
{
public function __construct()
public function __construct(string $version = "1.0", string $encoding = "")
{
throw new Exception('The dom extension is not enabled');
}
@@ -45,7 +45,7 @@ if (!class_exists('DOMElement')) {
*/
class DOMElement
{
public function __construct()
public function __construct(string $qualifiedName, ?string $value = null, string $namespace = "")
{
throw new Exception('The dom extension is not enabled');
}

View File

@@ -1562,14 +1562,7 @@ EOF;
foreach ($aStatesOrder as $sState => $foo) {
$oState = $aStates[$sState];
$oInitialStatePath = $oState->GetOptionalElement('initial_state_path');
if ($oInitialStatePath) {
$aInitialStatePath = [];
foreach ($oInitialStatePath->getElementsByTagName('state_ref') as $oIntermediateState) {
$aInitialStatePath[] = "'".$oIntermediateState->GetText()."'";
}
$sInitialStatePath = 'Array('.implode(', ', $aInitialStatePath).')';
}
$sLifecycle .= " MetaModel::Init_DefineState(\n";
$sLifecycle .= " \"".$sState."\",\n";
$sLifecycle .= " array(\n";
@@ -1597,6 +1590,11 @@ EOF;
$sLifecycle .= " ),\n";
if (!is_null($oInitialStatePath)) {
$aInitialStatePath = [];
foreach ($oInitialStatePath->getElementsByTagName('state_ref') as $oIntermediateState) {
$aInitialStatePath[] = "'".$oIntermediateState->GetText()."'";
}
$sInitialStatePath = 'Array('.implode(', ', $aInitialStatePath).')';
$sLifecycle .= " \"initial_state_path\" => $sInitialStatePath,\n";
}
$sLifecycle .= " )\n";
@@ -2487,6 +2485,8 @@ EOF
// Generate SCSS declaration
$sScss = "";
$sMainColorCssVariableName = null;
$sComplementaryColorCssVariableName = null;
if ($bHasAtLeastOneColor) {
if ($bHasMainColor) {
$sMainColorScssVariableName = "\$$sCssRegularClass--main-color";
@@ -2503,8 +2503,10 @@ EOF
$sCssAlternativeClassComplementaryColorDeclaration = "--ibo-complementary-color: #{{$sMainColorScssVariableName}};";
} else {
$sMainColorScssVariableDeclaration = null;
$sMainColorCssVariableDeclaration = null;
$sCssRegularClassMainColorDeclaration = null;
$sCssRegularClassMainColor100Declaration = null;
$sCssRegularClassMainColor900Declaration = null;
$sCssAlternativeClassComplementaryColorDeclaration = null;
@@ -3358,6 +3360,7 @@ EOF;
clearstatcache();
$iDataXmlFileLastModified = 0;
$sDataXmlProvidedPrecompiledFile = '';
if (!empty($sPrecompiledFileUri)) {
$sDataXmlProvidedPrecompiledFile = $sTempTargetDir.DIRECTORY_SEPARATOR.$sPrecompiledFileUri;
$bDataXmlPrecompiledFileExists = file_exists($sDataXmlProvidedPrecompiledFile) ;
@@ -3371,7 +3374,6 @@ EOF;
APPROOT.DIRECTORY_SEPARATOR.'extensions/',
];
$iDataXmlFileLastModified = 0;
foreach ($aDirToCheck as $sDir) {
$sCurrentFile = $sDir.DIRECTORY_SEPARATOR.$sPrecompiledFileUri;
if (is_file($sCurrentFile)) {

View File

@@ -73,7 +73,7 @@ class iTopExtension
public $bVisible;
/**
* @var string[]
* @var array
*/
public $aModules;
@@ -83,7 +83,7 @@ class iTopExtension
public $aModuleVersion;
/**
* @var string[]
* @var array
*/
public $aModuleInfo;
@@ -94,7 +94,7 @@ class iTopExtension
/**
*
* @var string[]
* @var array
*/
public $aMissingDependencies;
/**

View File

@@ -1288,7 +1288,7 @@ class ModelFactory
if ($bExcludeWorkspace) {
$aModules = [];
foreach (self::$aLoadedModules as $oModule) {
if (!$oModule instanceof MFWorkspace) {
if (!class_exists('MFWorkspace') || !$oModule instanceof MFWorkspace) {
$aModules[] = $oModule;
}
}

View File

@@ -34,7 +34,7 @@ class MissingDependencyException extends CoreException
{
/**
* @see \ModuleDiscovery::OrderModulesByDependencies property init
* @var array<string, array<string>>
* @var array<string, array<array>>
* module id as key
* another array as value, containing : 'module' with module info, 'dependencies' with missing dependencies
*/
@@ -410,6 +410,7 @@ class ModuleDiscovery
continue;
}
/** @var array|null $aCurrentModuleInfo */
$aCurrentModuleInfo = $oExtension->aModuleInfo[$sModuleName] ?? null;
if (is_null($aCurrentModuleInfo)) {
SetupLog::Warning("Missing $sModuleName in ".$oExtension->sLabel.". it should not happen");

View File

@@ -57,9 +57,8 @@ class ApplicationInstallSequencer extends StepSequencer
*/
public function ExecuteStep($sStep = '', $sInstallComment = null): array
{
$fStart = microtime(true);
try {
$fStart = microtime(true);
/**
* @since 3.2.0 move the ContextTag init at the very beginning of the method
* @noinspection PhpUnusedLocalVariableInspection

View File

@@ -33,9 +33,8 @@ class DataAuditSequencer extends StepSequencer
*/
public function ExecuteStep($sStep = '', $sInstallComment = null): array
{
$fStart = microtime(true);
try {
$fStart = microtime(true);
/**
* @since 3.2.0 move the ContextTag init at the very beginning of the method
* @noinspection PhpUnusedLocalVariableInspection

View File

@@ -58,7 +58,7 @@ class CheckResult
/**
* @param \CheckResult[] $aResults
* @param string[] $aCheckResultSeverities list of CheckResult object severities to keep
* @param array $aCheckResultSeverities list of CheckResult object severities to keep
*
* @return \CheckResult[] only elements that have one of the passed severity
*
@@ -458,6 +458,7 @@ class SetupUtils
);
$sPhpNextMinVersion = self::PHP_NEXT_MIN_VERSION; // mandatory before PHP 5.5 (arbitrary expressions), keeping compat because we're in the setup !
// @phpstan-ignore empty.variable
if (!empty($sPhpNextMinVersion)) {
if (version_compare($sPhpVersion, self::PHP_NEXT_MIN_VERSION, '>=')) {
$aResult[] = new CheckResult(
@@ -1351,6 +1352,7 @@ EOF
);
$sMySqlNextMinVersion = self::MYSQL_NEXT_MIN_VERSION; // mandatory before PHP 5.5 (arbitrary expressions), keeping compat because we're in the setup !
// @phpstan-ignore empty.variable
if (!empty($sMySqlNextMinVersion)) {
if (version_compare($sDBVersion, self::MYSQL_NEXT_MIN_VERSION, '>=')) {
$aResult['checks'][] = new CheckResult(
@@ -1675,8 +1677,8 @@ JS
* @param string $sSourceDir Relative path to the directory to check under $sBaseDir
* @param $aManifest
* @param array $aExcludeNames
* @param Hash $aResult Used for recursion
* @return hash Hash array ('added' => array(), 'removed' => array(), 'modified' => array())
* @param array $aResult Used for recursion
* @return array array ('added' => array(), 'removed' => array(), 'modified' => array())
* @internal param array $aDOMManifest Array of array('path' => relative_path 'size'=> iSize, 'md5' => sHexMD5)
*/
public static function CheckDirAgainstManifest($sBaseDir, $sSourceDir, $aManifest, $aExcludeNames = ['.svn', '.git'], $aResult = null)
@@ -1801,7 +1803,7 @@ JS
/**
* @param string $sInstalledVersion
* @param string $sSourceDir
* @return bool|hash
* @return bool|array
* @throws Exception
*/
public static function CheckVersion($sInstalledVersion, $sSourceDir)

View File

@@ -67,7 +67,7 @@ class WizardController
/**
* Removes information about the previous step from the stack
* @return hash Array('class' => , 'state' => )
* @return array{'class': string, 'state': string}
*/
protected function PopStep()
{
@@ -186,9 +186,12 @@ class WizardController
/**
* Displays the specified 'step' of the wizard
*
* @param WizardStep $oStep The 'step' to display
*
* @throws \Exception
*/
protected function DisplayStep(WizardStep $oStep)
protected function DisplayStep(WizardStep $oStep): void
{
SetupLog::Info("=== Setup screen: ".$oStep->GetTitle().' ('.get_class($oStep).')');
$oPage = new SetupPage($oStep->GetTitle());
@@ -313,7 +316,7 @@ on the page's parameters
* Provides information about the structure/workflow of the wizard by listing
* the possible list of 'steps' and their dependencies
* @param string $sStep Name of the class to start from (used for recursion)
* @param hash $aAllSteps List of steps (used for recursion)
* @param array $aAllSteps List of steps (used for recursion)
*/
public function DumpStructure($sStep = '', $aAllSteps = null)
{

View File

@@ -44,7 +44,7 @@ class WizStepAdminAccount extends WizardStep
return new WizardState(WizStepInstallMiscParams::class);
}
public function Display(WebPage $oPage)
public function Display(SetupPage $oPage): void
{
$sAdminUser = $this->oWizard->GetParameter('admin_user', 'admin');
$sAdminPwd = $this->oWizard->GetParameter('admin_pwd', '');

View File

@@ -51,7 +51,7 @@ class WizStepDBParams extends WizardStep
return new WizardState(WizStepAdminAccount::class);
}
public function Display(WebPage $oPage)
public function Display(SetupPage $oPage): void
{
$oPage->add('<h2>Configuration of the database connection:</h2>');
$sDBServer = $this->oWizard->GetParameter('db_server', '');

View File

@@ -64,7 +64,7 @@ class WizStepDataAudit extends WizStepInstall
return false;
}
public function Display(WebPage $oPage)
public function Display(SetupPage $oPage): void
{
$aInstallParams = $this->BuildConfig();

View File

@@ -69,11 +69,11 @@ class WizStepDetectedInfo extends WizardStep
}
/**
* @param WebPage $oPage
* @param \SetupPage $oPage
*
* @throws Exception
*/
public function Display(WebPage $oPage)
public function Display(SetupPage $oPage): void
{
$oPage->add_style(
<<<EOF

View File

@@ -39,7 +39,7 @@ class WizStepDone extends WizardStep
return new WizardState('');
}
public function Display(WebPage $oPage)
public function Display(SetupPage $oPage): void
{
// Check if there are some manual steps required:
$aManualSteps = [];
@@ -102,9 +102,9 @@ class WizStepDone extends WizardStep
$sSetupTokenFile = APPROOT.'data/.setup';
$sSetupToken = bin2hex(random_bytes(12));
file_put_contents($sSetupTokenFile, $sSetupToken);
$sIframeUrl .= "&setup_token=$sSetupToken";
if ($sIframeUrl != '') {
if (mb_strlen($sIframeUrl) > 0) {
$sIframeUrl .= "&setup_token=$sSetupToken";
$oPage->add('<iframe id="fresh_content" frameborder="0" scrolling="auto" src="'.$sIframeUrl.'"></iframe>');
$oPage->add_script("

View File

@@ -70,7 +70,7 @@ class WizStepInstall extends AbstractWizStepInstall
$oPage->add("<div class=\"message message-error ibo-is-html-content\" style=\"display:none;\" id=\"setup_error\"></div>");
}
public function Display(WebPage $oPage)
public function Display(SetupPage $oPage): void
{
$aInstallParams = $this->BuildConfig();
$this->AddProgressBar($oPage, 'Progress of the installation');

View File

@@ -44,7 +44,7 @@ class WizStepInstallMiscParams extends AbstractWizStepMiscParams
return new WizardState(WizStepModulesChoice::class, 'start_install');
}
public function Display(WebPage $oPage)
public function Display(SetupPage $oPage): void
{
$sDefaultLanguage = $this->oWizard->GetParameter('default_language', $this->oWizard->GetParameter('admin_language'));
$sApplicationURL = $this->oWizard->GetParameter('application_url', utils::GetDefaultUrlAppRoot(true));

View File

@@ -62,7 +62,7 @@ class WizStepInstallOrUpgrade extends WizardStep
return new WizardState($sNextStep);
}
public function Display(WebPage $oPage)
public function Display(SetupPage $oPage): void
{
$sInstallMode = $this->oWizard->GetParameter('install_mode', '');
$sDBServer = $this->oWizard->GetParameter('db_server', '');
@@ -121,8 +121,7 @@ HTML
$sDBName,
$sDBPrefix,
$sTlsEnabled,
$sTlsCA,
null
$sTlsCA
);
$sAuthentToken = $this->oWizard->GetParameter('authent', '');

View File

@@ -60,9 +60,9 @@ class WizStepLicense extends WizardStep
}
/**
* @param WebPage $oPage
* @param \SetupPage $oPage
*/
public function Display(WebPage $oPage)
public function Display(SetupPage $oPage): void
{
$aLicenses = SetupUtils::GetLicenses();
$oPage->add_style(

View File

@@ -145,7 +145,7 @@ class WizStepModulesChoice extends WizardStep
throw new Exception('Internal error: invalid step "'.$index.'" for the choice of modules.');
} elseif ($bMoveForward) {
if ($this->GetStepInfo(1 + $index) != null) {
return new WizardState(WizStepModulesChoice::class, (1 + $index));
return new WizardState(WizStepModulesChoice::class, (string)($index +1));
} else {
// Exiting this step of the wizard, let's convert the selection into a list of modules
$aModules = [];
@@ -173,10 +173,10 @@ class WizStepModulesChoice extends WizardStep
}
//Unused when going backward
return new WizardState(WizStepModulesChoice::class, ($index - 1));
return new WizardState(WizStepModulesChoice::class, (string)($index - 1));
}
public function Display(WebPage $oPage)
public function Display(SetupPage $oPage): void
{
$this->DisplayStep($oPage);
}
@@ -390,14 +390,12 @@ EOF
}
if (isset($aChoice['sub_options'])) {
$aScores[$sChoiceId] = array_merge($aScores[$sChoiceId], $this->GuessDefaultsFromModules($aChoice['sub_options'], $aDefaults, $sChoiceId));
$aScores[$sChoiceId] = array_merge($aScores[$sChoiceId], $this->GuessDefaultsFromModules($aChoice['sub_options'], $aDefaults, $aModules, $sChoiceId));
}
$index++;
}
$aAlternatives = isset($aInfo['alternatives']) ? $aInfo['alternatives'] : [];
$sChoiceName = null;
$sChoiceIdNone = null;
foreach ($aAlternatives as $index => $aChoice) {
$sChoiceId = $sParentId.self::$SEP.$index;
$aScores[$sChoiceId] = [];
@@ -413,7 +411,6 @@ EOF
$aScores[$sChoiceId] = $this->GuessDefaultsFromModules($aChoice['sub_options'], $aDefaults, $aModules, $sChoiceId);
}
}
$index++;
}
$iMaxScore = 0;
@@ -517,7 +514,7 @@ EOF
foreach ($aChoice['modules'] as $sModuleId) {
$bSelected = true;
if (isset($aModuleInfo[$sModuleId])) {
// Test if module has 'auto_select'
/** @var array $aCurrentModuleInfo */
$aCurrentModuleInfo = $aModuleInfo[$sModuleId];
if (isset($aCurrentModuleInfo['auto_select'])) {
// Check the module selection
@@ -760,9 +757,6 @@ EOF
foreach ($aAlternatives as $index => $aChoice) {
$sChoiceId = $sParentId.self::$SEP.$index;
if ($sChoiceName === null) {
$sChoiceName = $sChoiceId; // All radios share the same name
}
$bSelected = isset($aSelectedComponents[$sChoiceName]) && ($aSelectedComponents[$sChoiceName] === $sChoiceId);
if (!isset($aSelectedComponents[$sChoiceName]) && ($sChoiceIdNone !== null)) {
// No choice selected, select the "None" option

View File

@@ -65,7 +65,7 @@ class WizStepSummary extends AbstractWizStepInstall
return new WizardState(WizStepInstall::class);
}
public function Display(WebPage $oPage)
public function Display(SetupPage $oPage): void
{
$aInstallParams = $this->BuildConfig();
@@ -100,7 +100,7 @@ class WizStepSummary extends AbstractWizStepInstall
$oPage->add('<div class="closed"><a class="title ibo-setup-summary-title" href="#" aria-label="Extensions to be uninstalled">Extensions to be uninstalled</a>');
$aExtensionsRemoved = json_decode($this->oWizard->GetParameter('removed_extensions'), true) ?? [];
$aExtensionsNotUninstallable = json_decode($this->oWizard->GetParameter('extensions_not_uninstallable'));
$aExtensionsNotUninstallable = json_decode($this->oWizard->GetParameter('extensions_not_uninstallable')) ?? [];
if (count($aExtensionsRemoved) > 0) {
$sExtensionsRemoved = '<ul>';
foreach ($aExtensionsRemoved as $sExtensionCode => $sLabel) {

View File

@@ -44,7 +44,7 @@ class WizStepUpgradeMiscParams extends AbstractWizStepMiscParams
return new WizardState(WizStepModulesChoice::class, 'start_upgrade');
}
public function Display(WebPage $oPage)
public function Display(SetupPage $oPage): void
{
$sApplicationURL = $this->oWizard->GetParameter('application_url', utils::GetAbsoluteUrlAppRoot(true)); //Preserve existing configuration (except for the str_replace based joker $SERVER_NAME$ which is lost)
$sDefaultGraphvizPath = (strtolower(substr(PHP_OS, 0, 3)) === 'win') ? 'C:\\Program Files\\Graphviz\\bin\\dot.exe' : '/usr/bin/dot';

View File

@@ -53,7 +53,7 @@ class WizStepWelcome extends WizardStep
return new WizardState(WizStepInstallOrUpgrade::class);
}
public function Display(WebPage $oPage)
public function Display(SetupPage $oPage): void
{
// Store the misc_options for the future...
$aMiscOptions = utils::ReadParam('option', [], false, 'raw_data');

View File

@@ -2,7 +2,7 @@
class WizardState
{
public function __construct($sNextStep, $sCurrentState = '')
public function __construct(string $sNextStep, string $sCurrentState = '')
{
$this->sNextStep = $sNextStep;
$this->sCurrentState = $sCurrentState;

View File

@@ -107,16 +107,19 @@ abstract class WizardStep
* The page can contain any number of "<input/>" fields, but no "<form>...</form>" tag
* The name of the input fields (and their id if one is supplied) MUST NOT start with "_"
* (this is reserved for the wizard's own parameters)
*
* @param \SetupPage $oPage
*
* @return void
*/
abstract public function Display(WebPage $oPage);
abstract public function Display(SetupPage $oPage): void;
/**
* Processes the page's parameters and (if moving forward) returns the next step/state to be displayed
* @param bool $bMoveForward True if the wizard is moving forward 'Next >>' button pressed, false otherwise
* @return hash array('class' => $sNextClass, 'state' => $sNextState)
* @return WizardState array('class' => $sNextClass, 'state' => $sNextState)
*/
abstract public function UpdateWizardStateAndGetNextStep($bMoveForward = true): WizardState;
abstract public function UpdateWizardStateAndGetNextStep(bool $bMoveForward = true): WizardState;
/**
* Returns the list of possible steps from this step forward
@@ -205,7 +208,7 @@ abstract class WizardStep
/**
* Overload this function to implement asynchronous action(s) (AJAX)
* @param string $sCode The code of the action (if several actions need to be distinguished)
* @param hash $aParameters The action's parameters name => value
* @param array $aParameters The action's parameters name => value
*/
public function AsyncAction(WebPage $oPage, $sCode, $aParameters)
{