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));
}
}
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 .= '