Name = 'ModuleManager'; $this->Version = '1.0'; $this->Creator = 'Chronos'; $this->License = 'GNU/GPLv3'; $this->Description = 'User interface for module management.'; $this->Dependencies = array(ModuleSetup::GetName()); $this->Revision = 1; $this->Type = ModuleType::System; $this->Models = array(ModelField::GetClassName(), ModuleDependency::GetClassName()); } function DoStart(): void { $this->Manager->OnInstallModel = array($this, 'InstallModel'); $this->Manager->OnUninstallModel = array($this, 'UninstallModel'); $this->Manager->OnInstallModule = array($this, 'InstallModule'); $this->Manager->OnUninstallModule = array($this, 'UninstallModule'); Core::Cast($this->System)->RegisterPage(['modules'], 'PageModules'); //$this->Manager->OnModuleChange = array($this, 'ModuleChange'); //$this->LoadFromDatabase(); $this->System->FormManager->RegisterClass('Module', array( 'Title' => 'Moduly', 'Table' => 'Module', 'Items' => array( 'Name' => array('Type' => 'String', 'Caption' => 'Systémové jméno', 'Default' => ''), 'Title' => array('Type' => 'String', 'Caption' => 'Název', 'Default' => ''), 'Description' => array('Type' => 'Text', 'Caption' => 'Popis', 'Default' => ''), 'Version' => array('Type' => 'String', 'Caption' => 'Verze', 'Default' => ''), 'License' => array('Type' => 'String', 'Caption' => 'Licence', 'Default' => ''), 'Creator' => array('Type' => 'String', 'Caption' => 'Tvůrce', 'Default' => ''), 'HomePage' => array('Type' => 'Hyperlink', 'Caption' => 'Domovské stránky', 'Default' => ''), 'Installed' => array('Type' => 'Boolean', 'Caption' => 'Instalováno', 'Default' => '', 'ReadOnly' => true), 'Models' => array('Type' => 'TModelListModule', 'Caption' => 'Modely', 'Default' => ''), 'Links' => array('Type' => 'TModuleLinkListModule', 'Caption' => 'Vazby', 'Default' => ''), ), 'Actions' => array( array('Caption' => 'Aktualizovat z disku', 'URL' => '/module/?A=SaveToDb'), ), )); $this->System->FormManager->RegisterFormType('TModule', array( 'Type' => 'Reference', 'Table' => 'Module', 'Id' => 'Id', 'Name' => 'Title', 'Filter' => '1', )); $this->System->FormManager->RegisterFormType('TModelListModule', array( 'Type' => 'ManyToOne', 'Table' => 'Model', 'Id' => 'Id', 'Ref' => 'Module', 'Filter' => '1', )); $this->System->FormManager->RegisterClass('Model', array( 'Title' => 'Modely', 'Table' => 'Model', 'Items' => array( 'Name' => array('Type' => 'String', 'Caption' => 'Systémové jméno', 'Default' => ''), 'Title' => array('Type' => 'String', 'Caption' => 'Název', 'Default' => ''), 'Module' => array('Type' => 'TModule', 'Caption' => 'Module', 'Default' => ''), 'Query' => array('Type' => 'String', 'Caption' => 'SQL dotaz', 'Default' => ''), 'DefaultSortColumn' => array('Type' => 'String', 'Caption' => 'Výchozí sloupce řazení', 'Default' => ''), 'DefaultSortOrder' => array('Type' => 'Text', 'Caption' => 'Výchozí směr řazení', 'Default' => ''), 'Fields' => array('Type' => 'TModelFieldListModel', 'Caption' => 'Pole', 'Default' => ''), ), )); $this->System->FormManager->RegisterFormType('TModel', array( 'Type' => 'Reference', 'Table' => 'Model', 'Id' => 'Id', 'Name' => 'Title', 'Filter' => '1', )); $this->System->FormManager->RegisterFormType('TModelFieldListModel', array( 'Type' => 'ManyToOne', 'Table' => 'ModelField', 'Id' => 'Id', 'Ref' => 'Model', 'Filter' => '1', )); $this->System->FormManager->RegisterClass('ModelField', array( 'Title' => 'Pole modelu', 'Table' => 'ModelField', 'Items' => array( 'Name' => array('Type' => 'String', 'Caption' => 'Systémové jméno', 'Default' => ''), 'Title' => array('Type' => 'String', 'Caption' => 'Název', 'Default' => ''), 'Model' => array('Type' => 'TModel', 'Caption' => 'Model', 'Default' => ''), 'Query' => array('Type' => 'String', 'Caption' => 'SQL dotaz', 'Default' => ''), 'Type' => array('Type' => 'String', 'Caption' => 'Typ', 'Default' => ''), 'DefaultValue' => array('Type' => 'String', 'Caption' => 'Výchozí hodnota', 'Default' => ''), 'IsNull' => array('Type' => 'Boolean', 'Caption' => 'Také nulová hodnota', 'Default' => ''), 'Suffix' => array('Type' => 'String', 'Caption' => 'Text za', 'Default' => ''), ), )); $this->System->FormManager->RegisterFormType('TModuleLink', array( 'Type' => 'Reference', 'Table' => 'ModuleLink', 'Id' => 'Id', 'Name' => 'Module', 'Filter' => '1', )); $this->System->FormManager->RegisterFormType('TModuleLinkListModule', array( 'Type' => 'ManyToOne', 'Table' => 'ModuleLink', 'Id' => 'Id', 'Ref' => 'Module', 'Filter' => '1', )); $this->System->FormManager->RegisterClass('ModuleLink', array( 'Title' => 'Vazby modulu', 'Table' => 'ModuleLink', 'Items' => array( 'Module' => array('Type' => 'TModule', 'Caption' => 'Modul', 'Default' => ''), 'LinkedModule' => array('Type' => 'TModule', 'Caption' => 'Vázaný modul', 'Default' => ''), 'Type' => array('Type' => 'String', 'Caption' => 'Typ vazby', 'Default' => ''), ), )); $this->System->FormManager->RegisterFormType('TModule', array( 'Type' => 'Reference', 'Table' => 'Module', 'Id' => 'Id', 'Name' => 'Name', 'Filter' => '1', )); } function DoStop(): void { Core::Cast($this->System)->UnregisterPage(['modules']); } function DoBeforeInstall(): void { $this->AddModelDatabase(Module::GetModelDesc()); $this->Manager->OnInstallModule = array($this, 'InstallModule'); $this->Manager->OnUninstallModule = array($this, 'UninstallModule'); $this->AddModelDatabase(Model::GetModelDesc()); $this->Manager->OnInstallModel = array($this, 'InstallModel'); $this->Manager->OnUninstallModel = array($this, 'UninstallModel'); } function DoAfterUninstall(): void { $this->Manager->OnInstallModel = null; $this->Manager->OnUninstallModel = null; $this->RemoveModelDatabase(Model::GetModelDesc()); $this->Manager->OnInstallModule = null; $this->Manager->OnUninstallModule = null; $this->RemoveModelDatabase(Module::GetModelDesc()); } function DoInstall(): void { $this->InstallModel(Module::GetModelDesc(), $this->System->GetModule($this::GetName())); $this->InstallModel(Model::GetModelDesc(), $this->System->GetModule($this::GetName())); } function AddModelDatabase(ModelDesc $ModelDesc) { $Query = "CREATE TABLE IF NOT EXISTS `".$ModelDesc->Name."` (\n"; $Query .= ' `'.$ModelDesc->PrimaryKey.'` int(11) NOT NULL AUTO_INCREMENT,'."\n"; foreach ($ModelDesc->Columns as $Column) { $Query .= " `".$Column->Name."` "; if ($Column->Type == ModelColumnType::Integer) $Query .= 'int(11)'; else if ($Column->Type == ModelColumnType::String) $Query .= 'varchar(255)'; else if ($Column->Type == ModelColumnType::Float) $Query .= 'varchar(255)'; else if ($Column->Type == ModelColumnType::Text) $Query .= 'text'; else if ($Column->Type == ModelColumnType::DateTime) $Query .= 'datetime'; else if ($Column->Type == ModelColumnType::Reference) $Query .= 'int(11)'; else if ($Column->Type == ModelColumnType::Boolean) $Query .= 'tinyint(1)'; else if ($Column->Type == ModelColumnType::Date) $Query .= 'date'; else if ($Column->Type == ModelColumnType::BigInt) $Query .= 'bigint(20)'; else if ($Column->Type == ModelColumnType::Enum) { $Query .= 'enum("'.implode('", "', $Column->States).'")'; } if ($Column->Nullable) $Query .= ''; else $Query .= ' NOT NULL'; $Query .= ' COLLATE utf8_general_ci'; if ($Column->HasDefault) { if ($Column->Default == null) $Query .= ' DEFAULT NULL'; else $Query .= ' DEFAULT '.$Column->GetDefault(); } $Query .= ",\n"; } $Query .= ' PRIMARY KEY (`'.$ModelDesc->PrimaryKey.'`)'; foreach ($ModelDesc->Columns as $Column) { if ($Column->Type == ModelColumnType::Reference) $Query .= ','."\n".' KEY `'.$Column->Name.'` (`'.$Column->Name.'`)'; else if ($Column->Unique) $Query .= ','."\n".' UNIQUE KEY `'.$Column->Name.'` (`'.$Column->Name.'`)'; } $Query .= "\n"; if ($ModelDesc->Memory) $Engine = 'MEMORY'; else $Engine = 'InnoDB'; $Query .= ') ENGINE='.$Engine.' DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;'; foreach ($ModelDesc->Columns as $Column) { if ($Column->Type == ModelColumnType::Reference) $Query .= "ALTER TABLE `".$ModelDesc->Name."` ". "ADD CONSTRAINT `".$ModelDesc->Name."_ibfk_".$Column->Name."` FOREIGN KEY (`".$Column->Name."`) REFERENCES `".$Column->RefTable."` (`Id`);"; } $this->Database->query($Query); } function RemoveModelDatabase(ModelDesc $ModelDesc) { /*$Query = ''; foreach ($ModelDesc->Columns as $Column) { if ($Column->Type == ModelColumnType::Reference) $Query .= "ALTER TABLE `".$ModelDesc->Name."` ". "DROP FOREIGN KEY `".$ModelDesc->Name."_ibfk_".$Column->Name."`;"; } if (($Query != '') and $this->Database->TableExists($ModelDesc->Name)) { $this->Database->query($Query); } */ $this->Database->query('SET foreign_key_checks = 0; DROP TABLE IF EXISTS `'.$ModelDesc->Name.'`'); } function InstallModel(ModelDesc $ModelDesc, Module $Module) { $this->AddModelDatabase($ModelDesc); $this->Database->insert('Model', array('Name' => $ModelDesc->Name, 'Module' => $Module->Id)); $ModelId = $this->Database->insert_id; foreach ($ModelDesc->Columns as $Field) { $this->Database->insert('ModelField', array('Name' => $Field->Name, 'Model' => $ModelId, 'Type' => ModelColumnType::GetName($Field->Type), 'Nullable' => (int)$Field->Nullable)); } if ($ModelDesc->DefaultValues != null) { $Values = call_user_func('self::'.$ModelDesc->DefaultValues); foreach ($Values as $Value) { $this->Database->insert($ModelDesc->Name, $Value); } } } function UninstallModel(ModelDesc $ModelDesc, Module $Module) { $DbResult = $this->Database->select('Model', 'Id', '(Name="'.$ModelDesc->Name.'") AND (Module='.$Module->Id.')'); if ($DbResult->num_rows > 0) { $DbRow = $DbResult->fetch_assoc(); $ModelId = $DbRow['Id']; $DbResult = $this->Database->delete('ModelField', '(Model='.$ModelId.')'); $this->Database->delete('Model', '(Id='.$ModelId.')'); } else echo('Can\'t remove model '.$ModelDesc->Name.'
'); $this->RemoveModelDatabase($ModelDesc); } function InstallModule(Module $Module) { $this->Database->insert('Module', array( 'Id' => $Module->Id, 'Name' => $Module->Name, 'Title' => $Module->Title, 'Creator' => $Module->Creator, 'Version' => $Module->Version, 'License' => $Module->License, 'Installed' => (int)$Module->Installed, 'Description' => $Module->Description, 'InstalledVersion' => $Module->InstalledVersion )); } function UninstallModule(Module $Module) { $this->Database->delete('Module', 'Name="'.$Module->Name.'"'); } function ModuleChange(Module $Module): void { if ($Module->Installed) $Installed = 1; else $Installed = 0; $this->Database->query('UPDATE `Module` SET `Installed`='.$Installed.' WHERE `Name`="'.$Module->Name.'"'); } function LoadFromDatabase(): void { //DebugLog('Loading modules...'); $this->Modules = array(); $Query = 'SELECT `Id`, `Name`,`Installed` FROM `Module`'; $DbResult = $this->Database->query($Query); while ($Module = $DbResult->fetch_array()) { include_once('Modules/'.$Module['Name'].'/'.$Module['Name'].'.php'); $ModuleClassName = 'Module'.$Module['Name']; $NewModule = new $ModuleClassName($this->Database, $this->Manager); $NewModule->Id = $Module['Id']; $NewModule->Installed = $Module['Installed']; $this->Manager->RegisterModule($NewModule); } } function SaveToDatabase(): string { $Output = ''; $Modules = array(); $DbResult = $this->Database->query('SELECT * FROM `Module`'); while ($DbRow = $DbResult->fetch_assoc()) { $Modules[$DbRow['Name']] = $DbRow; if ($this->System->ModuleManager->ModulePresent($DbRow['Name'])) $this->System->ModuleManager->GetModule($DbRow['Name'])->Id = $DbRow['Id']; } // Add missing foreach ($this->System->ModuleManager->Modules as $Module) { if (!array_key_exists($Module->Name, $Modules)) { $this->Database->insert('Module', array('Name' => $Module->Name, 'Version' => $Module->Version, 'Creator' => $Module->Creator, 'HomePage' => $Module->HomePage, 'Title' => $Module->Title, 'Description' => $Module->Description, 'License' => $Module->License, 'Installed' => $Module->Installed)); $this->System->ModuleManager->GetModule($Module->Name)->Id = $this->Database->insert_id; } else $this->Database->update('Module', 'Name = "'.$Module->Name.'"', array( 'Version' => $Module->Version, 'Creator' => $Module->Creator, 'HomePage' => $Module->HomePage, 'Title' => $Module->Title, 'Description' => $Module->Description, 'License' => $Module->License, 'Installed' => $Module->Installed)); } // Remove exceeding foreach ($Modules as $Module) if (!$this->System->ModuleManager->ModulePresent($Module['Name'])) { $Output .= 'Removing module '.$Module['Name'].' from list
'; $this->Database->query('DELETE FROM `ModuleLink` WHERE `Module` = '.$Module['Id']); $this->Database->query('DELETE FROM `ModuleLink` WHERE `LinkedModule` = '.$Module['Id']); $DbResult = $this->Database->query('SELECT Id FROM `PermissionOperation` WHERE `Module` = '.$Module['Id']); while ($DbRow = $DbResult->fetch_assoc()) { $this->Database->query('DELETE FROM `PermissionGroupAssignment` WHERE `AssignedOperation` = '.$DbRow['Id']); $this->Database->query('DELETE FROM `PermissionUserAssignment` WHERE `AssignedOperation` = '.$DbRow['Id']); } $this->Database->query('DELETE FROM `PermissionOperation` WHERE `Module` = '.$Module['Id']); $this->Database->query('DELETE FROM `Model` WHERE `Module` = '.$Module['Id']); $DbResult = $this->Database->query('SELECT Id FROM `Model` WHERE `Module` = '.$Module['Id']); while ($DbRow = $DbResult->fetch_assoc()) $this->Database->query('DELETE FROM `ModelField` WHERE `Model` = '.$DbRow['Id']); $this->Database->query('DELETE FROM `Module` WHERE `Id` = '.$Module['Id']); } // Reload dependencies $DbDependency = array(); $DbResult = $this->Database->query('SELECT * FROM `ModuleLink`'); while ($DbRow = $DbResult->fetch_assoc()) $DbDependency[$DbRow['Module']][] = $DbRow['LinkedModule']; foreach ($this->System->ModuleManager->Modules as $Module) { // Add missing foreach ($Module->Dependencies as $Dependency) { if (!array_key_exists($Module->Id, $DbDependency) or !in_array($this->System->ModuleManager->GetModule($Dependency)->Id, $DbDependency[$Module->Id])) { if ($this->System->ModuleManager->ModulePresent($Dependency)) $DependencyId = $this->System->ModuleManager->GetModule($Dependency)->Id; else throw new Exception('Dependent module '.$Dependency.' not found'); $this->Database->insert('ModuleLink', array('Module' => $Module->Id, 'LinkedModule' => $DependencyId, 'Type' => 'DependOn')); } } // Remove exceeding if (array_key_exists($Module->Id, $DbDependency)) foreach ($DbDependency[$Module->Id] as $Dep) { $DepModName = $this->System->ModuleManager->SearchModuleById($Dep); if (!in_array($DepModName, $Module->Dependencies)) $this->Database->query('DELETE FROM `ModuleLink` WHERE `Module` = '. $Module->Id.' AND LinkedModule='.$Dep); } } return $Output; } } class PageModules extends Page { public array $YesNo; function __construct(System $System) { parent::__construct($System); $this->Title = T('Modules'); $this->ParentClass = 'PageSetup'; $this->YesNo = array(false => T('No'), true => T('Yes')); } function Show(): string { $Output = ''; if (array_key_exists('op', $_GET)) $Operation = $_GET['op']; else $Operation = ''; if ($Operation == 'install') { $this->System->ModuleManager->GetModule($_GET['name'])->Install(); $this->System->ModuleManager->SaveState(); $Output .= 'Modul '.$_GET['name'].' instalován.
'; } else if ($Operation == 'uninstall') { $this->System->ModuleManager->GetModule($_GET['name'])->Uninstall(); $this->System->ModuleManager->SaveState(); $Output .= 'Modul '.$_GET['name'].' odinstalován.
'; } else if ($Operation == 'enable') { $this->System->ModuleManager->GetModule($_GET['name'])->Enable(); $this->System->ModuleManager->SaveState(); $Output .= 'Modul '.$_GET['name'].' povolen.
'; } else if ($Operation == 'disable') { $this->System->ModuleManager->GetModule($_GET['name'])->Disable(); $this->System->ModuleManager->SaveState(); $Output .= 'Modul '.$_GET['name'].' zakázán.
'; } else if ($Operation == 'upgrade') { $this->System->ModuleManager->GetModule($_GET['name'])->Upgrade(); $this->System->ModuleManager->SaveState(); $Output .= 'Modul '.$_GET['name'].' povýšen.
'; } else if ($Operation == 'install-all') { $this->System->ModuleManager->InstallAll(); $this->System->ModuleManager->SaveState(); $Output .= 'Všechny moduly instalovány.
'; } else if ($Operation == 'uninstall-all') { $this->System->ModuleManager->UninstallAll(array(ModuleCondition::Application)); $this->System->ModuleManager->UninstallAll(array(ModuleCondition::Library)); $this->System->ModuleManager->SaveState(); $Output .= 'Všechny moduly odinstalovány.
'; } else if ($Operation == 'enable-all') { $this->System->ModuleManager->EnableAll(); $this->System->ModuleManager->SaveState(); $Output .= 'Všechny moduly povoleny.
'; } else if ($Operation == 'disable-all') { $this->System->ModuleManager->DisableAll(); $this->System->ModuleManager->SaveState(); $Output .= 'Všechny moduly zakázány.
'; } else if ($Operation == 'upgrade-all') { $this->System->ModuleManager->UpgradeAll(); $this->System->ModuleManager->SaveState(); $Output .= 'Všechny moduly povýšeny.
'; } $Output .= '

Správa modulů

'; $Output .= $this->ShowList(); return $Output; } function ShowList(): string { $Output = ''; $Pageing = new Paging(); $Pageing->TotalCount = count($this->System->ModuleManager->Modules); $Table = new VisualTable(); $Table->SetColumns(array( array('Name' => 'Name', 'Title' => T('Name')), array('Name' => 'Creator', 'Title' => T('Creator')), array('Name' => 'Version', 'Title' => T('Version')), array('Name' => 'InstalledVersion', 'Title' => T('Installed version')), array('Name' => 'Type', 'Title' => T('Type')), array('Name' => 'License', 'Title' => T('License')), array('Name' => 'Installed', 'Title' => T('Installed')), array('Name' => 'Enabled', 'Title' => T('Enabled')), array('Name' => 'Description', 'Title' => T('Description')), array('Name' => 'Dependencies', 'Title' => T('Dependencies')), array('Name' => '', 'Title' => 'Akce'), )); $ModuleType = array(T('System'), T('Library'), T('Application')); foreach ($this->System->ModuleManager->Modules as $Module) { if (($Module->Dependencies) > 0) $Dependencies = implode(',', $Module->Dependencies); else $Dependencies = ' '; $Actions = ''; if ($Module->Type != ModuleType::System) { if ($Module->Installed == true) { $Actions .= ' Odinstalovat'; if ($Module->Enabled == true) $Actions .= ' Zakázat'; else $Actions .= ' Povolit'; if ($Module->InstalledVersion != $Module->Version) $Actions .= ' Povýšit'; } else $Actions .= ' Instalovat'; } $Table->Table->Cells[] = array($Module->Name, $Module->Creator, $Module->Version, $Module->InstalledVersion, $ModuleType[$Module->Type], $Module->License, $this->YesNo[$Module->Installed], $this->YesNo[$Module->Enabled], $Module->Description, $Dependencies, $Actions); } $Output .= $Pageing->Show(); $Output .= $Table->Show(); $Output .= $Pageing->Show(); $Output .= '
'. 'Instalovat vše '. 'Odinstalovat vše '. 'Zakázat vše '. 'Povolit vše '. 'Povýšit vše '. '
'; return $Output; } } class ModelField extends Model { static function GetModelDesc(): ModelDesc { $Desc = new ModelDesc(self::GetClassName()); $Desc->AddString('Name'); $Desc->AddReference('Model', Model::GetClassName()); $Desc->AddString('Type'); $Desc->AddBoolean('Nullable'); return $Desc; } } class ModuleDependency extends Model { static function GetModelDesc(): ModelDesc { $Desc = new ModelDesc(self::GetClassName()); $Desc->AddReference('Module', Module::GetClassName()); $Desc->AddReference('Dependency', Module::GetClassName()); return $Desc; } }