feat: Перенос установщика в cms
This commit is contained in:
parent
36c81135f3
commit
30ead2b42f
3 changed files with 64 additions and 161 deletions
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,16 +3,21 @@
|
|||
|
||||
namespace ctiso\Database;
|
||||
use ctiso\Database\Manager;
|
||||
use App\DbMigrate\DataBaseInfo;
|
||||
use App\DbMigrate\DiffPatch;
|
||||
|
||||
/**
|
||||
* Уcтсановить базу данных из 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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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 = [];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue