adjusted database and install scripts

This commit is contained in:
Roman 2024-05-04 15:07:24 +02:00
parent cd360560fc
commit 4b6554b870
8 changed files with 88 additions and 130 deletions

@ -7,12 +7,12 @@ use Core\Driver\SQL\SQL;
use Core\Objects\DatabaseEntity\Controller\DatabaseEntity; use Core\Objects\DatabaseEntity\Controller\DatabaseEntity;
use PHPUnit\Util\Exception; use PHPUnit\Util\Exception;
class CreateDatabase extends DatabaseScript { class CreateDatabase {
public static function createQueries(SQL $sql): array { public static function createQueries(SQL $sql): array {
$queries = array(); $queries = array();
self::loadEntities($queries, $sql); self::loadEntities($sql, $queries);
$queries[] = $sql->createTable("Settings") $queries[] = $sql->createTable("Settings")
->addString("name", 32) ->addString("name", 32)
@ -33,34 +33,25 @@ class CreateDatabase extends DatabaseScript {
->primaryKey("method") ->primaryKey("method")
->addBool("is_core", false); ->addBool("is_core", false);
self::loadDefaultACL($queries, $sql); self::loadDefaultACL($sql, $queries);
self::loadPatches($queries, $sql); self::loadPatches($sql, $queries);
return $queries; return $queries;
} }
private static function loadPatches(&$queries, $sql) { private static function loadPatches(SQL $sql, array &$queries): void {
$baseDirs = ["Core", "Site"]; $patchFiles = array_merge(
foreach ($baseDirs as $baseDir) { glob('Core/Configuration/Patch/*.php'),
$patchDirectory = "./$baseDir/Configuration/Patch/"; glob('Site/Configuration/Patch/*.php')
if (file_exists($patchDirectory) && is_dir($patchDirectory)) { );
$scan_arr = scandir($patchDirectory);
$files_arr = array_diff($scan_arr, array('.', '..')); sort($patchFiles);
foreach ($files_arr as $file) { foreach ($patchFiles as $file) {
$suffix = ".class.php"; @include_once $file;
if (endsWith($file, $suffix)) {
$className = substr($file, 0, strlen($file) - strlen($suffix));
$className = "\\$baseDir\\Configuration\\Patch\\$className";
$method = "$className::createQueries";
$patchQueries = call_user_func($method, $sql);
foreach ($patchQueries as $query) $queries[] = $query;
}
}
}
} }
} }
private static function loadEntities(&$queries, $sql) { private static function loadEntities(SQL $sql, array &$queries): void {
$persistables = []; $persistables = [];
$baseDirs = ["Core", "Site"]; $baseDirs = ["Core", "Site"];
foreach ($baseDirs as $baseDir) { foreach ($baseDirs as $baseDir) {
@ -113,7 +104,7 @@ class CreateDatabase extends DatabaseScript {
} }
} }
public static function loadDefaultACL(array &$queries, SQL $sql): void { public static function loadDefaultACL(SQL $sql, array &$queries): void {
$query = $sql->insert("ApiPermission", ["method", "groups", "description", "is_core"]); $query = $sql->insert("ApiPermission", ["method", "groups", "description", "is_core"]);
foreach (Request::getApiEndpoints() as $reflectionClass) { foreach (Request::getApiEndpoints() as $reflectionClass) {

@ -1,9 +0,0 @@
<?php
namespace Core\Configuration;
use Core\Driver\SQL\SQL;
abstract class DatabaseScript {
public static abstract function createQueries(SQL $sql);
}

@ -0,0 +1,47 @@
<?php
use Core\Driver\SQL\Column\IntColumn;
use Core\Driver\SQL\Type\CurrentColumn;
use Core\Driver\SQL\Type\CurrentTable;
use Core\Driver\SQL\Type\Trigger;
$queries[] = $sql->createTable("EntityLog")
->addInt("entityId")
->addString("tableName")
->addDateTime("modified", false, $sql->now())
->addInt("lifetime", false, 90);
$insertProcedure = $sql->createProcedure("InsertEntityLog")
->param(new CurrentTable())
->param(new IntColumn("id"))
->param(new IntColumn("lifetime", false, 90))
->returns(new Trigger())
->exec(array(
$sql->insert("EntityLog", ["entityId", "tableName", "lifetime"])
->addRow(new CurrentColumn("id"), new CurrentTable(), new CurrentColumn("lifetime"))
));
$updateProcedure = $sql->createProcedure("UpdateEntityLog")
->param(new CurrentTable())
->param(new IntColumn("id"))
->returns(new Trigger())
->exec(array(
$sql->update("EntityLog")
->set("modified", $sql->now())
->whereEq("entityId", new CurrentColumn("id"))
->whereEq("tableName", new CurrentTable())
));
$deleteProcedure = $sql->createProcedure("DeleteEntityLog")
->param(new CurrentTable())
->param(new IntColumn("id"))
->returns(new Trigger())
->exec(array(
$sql->delete("EntityLog")
->whereEq("entityId", new CurrentColumn("id"))
->whereEq("tableName", new CurrentTable())
));
$queries[] = $insertProcedure;
$queries[] = $updateProcedure;
$queries[] = $deleteProcedure;

@ -1,63 +0,0 @@
<?php
namespace Core\Configuration\Patch;
use Core\Configuration\DatabaseScript;
use Core\Driver\SQL\Column\IntColumn;
use Core\Driver\SQL\Condition\Compare;
use Core\Driver\SQL\SQL;
use Core\Driver\SQL\Type\CurrentColumn;
use Core\Driver\SQL\Type\CurrentTable;
use Core\Driver\SQL\Type\Trigger;
class EntityLog_2021_04_08 extends DatabaseScript {
public static function createQueries(SQL $sql): array {
$queries = array();
$queries[] = $sql->createTable("EntityLog")
->addInt("entityId")
->addString("tableName")
->addDateTime("modified", false, $sql->now())
->addInt("lifetime", false, 90);
$insertProcedure = $sql->createProcedure("InsertEntityLog")
->param(new CurrentTable())
->param(new IntColumn("id"))
->param(new IntColumn("lifetime", false, 90))
->returns(new Trigger())
->exec(array(
$sql->insert("EntityLog", ["entityId", "tableName", "lifetime"])
->addRow(new CurrentColumn("id"), new CurrentTable(), new CurrentColumn("lifetime"))
));
$updateProcedure = $sql->createProcedure("UpdateEntityLog")
->param(new CurrentTable())
->param(new IntColumn("id"))
->returns(new Trigger())
->exec(array(
$sql->update("EntityLog")
->set("modified", $sql->now())
->whereEq("entityId", new CurrentColumn("id"))
->whereEq("tableName", new CurrentTable())
));
$deleteProcedure = $sql->createProcedure("DeleteEntityLog")
->param(new CurrentTable())
->param(new IntColumn("id"))
->returns(new Trigger())
->exec(array(
$sql->delete("EntityLog")
->whereEq("entityId", new CurrentColumn("id"))
->whereEq("tableName", new CurrentTable())
));
$queries[] = $insertProcedure;
$queries[] = $updateProcedure;
$queries[] = $deleteProcedure;
return $queries;
}
}

@ -161,6 +161,7 @@ namespace Documents\Install {
return self::CHECKING_REQUIREMENTS; return self::CHECKING_REQUIREMENTS;
} }
// TODO: also check the presence of react dist?
$externalDir = $this->getExternalDirectory(); $externalDir = $this->getExternalDirectory();
$autoload = implode(DIRECTORY_SEPARATOR, [$externalDir, "vendor", "autoload.php"]); $autoload = implode(DIRECTORY_SEPARATOR, [$externalDir, "vendor", "autoload.php"]);
if (!is_file($autoload)) { if (!is_file($autoload)) {
@ -238,6 +239,7 @@ namespace Documents\Install {
"/Site/Configuration", "/Site/Configuration",
"/Core/External/vendor", "/Core/External/vendor",
"/files/uploaded", "/files/uploaded",
"/react",
]; ];
$nonWritableDirectories = []; $nonWritableDirectories = [];
@ -801,7 +803,7 @@ namespace Documents\Install {
$progressText = htmlspecialchars($currentView["progressText"]); $progressText = htmlspecialchars($currentView["progressText"]);
$class = ["my-3"]; $class = ["my-3"];
if (!in_array($this->currentStep, [self::CHECKING_REQUIREMENTS, self::INSTALL_DEPENDENCIES])) { if (!in_array($this->currentStep, [self::CHECKING_REQUIREMENTS, self::INSTALL_DEPENDENCIES])) {
$class[] = "hidden"; $class[] = "d-none";
} }
$html .= html_tag("div", ["class" => $class, "id" => "progressText"], [$progressText, $spinnerIcon], false); $html .= html_tag("div", ["class" => $class, "id" => "progressText"], [$progressText, $spinnerIcon], false);
@ -851,7 +853,7 @@ namespace Documents\Install {
$attrs = ["id" => $id, "class" => ["m-1", "btn", "btn-$type"]]; $attrs = ["id" => $id, "class" => ["m-1", "btn", "btn-$type"]];
if (isset($button["hidden"]) && $button["hidden"]) { if (isset($button["hidden"]) && $button["hidden"]) {
$attrs["class"][] = "hidden"; $attrs["class"][] = "d-none";
} }
if (isset($button["disabled"]) && $button["disabled"]) { if (isset($button["disabled"]) && $button["disabled"]) {

39
cli.php

@ -8,7 +8,6 @@ require_once 'Core/datetime.php';
include_once 'Core/constants.php'; include_once 'Core/constants.php';
use Core\API\Request; use Core\API\Request;
use Core\Configuration\DatabaseScript;
use Core\Driver\SQL\Column\Column; use Core\Driver\SQL\Column\Column;
use Core\Driver\SQL\Condition\Compare; use Core\Driver\SQL\Condition\Compare;
use Core\Driver\SQL\Condition\CondIn; use Core\Driver\SQL\Condition\CondIn;
@ -79,23 +78,9 @@ function printHelp(array $argv): void {
} }
} }
function applyPatch(\Core\Driver\SQL\SQL $sql, string $patchName): bool { function applyPatch(SQL $sql, string $patchFile): bool {
$class = str_replace('/', '\\', $patchName); $queries = [];
$className = "\\Core\\Configuration\\$class"; @include_once $patchFile;
$classPath = getClassPath($className);
if (!file_exists($classPath) || !is_readable($classPath)) {
printLine("Database script file does not exist or is not readable");
return false;
}
include_once $classPath;
$obj = new $className();
if (!($obj instanceof DatabaseScript)) {
printLine("Not a database script");
return false;
}
$queries = $obj->createQueries($sql);
foreach ($queries as $query) { foreach ($queries as $query) {
if (!$query->execute($sql)) { if (!$query->execute($sql)) {
printLine($sql->getLastError()); printLine($sql->getLastError());
@ -288,7 +273,10 @@ function onMaintenance(array $argv): void {
_exit("Maintenance disabled"); _exit("Maintenance disabled");
} else if ($action === "update") { } else if ($action === "update") {
$logger->info("Update started"); $logger->info("Update started");
$oldPatchFiles = glob('Core/Configuration/Patch/*.php'); $oldPatchFiles = array_merge(
glob('Core/Configuration/Patch/*.php'),
glob('Site/Configuration/Patch/*.php')
);
printLine("$ git remote -v"); printLine("$ git remote -v");
exec("git remote -v", $gitRemote, $ret); exec("git remote -v", $gitRemote, $ret);
if ($ret !== 0) { if ($ret !== 0) {
@ -351,16 +339,19 @@ function onMaintenance(array $argv): void {
die(); die();
} }
// TODO: also collect patches from Site/Configuration/Patch ... and what about database entities? // TODO: how to handle modified database entities?
$newPatchFiles = glob('Core/Configuration/Patch/*.php'); $newPatchFiles = array_merge(
glob('Core/Configuration/Patch/*.php'),
glob('Site/Configuration/Patch/*.php')
);
$newPatchFiles = array_diff($newPatchFiles, $oldPatchFiles); $newPatchFiles = array_diff($newPatchFiles, $oldPatchFiles);
if (count($newPatchFiles) > 0) { if (count($newPatchFiles) > 0) {
if ($sql) { if ($sql) {
printLine("Applying new database patches"); printLine("Applying new database patches");
sort($newPatchFiles);
foreach ($newPatchFiles as $patchFile) { foreach ($newPatchFiles as $patchFile) {
if (preg_match("/Core\/Configuration\/(Patch\/.*)\.class\.php/", $patchFile, $match)) { if (preg_match("/(Core|Site)\/Configuration\/Patch\/(.*)\.php/", $patchFile, $match)) {
$patchName = $match[1]; applyPatch($sql, $patchFile);
applyPatch($sql, $patchName);
} }
} }
} else { } else {

@ -1,4 +1,3 @@
version: "3.9"
services: services:
web: web:
container_name: webbase-web container_name: webbase-web

@ -27,7 +27,7 @@ function setState(state) {
icon = 'fas fa-times-circle'; icon = 'fas fa-times-circle';
text = "Failed"; text = "Failed";
color = "danger"; color = "danger";
$("#btnRetry").show(); $("#btnRetry").removeClass("d-none");
break; break;
default: default:
@ -74,7 +74,7 @@ function sendRequest(params, done) {
setState(ERROR); setState(ERROR);
statusBox.addClass("alert-danger"); statusBox.addClass("alert-danger");
statusBox.html("An error occurred during installation. Try <a href=\"/index.php\">restarting the process</a>."); statusBox.html("An error occurred during installation. Try <a href=\"/index.php\">restarting the process</a>.");
statusBox.show(); statusBox.removeClass("d-none");
}).always(function() { }).always(function() {
if(done) done(success); if(done) done(success);
}); });
@ -82,15 +82,15 @@ function sendRequest(params, done) {
function retry() { function retry() {
let progressText = $("#progressText"); let progressText = $("#progressText");
let wasHidden = progressText.hasClass("hidden"); let wasHidden = progressText.hasClass("d-none");
$("#btnRetry").hide(); $("#btnRetry").addClass("d-none");
progressText.removeClass("hidden"); progressText.removeClass("d-none");
sendRequest({ }, function(success) { sendRequest({ }, function(success) {
if (wasHidden) { if (wasHidden) {
$("#progressText").addClass("hidden"); $("#progressText").addClass("d-none");
} }
if(!success) { if(!success) {
$("#btnRetry").show(); $("#btnRetry").removeClass("d-none");
} }
}); });
} }