@@ -60,6 +60,7 @@ class iTopExtension
6060 * @var bool
6161 */
6262 public $ bMarkedAsChosen ;
63+ public ?bool $ bUninstallable = null ;
6364
6465 /**
6566 * @var bool
@@ -95,6 +96,10 @@ class iTopExtension
9596 * @var true
9697 */
9798 public bool $ bInstalled = false ;
99+ /**
100+ * @var true
101+ */
102+ public bool $ bRemovedFromDisk = false ;
98103
99104 public function __construct ()
100105 {
@@ -119,8 +124,11 @@ public function __construct()
119124 * @since 3.3.0
120125 * @return bool
121126 */
122- public function CanBeUninstalled ()
127+ public function CanBeUninstalled (): bool
123128 {
129+ if (!is_null ($ this ->bUninstallable )) {
130+ return $ this ->bUninstallable ;
131+ }
124132 foreach ($ this ->aModuleInfo as $ sModuleCode => $ aModuleInfo ) {
125133 $ bUninstallable = $ aModuleInfo ['uninstallable ' ] === 'yes ' ;
126134 if (!$ bUninstallable ) {
@@ -143,6 +151,7 @@ class iTopExtensionsMap
143151 * @return void
144152 */
145153 protected $ aExtensions ;
154+ protected ?array $ aInstalledExtensions = null ;
146155
147156 /**
148157 * The list of directories browsed using the ReadDir method when building the map
@@ -263,7 +272,7 @@ protected function AddExtension(iTopExtension $oNewExtension)
263272 *
264273 * @return \iTopExtension|null
265274 */
266- public function Get (string $ sExtensionCode ): ?iTopExtension
275+ public function GetFromExtensionCode (string $ sExtensionCode ): ?iTopExtension
267276 {
268277 foreach ($ this ->aExtensions as $ oExtension ) {
269278 if ($ oExtension ->sCode === $ sExtensionCode ) {
@@ -434,6 +443,11 @@ public function GetAllExtensions()
434443 return $ this ->aExtensions ;
435444 }
436445
446+ public function GetAllExtensionsWithPreviouslyInstalled ()
447+ {
448+ return array_merge ($ this ->aExtensions , $ this ->aInstalledExtensions ?? []);
449+ }
450+
437451 /**
438452 * Mark the given extension as chosen
439453 * @param string $sExtensionCode The code of the extension (code without version number)
@@ -503,24 +517,52 @@ public function GetChoices()
503517 */
504518 public function LoadChoicesFromDatabase (Config $ oConfig )
505519 {
506-
507- $ aInstalledExtensions = $ this ->GetInstalledExtensionsFromDatabase ($ oConfig );
508-
509- foreach ($ aInstalledExtensions as $ aDBInfo ) {
510- $ this ->MarkAsChosen ($ aDBInfo ['code ' ]);
511- $ this ->SetInstalledVersion ($ aDBInfo ['code ' ], $ aDBInfo ['version ' ]);
520+ foreach ($ this ->LoadInstalledExtensionsFromDatabase ($ oConfig ) as $ oExtension ) {
521+ $ this ->MarkAsChosen ($ oExtension ->sCode );
522+ $ this ->SetInstalledVersion ($ oExtension ->sCode , $ oExtension ->sVersion );
512523 }
513524 return true ;
514525 }
515526
516- public function GetInstalledExtensionsFromDatabase (Config $ oConfig ): array |false
527+ public function LoadInstalledExtensionsFromDatabase (Config $ oConfig ): array |false
517528 {
529+ if (is_array ($ this ->aInstalledExtensions )) {
530+ return $ this ->aInstalledExtensions ;
531+ }
518532 try {
519533 if (CMDBSource::DBName () === null ) {
520534 CMDBSource::InitFromConfig ($ oConfig );
521535 }
522536 $ sLatestInstallationDate = CMDBSource::QueryToScalar ("SELECT max(installed) FROM " .$ oConfig ->Get ('db_subname ' )."priv_extension_install " );
523- return CMDBSource::QueryToArray ("SELECT * FROM " .$ oConfig ->Get ('db_subname ' )."priv_extension_install WHERE installed = ' " .$ sLatestInstallationDate ."' " );
537+ $ aDBInfo = CMDBSource::QueryToArray ("SELECT * FROM " .$ oConfig ->Get ('db_subname ' )."priv_extension_install WHERE installed = ' " .$ sLatestInstallationDate ."' " );
538+
539+ $ this ->aInstalledExtensions = [];
540+ foreach ($ aDBInfo as $ aExtensionInfo ) {
541+ $ oExtension = new iTopExtension ();
542+ $ oExtension ->sCode = $ aExtensionInfo ['code ' ];
543+ $ oExtension ->sLabel = $ aExtensionInfo ['label ' ];
544+ $ oExtension ->sDescription = $ aExtensionInfo ['description ' ] ?? '' ;
545+ $ oExtension ->sVersion = $ aExtensionInfo ['version ' ];
546+ $ oExtension ->sSource = $ aExtensionInfo ['source ' ];
547+ $ oExtension ->bMandatory = false ;
548+ $ oExtension ->sMoreInfoUrl = '' ;
549+ $ oExtension ->aModules = [];
550+ $ oExtension ->aModuleVersion = [];
551+ $ oExtension ->aModuleInfo = [];
552+ $ oExtension ->sSourceDir = '' ;
553+ $ oExtension ->bVisible = true ;
554+ $ oExtension ->bInstalled = true ;
555+ $ oExtension ->bUninstallable = !isset ($ aExtensionInfo ['uninstallable ' ]) || $ aExtensionInfo ['uninstallable ' ] === 'yes ' ;
556+ if ($ oChoice = $ this ->GetFromExtensionCode ($ oExtension ->sCode )) {
557+ $ oChoice ->bInstalled = true ;
558+ } else {
559+ $ oExtension ->bRemovedFromDisk = true ;
560+ }
561+
562+ $ this ->aInstalledExtensions [$ oExtension ->sCode .'/ ' .$ oExtension ->sVersion ] = $ oExtension ;
563+ }
564+
565+ return $ this ->aInstalledExtensions ;
524566 } catch (MySQLException $ e ) {
525567 // No database or erroneous information
526568 return false ;
0 commit comments