feat: Перенос установщика в cms

This commit is contained in:
origami11@yandex.ru 2025-05-16 13:08:13 +03:00
parent 36c81135f3
commit 30ead2b42f
3 changed files with 64 additions and 161 deletions

View file

@ -1,121 +0,0 @@
<?php
namespace ctiso\Controller;
use ctiso\Settings,
ctiso\Path,
ctiso\Database\JsonInstall;
class Installer
{
protected $db_manager;
protected $installPath;
public $_registry;
public function __construct(Settings $_registry)
{
$this->_registry = $_registry;
}
public function setUp($db_manager, $installPath)
{
$this->db_manager = $db_manager;
$this->installPath = $installPath;
}
function getSetupFile($name)
{
$setup = Path::join(call_user_func($this->installPath, $name), "install.json");
return $setup;
}
function getUninstallFile($name) {
return Path::join(call_user_func($this->installPath, $name), "sql", "uninstall.json");
}
// Проверка версии обновления
function isChanged($name) // Информация о модулях
{
$item = $this->_registry->get($name);
if ($item) {
$setup = $this->getSetupFile($name);
if (file_exists($setup) && (filemtime($setup) > $item['time'])) {
return true;
}
return false;
}
return true;
}
function installSQL(array $sql, $version_new, $version_old, $name)
{
$result = [];
$json_installer = new JsonInstall($this->db_manager);
foreach ($sql as $version => $install) {
if (version_compare($version, $version_new, "<=") && version_compare($version, $version_old, ">")) {
$file = Path::join(call_user_func($this->installPath, $name), "sql", $install);
$json_installer->install($file, null);
$result[] = $version;
}
}
return $result;
}
function uninstall($name){
$uninstall = $this->getUninstallFile($name);
if (file_exists($uninstall)) {
$json_installer = new JsonInstall($this->db_manager);
$json_installer->install($uninstall,null);
}
$this->_registry->removeKey($name);
$this->_registry->write();
}
// Устанавливает обновления если есть
function doUpdates($name, $force = false) // Установка модуля
{
$result = [];
$setup = $this->getSetupFile($name);
if (file_exists($setup) && ($this->isChanged($name) || $force)) {
$registry = $this->_registry;
$settings = new Settings($setup);
$settings->read();
$item = $registry->get($name);
$version_new = $settings->get('version');
if ($item) {
$version_old = $item['version'];
} else {
$version_old = "0.0";
$registry->writeKey([$name], []);
}
if (version_compare($version_old, $settings->get('version'), "!=")) {
$sql = $settings->get('sql');
if (is_array($sql)) {
$res = $this->installSQL($sql, $version_new, $version_old, $name);
if ($res) {
$result[]=$res;
}
}
}
// Обновление версии меню
$registry->removeKey($name);
$registry->set($name, [
'version' => $version_new,
'time' => filemtime($setup)
]);
// $registry->writeKey([$name], $settings->export());
$registry->write();
}
return $result;
}
function install($dbinit_path, $dbfill_path = null) {
$json_installer = new JsonInstall($this->db_manager);
$json_installer->install($dbinit_path, $dbfill_path);
}
}

View file

@ -3,16 +3,21 @@
namespace ctiso\Database;
use ctiso\Database\Manager;
use App\DbMigrate\DataBaseInfo;
use App\DbMigrate\DiffPatch;
/**
* Усановить базу данных из json файла.
*/
class JsonInstall {
public $db_manager;
public Manager $db_manager;
public $serialColumns;
public function __construct(Manager $db_manager) {
$this->db_manager = $db_manager;
}
function install($dbinit_path, $dbfill_path = null) {
public function install(string $dbinit_path, ?string $dbfill_path = null) {
$dbinit_file = file_get_contents($dbinit_path);
if (is_string($dbinit_file)) {
$initActions = json_decode($dbinit_file, true);
@ -32,7 +37,7 @@ class JsonInstall {
$this->makeConstraints($initActions);
}
function missingTables($tables) {
protected function missingTables(array $tables) {
$actual_tables = $this->db_manager->getAllTableNames();
$missingTables = [];
foreach ($tables as $table) {
@ -42,16 +47,19 @@ class JsonInstall {
return $missingTables;
}
//Создать таблицы
function initDataBase($initActions/*: array*/, $dbinit_path) {
/**
* Создать таблицы
*/
function initDataBase(array $initActions, string $dbinit_path): void {
$pg = $this->db_manager->db->isPostgres();
if (!$pg) {
$refs = [];
//В sqlite нет alter reference. Референсы надо создавать при создании таблицы.
foreach ($initActions as $action) {
if ($action["type"] == "alterReference") {
if (!isset($refs[$action["table"]]))
if (!isset($refs[$action["table"]])) {
$refs[$action["table"]] = [];
}
$refs[$action["table"]][]=$action;//добавить к списку референсов для таблицы
}
}
@ -73,7 +81,7 @@ class JsonInstall {
}
}
if ($action["type"] != "alterReference") {
$this->db_manager->ExecuteAction($action, $dbinit_path);
$this->db_manager->executeAction($action, $dbinit_path);
}
}
@ -95,14 +103,15 @@ class JsonInstall {
}
}
//Заполнить данными
function fillDataBase($dbfill_file_path) {
/**
* Заполнить данными
*/
function fillDataBase(string $dbfill_file_path): void {
$dbfill_file = file_get_contents($dbfill_file_path);
if (is_string($dbfill_file)) {
$actions = json_decode($dbfill_file,true);
if ($actions) {
//Проверка что упоминаемые в списке действий таблицы уже есть в базе
// Проверка что упоминаемые в списке действий таблицы уже есть в базе
$affected_tables = [];
foreach ($actions as $action) {
if ($action["table_name"]) {
@ -128,15 +137,16 @@ class JsonInstall {
}
}
//Обновить ключи serial и создать ограничения
function makeConstraints($initActions) {
/**
* Обновить ключи serial и создать ограничения
*/
protected function makeConstraints(array $initActions) {
$pg = $this->db_manager->db->isPostgres();
if ($pg) {
foreach ($this->serialColumns as $serialColumn) {
$this->db_manager->updateSerial($serialColumn["table"], $serialColumn["column"]);
}
foreach ($initActions as $action) {
if ($action["type"] == "alterReference") {
$this->db_manager->executeAction($action);
@ -145,4 +155,18 @@ class JsonInstall {
}
}
/**
* Обновить базу данных
*/
function update(array $patches): void {
$db = $this->db_manager->db;
$dbi = new DataBaseInfo();
$diff = new DiffPatch($db);
$diff->readPatches($dbi, $patches);
// Применяем изменения
$db->beginTransaction();
$diff->patchDatabase($diff->getCurrentSchema(), $dbi);
$db->commit();
}
}

View file

@ -9,15 +9,13 @@ use Exception;
class Manager
{
public $db/*: Database*/;
public Database $db;
public function __construct(Database $db)
{
public function __construct(Database $db) {
$this->db = $db;
}
public function executeAction($action/*: array*/, $db_file = "")
{
public function executeAction(array $action, string $db_file = ""): void {
switch($action["type"]) {
case "dropTable":
$this->dropTableQuery($action["table_name"], true);
@ -59,9 +57,10 @@ class Manager
}
}
//Дропает и создаёт SQL VIEW
public function recreateView($viewName, $selectStatement)
{
/**
* Дропает и создаёт SQL VIEW
*/
public function recreateView($viewName, $selectStatement) {
$this->db->query("DROP VIEW ".$viewName);
$this->db->query("CREATE VIEW ".$viewName." AS ".$selectStatement);
}
@ -95,7 +94,7 @@ class Manager
foreach ($results as $result) {
$fields[$result["name"]] = [
"type"=> $result["type"],
"not_null"=> boolval($result["notnull"]),
"nullable"=> !boolval($result["notnull"]),
"constraint"=> ((bool) $result["pk"]) ? "PRIMARY KEY" : null
];
}
@ -103,7 +102,7 @@ class Manager
}
}
public function renameColumn($table, $old_name, $new_name)
public function renameColumn(string $table, string $old_name, string $new_name): void
{
$pg = $this->db->isPostgres();
if ($pg) {
@ -117,7 +116,7 @@ class Manager
return;
}
$data/*: array*/ = $this->dumpTable($table);
$data = $this->dumpTable($table);
$this->db->query("ALTER TABLE ".$table." RENAME TO ".$tmp_table.";");
$table_info[$new_name] = $table_info[$old_name];
@ -134,20 +133,22 @@ class Manager
}
}
//Обновление ключа serial после ручной вставки
public function updateSerial($table, $column)
/**
* Обновление ключа serial после ручной вставки
*/
public function updateSerial($table, $column): void
{
$this->db->query("SELECT setval(pg_get_serial_sequence('".$table."', '".$column."'), coalesce(max(".$column."),0) + 1, false) FROM ".$table);
}
public function columnDefinition($name, $data, $pg)
public function columnDefinition(string $name, $data, $pg): string
{
$constraint = isset($data['constraint']) ? " ".$data['constraint'] : "";
$references = "";
if (isset($data['references'])) {
$references = " REFERENCES " . $data['references']['refTable'] . '(' .$data['references']['refColumn'] . ')';
$references = " REFERENCES " . $data['references']['table'] . '(' .$data['references']['column'] . ')';
}
if (isset($data["not_null"]) && $data["not_null"]) {
if (isset($data["nullable"]) && $data["nullable"] === false) {
$constraint .=" NOT NULL";
}
$type = $data['type'];
@ -155,21 +156,20 @@ class Manager
if (strtolower($type)=="serial") {
$type = "integer";
}
//if (strtolower($type)=="boolean")
// $type = "integer";
}
return $name." ".$type.$references.$constraint;
}
public function addColumn($table_name, $column_name, $field)
public function addColumn(string $table_name, string $column_name, $field): void
{
$pg = $this->db->isPostgres();
$q = "ALTER TABLE ".$table_name." ADD COLUMN ".
$this->columnDefinition($column_name, $field, $pg);
$this->columnDefinition($column_name, $field, $pg);
$this->db->query($q);
}
public function getConstraintDef($c/*: array*/)
public function getConstraintDef(array $c)
{
if ($c['type'] == 'unique') {
return "UNIQUE(" . implode(", ", $c['fields']) . ")";
@ -178,7 +178,7 @@ class Manager
}
//CreateTableQuery('users',['id'=>['type'=>'integer','constraint'=>'PRIMARY KEY']])
public function createTableQuery($table, $fields, $constraints)
public function createTableQuery(string $table, array $fields, $constraints): void
{
$pg = $this->db->isPostgres();
if ($constraints) {
@ -197,7 +197,7 @@ class Manager
$this->db->query($statement);
}
public function dumpTable($table_name)
public function dumpTable(string $table_name): array
{
$pg = $this->db->isPostgres();
@ -209,7 +209,7 @@ class Manager
foreach ($table_fields as $name => $value) {
$type = strtolower($value['type']);
if ($type == "boolean") {
foreach ($data as &$row) {
foreach ($data as &$row) {
if (isset($row[$name])) {
$row[$name] = boolval($row[$name]);
}
@ -227,7 +227,7 @@ class Manager
return $result;
}
public function getAllTableNames()
public function getAllTableNames(): array
{
$result = [];
if ($this->db->isPostgres()) {
@ -242,7 +242,7 @@ class Manager
return $result;
}
public function dumpInserts()
public function dumpInserts(): array
{
$table_names = $this->getAllTableNames();
$result = [];