diff --git a/setup/modulediscovery/ModuleDiscoveryService.php b/setup/modulediscovery/ModuleDiscoveryService.php index a279e5bdb..7af6130f9 100644 --- a/setup/modulediscovery/ModuleDiscoveryService.php +++ b/setup/modulediscovery/ModuleDiscoveryService.php @@ -1,5 +1,8 @@ '), '', $sModuleFileContents); + $sModuleFileContents = str_replace([''], '', $sModuleFileContents); $sModuleFileContents = str_replace('__FILE__', "'".addslashes($sModuleFilePath)."'", $sModuleFileContents); preg_match_all('/class ([A-Za-z0-9_]+) extends ([A-Za-z0-9_]+)/', $sModuleFileContents, $aMatches); //print_r($aMatches); @@ -50,7 +53,7 @@ class ModuleDiscoveryService { $idx++; } // Replace the main function call by an assignment to a variable, as an array... - $sModuleFileContents = str_replace(array('SetupWebPage::AddModule', 'ModuleDiscovery::AddModule'), '$aModuleInfo = array', $sModuleFileContents); + $sModuleFileContents = str_replace(['SetupWebPage::AddModule', 'ModuleDiscovery::AddModule'], '$aModuleInfo = array', $sModuleFileContents); eval($sModuleFileContents); // Assigns $aModuleInfo if (count($aModuleInfo) === 0) @@ -76,6 +79,96 @@ class ModuleDiscoveryService { return $aModuleInfo; } + /** + * Read the information from a module file (module.xxx.php) + * Closely inspired (almost copied/pasted !!) from ModuleDiscovery::ListModuleFiles + * @param string $sModuleFile + * @return array + * @throws ModuleDiscoveryServiceException + */ + public function ReadModuleFileConfiguration(string $sModuleFilePath) : array + { + $aModuleInfo = []; // will be filled by the "eval" line below... + try + { + $oParser = (new ParserFactory())->createForNewestSupportedVersion(); + $aNodes = $oParser->parse(file_get_contents($sModuleFilePath)); + } + catch (\Error $e) { + $sMessage = Dict::Format('config-parse-error', $e->getMessage(), $e->getLine()); + $this->oException = new \ModuleDiscoveryServiceException($sMessage, 0, $e); + } + + try { + foreach ($aNodes as $sKey => $oNode) { + if (false === ($oNode instanceof \PhpParser\Node\Stmt\Expression)) { + continue; + } + + /** @var Assign $oAssignation */ + $oAssignation = $oNode->expr; + + if (false === ($oAssignation instanceof PhpParser\Node\Expr\StaticCall)) { + continue; + } + + /** @var PhpParser\Node\Expr\StaticCall $oAssignation */ + + if ("SetupWebPage" !== $oAssignation?->class?->name) { + continue; + } + + if ("AddModule" !== $oAssignation?->name?->name) { + continue; + } + + $aArgs = $oAssignation?->args; + if (count($aArgs) != 3) { + throw new ModuleDiscoveryServiceException("Not enough parameters when calling SetupWebPage::AddModule"); + } + + $oModuleId = $aArgs[1]; + if (false === ($oModuleId instanceof PhpParser\Node\Arg)) { + throw new ModuleDiscoveryServiceException("2nd parameter to SetupWebPage::AddModule call issue: " . get_class($oModuleId)); + } + + /** @var PhpParser\Node\Arg $oModuleId */ + if (false === ($oModuleId->value instanceof PhpParser\Node\Scalar\String_)) { + throw new ModuleDiscoveryServiceException("2nd parameter to SetupWebPage::AddModule not a string: " . get_class($oModuleId->value)); + } + + /** @var PhpParser\Node\Scalar\String_ $sModuleIdStringObj */ + $sModuleIdStringObj = $oModuleId->value; + $sModuleId = $sModuleIdStringObj->value; + + $oModuleConfigInfo = $aArgs[2]; + if (false === ($oModuleConfigInfo instanceof PhpParser\Node\Arg)) { + throw new ModuleDiscoveryServiceException("3rd parameter to SetupWebPage::AddModule call issue: " . get_class($oModuleConfigInfo)); + } + + /** @var PhpParser\Node\Arg $oModuleConfigInfo */ + if (false === ($oModuleConfigInfo->value instanceof PhpParser\Node\Expr\Array_)) { + throw new ModuleDiscoveryServiceException("3rd parameter to SetupWebPage::AddModule not an array: " . get_class($oModuleConfigInfo->value)); + } + + $aModuleConfig=[]; + $this->BrowseArrayStructure($oModuleConfigInfo->value, $aModuleConfig); + + return [ + $sModuleFilePath, + $sModuleId, + $aModuleConfig + ]; + } + } catch(ModuleDiscoveryServiceException $e) { + // Continue... + throw $e; + } catch(Exception $e) { + // Continue... + throw new ModuleDiscoveryServiceException("Eval of $sModuleFilePath caused an exception: ".$e->getMessage(), 0, $e); + } + } + /** * @param string $sBooleanExpr * @@ -93,6 +186,37 @@ class ModuleDiscoveryService { return $bResult; } + + private function BrowseArrayStructure(PhpParser\Node\Expr\Array_ $oArray, array &$aModuleConfig) : void + { + $iIndex=0; + /** @var \PhpParser\Node\Expr\ArrayItem $oValue */ + foreach ($oArray->items as $oArrayItem){ + if ($oArrayItem->key instanceof PhpParser\Node\Scalar\String_) { + //dictionnary + $sKey = $oArrayItem->key->value; + } else { + $sKey = $iIndex++; + } + + $oValue = $oArrayItem->value; + + if ($oValue instanceof PhpParser\Node\Expr\Array_) { + $aSubConfig=[]; + $this->BrowseArrayStructure($oValue, $aSubConfig); + $aModuleConfig[$sKey]=$aSubConfig; + } + + if ($oValue instanceof PhpParser\Node\Scalar\String_) { + $aModuleConfig[$sKey]=$oValue->value; + continue; + } + + if ($oValue instanceof \PhpParser\Node\Expr\ConstFetch) { + $aModuleConfig[$sKey]= filter_var($oValue->name->name, FILTER_VALIDATE_BOOLEAN); + } + } + } } class ModuleDiscoveryServiceException extends Exception diff --git a/tests/php-unit-tests/unitary-tests/setup/modulediscovery/ModuleDiscoveryServiceTest.php b/tests/php-unit-tests/unitary-tests/setup/modulediscovery/ModuleDiscoveryServiceTest.php index 415a4aa19..ee6ecbecf 100644 --- a/tests/php-unit-tests/unitary-tests/setup/modulediscovery/ModuleDiscoveryServiceTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/modulediscovery/ModuleDiscoveryServiceTest.php @@ -13,13 +13,11 @@ class ModuleDiscoveryServiceTest extends ItopDataTestCase $this->RequireOnceItopFile('setup/modulediscovery/ModuleDiscoveryService.php'); } - public function test() + public function testReadModuleFileConfigurationLegacy() { $sModuleFilePath = __DIR__.'/resources/module.itop-full-itil.php'; $aRes = ModuleDiscoveryService::GetInstance()->ReadModuleFileConfiguration($sModuleFilePath); - var_dump($aRes); - $this->assertCount(3, $aRes); $this->assertEquals($sModuleFilePath, $aRes[0]); $this->assertEquals('itop-full-itil/3.3.0', $aRes[1]); @@ -28,6 +26,15 @@ class ModuleDiscoveryServiceTest extends ItopDataTestCase $this->assertEquals('Bridge - Request management ITIL + Incident management ITIL', $aRes[2]['label'] ?? null); } + public function testReadModuleFileConfiguration() + { + $sModuleFilePath = __DIR__.'/resources/module.itop-full-itil.php'; + $aRes = ModuleDiscoveryService::GetInstance()->ReadModuleFileConfiguration($sModuleFilePath); + $aExpected = ModuleDiscoveryService::GetInstance()->ReadModuleFileConfigurationLegacy($sModuleFilePath); + + $this->assertEquals($aExpected, $aRes); + } + public static function ComputeBooleanExpressionProvider() { return [