Commit 7d6ca4d0 authored by Marc Egger's avatar Marc Egger
Browse files

Refs #10120 Dirty.php: add error hint, FormAsFile.php: fix CWD file path problem when API

parent df7ee54e
Pipeline #3597 failed with stages
in 51 seconds
......@@ -286,7 +286,7 @@ class Dirty {
$primaryKey = $tableVars[F_PRIMARY_KEY];
$formDirtyMode = $tableVars[F_DIRTY_MODE];
$record = $this->dbArray[$this->dbIndexData]->sql("SELECT * FROM `$tableName` WHERE `$primaryKey`=?", ROW_EXPECT_1, [$recordId], "Record to lock not found.");
$record = $this->dbArray[$this->dbIndexData]->sql("SELECT * FROM `$tableName` WHERE `$primaryKey`=?", ROW_EXPECT_1, [$recordId], "Record to lock not found. " . FormAsFile::errorHintFormImport($tableName));
# Dirty workaround: setting the 'expired timestamp' minus 1 second guarantees that the client ask for relock always if the timeout is expired.
$expire = date('Y-m-d H:i:s', strtotime("+" . $tableVars[F_RECORD_LOCK_TIMEOUT_SECONDS] - 1 . " seconds"));
......@@ -320,7 +320,7 @@ class Dirty {
return false; // If there is no recordHashMd5, the check is not possible. Always return 'not modified' (=ok)
}
$record = $this->dbArray[$this->dbIndexData]->sql("SELECT * FROM `$tableName` WHERE `$primaryKey`=?", ROW_EXPECT_1, [$recordId], "Record to lock not found.");
$record = $this->dbArray[$this->dbIndexData]->sql("SELECT * FROM `$tableName` WHERE `$primaryKey`=?", ROW_EXPECT_1, [$recordId], "Record to lock not found. " . FormAsFile::errorHintFormImport($tableName));
$rcMd5 = OnArray::getMd5($record);
......
......@@ -6,11 +6,14 @@ use IMATHUZH\Qfq\Core\Database\Database;
use IMATHUZH\Qfq\Core\Helper\HelperFile;
use IMATHUZH\Qfq\Core\Helper\SqlQuery;
// TODO: Form speichern. siehe zettlr note. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< NEXT
// TODO: bevor ein form/formelement im form editor gespeichert wird, soll es vom file geladen werden (Save.php). Falls das file importiert wurde, gibt es eine fehlermeldung.
// TODO: anfrage nach dirty, form file ueberpruefen (importieren)
// TODO: ausporbieren was passiert wenn ich in Form-Editor auf speicher druecke nachdem ich in einem anderen tab das geanderte form file in die DB lade.
// TODO: form list Report: when form list report is loaded, load new form files into DB and delete removed forms from DB
// TODO: Carsten Fragen: Form backups erstellen vor dem delete?
// TODO: Maybe: solve reference by ID after file change Problem (might not be a big deal since it only happens on git pull)
// Problem: FormEditor and form list might reference a form by an old id. In that case everything has to be reloaded. That's anoying.
// Problem: FormEditor and form list might reference a form by an old id. In that case everything has to be reloaded. That's annoying.
// Variant 1: reference form by name in edit and delete button, not by id (only solver part of the problem)
// Variant 2: track old form ids and relay to new form automatically. Track old form ids in new Form column "oldIds"
......@@ -36,9 +39,24 @@ const FORM_FILE_CONTAINER_NAME = 'containerName_ff'; // key for referencing cont
class FormAsFile
{
/**
* Multiple errors might occur after a form file import. This hint can be added to such exceptions to help users.
* Only returns non-empty string if the table is either Form of FormElement.
*
* @param string $tableName
* @return string
*/
public static function errorHintFormImport (string $tableName = 'Form'): string
{
$message = '';
if (in_array($tableName, [TABLE_NAME_FORM, TABLE_NAME_FORM_ELEMENT])) {
$message .= "Hint: Form definition file might have changed. Please reopen the form list and Form-Editor from scratch.";
}
return $message;
}
/**
* Wrapper to call self::loadForm(...) with a formElement ID instead of a form name.
* Wrapper to call self::importForm(...) with a formElement ID instead of a form name.
*
* @param int $formElementId
* @param Database $database
......@@ -47,7 +65,7 @@ class FormAsFile
* @throws \DbException
* @throws \UserFormException
*/
public static function loadFormElementWithId(int $formElementId, Database $database): bool
public static function importFormElementWithId(int $formElementId, Database $database): bool
{
if ($formElementId === 0) {
return false;
......@@ -61,14 +79,14 @@ class FormAsFile
$FE_FORM_ID = FE_FORM_ID;
$FE_ID = FE_ID;
$formFromDb = $database->sql("SELECT `f`.`$F_ID`, `f`.`$F_NAME` FROM `$TABLE_NAME_FORM` AS f INNER JOIN `$TABLE_NAME_FORM_ELEMENT` AS fe ON f.`$F_ID`=fe.`$FE_FORM_ID` WHERE `fe`.`$FE_ID`=?", ROW_EXPECT_1,
[$formElementId], "Form element with id '$formElementId' not found. This might be because the Form definition file has changed. Please close tab and reload the form list and Form-Editor from scratch.");
[$formElementId], "Form element with id '$formElementId' not found. " . self::errorHintFormImport());
// load form
return self::loadForm($formFromDb[F_NAME], $database);
// import form
return self::importForm($formFromDb[F_NAME], $database);
}
/**
* Wrapper to call self::loadForm(...) with an ID instead of a form name.
* Wrapper to call self::importForm(...) with an ID instead of a form name.
*
* @param int $formId
* @param Database $database
......@@ -77,7 +95,7 @@ class FormAsFile
* @throws \DbException
* @throws \UserFormException
*/
public static function loadFormWithId(int $formId, Database $database): bool
public static function importFormWithId(int $formId, Database $database): bool
{
if ($formId === 0) {
return false;
......@@ -88,10 +106,10 @@ class FormAsFile
$TABLE_NAME_FORM = TABLE_NAME_FORM;
$F_ID = F_ID;
$formFromDb = $database->sql("SELECT `$F_NAME` FROM `$TABLE_NAME_FORM` AS f WHERE `f`.`$F_ID`=? AND `f`.`deleted`='no'", ROW_EXPECT_1,
[$formId], "Form with id '$formId' not found. This might be because the Form definition file has changed. Please close tab and reload the form list and Form-Editor from scratch.");
[$formId], "Form with id '$formId' not found. " . self::errorHintFormImport());
// load form
return self::loadForm($formFromDb[F_NAME], $database);
// import form
return self::importForm($formFromDb[F_NAME], $database);
}
/**
......@@ -110,20 +128,28 @@ class FormAsFile
* @throws \DbException
* @throws \UserFormException
*/
public static function loadForm(string $formName, Database $database): bool
public static function importForm(string $formName, Database $database): bool
{
// Get file stats both from file system and DB and exit if they are equal
self::CheckFormNameValid($formName);
$filePath = SYSTEM_FORM_FILE_PATH . '/' . $formName . ".json";
self::enforceFormNameValid($formName);
$pathFileName = HelperFile::correctRelativePathFileName(SYSTEM_FORM_FILE_PATH . '/' . $formName . ".json");
$fileReadException = new \UserFormException(json_encode([
ERROR_MESSAGE_TO_USER => 'Form not found.',
ERROR_MESSAGE_TO_DEVELOPER => "Form definition file not found or no permission to read file: '$filePath'"]),
ERROR_MESSAGE_TO_USER => "Form file not found or missing permission: {$formName}.json",
ERROR_MESSAGE_TO_DEVELOPER => "Form definition file not found or no permission to read file: '$pathFileName'"]),
ERROR_FORM_NOT_FOUND);
if(!file_exists($filePath)) {
/////// DEBUG /////////
// throw new \UserFormException(json_encode([
// ERROR_MESSAGE_TO_USER => json_encode([$pathFileName, file_exists($pathFileName), getcwd()], JSON_PRETTY_PRINT),
// ERROR_MESSAGE_TO_DEVELOPER => json_encode([$pathFileName, file_exists($pathFileName)], JSON_PRETTY_PRINT)
// ]));
///////////////////////
if(!file_exists($pathFileName)) {
self::deleteForm($formName, $database);
throw $fileReadException;
}
$stat = stat($filePath);
$stat = stat($pathFileName);
if ($stat === false) {
self::deleteForm($formName, $database);
throw $fileReadException;
......@@ -144,7 +170,7 @@ class FormAsFile
}
// Read form file
$fileContents = file_get_contents($filePath);
$fileContents = file_get_contents($pathFileName);
if ($fileContents === false) {
self::deleteForm($formName, $database);
throw $fileReadException;
......@@ -189,13 +215,6 @@ class FormAsFile
}
}
return true;
/////// DEBUG /////////
// throw new \UserFormException(json_encode([
// ERROR_MESSAGE_TO_USER => 'Marc debug error',
// ERROR_MESSAGE_TO_DEVELOPER => json_encode([$containerId, $feId], JSON_PRETTY_PRINT)
// ]));
///////////////////////
}
/**
......@@ -212,9 +231,9 @@ class FormAsFile
* @throws \DbException
* @throws \UserFormException
*/
public static function databaseToFile(string $formName, Database $database): void
public static function exportForm(string $formName, Database $database): void
{
self::CheckFormNameValid($formName);
self::enforceFormNameValid($formName);
// Get form from DB
$FORM = TABLE_NAME_FORM; // can't use constants in strings directly
......@@ -267,12 +286,12 @@ class FormAsFile
if (!is_dir(SYSTEM_FORM_FILE_PATH)) {
mkdir(SYSTEM_FORM_FILE_PATH, 0777, true);
}
$filename = SYSTEM_FORM_FILE_PATH . '/' . $formName . ".json";
$success = file_put_contents($filename, $formJson);
$pathFileName = HelperFile::correctRelativePathFileName(SYSTEM_FORM_FILE_PATH . '/' . $formName . ".json");
$success = file_put_contents($pathFileName, $formJson);
if ($success === false) {
throw new \UserFormException(json_encode([
ERROR_MESSAGE_TO_USER => 'writing file failed',
ERROR_MESSAGE_TO_DEVELOPER => "Can't write to file '$filename'"]),
ERROR_MESSAGE_TO_DEVELOPER => "Can't write to file '$pathFileName'"]),
ERROR_IO_WRITE_FILE);
}
}
......@@ -283,7 +302,7 @@ class FormAsFile
* @param string $formName
* @throws \UserFormException
*/
private static function CheckFormNameValid(string $formName): void
private static function enforceFormNameValid(string $formName): void
{
if (!HelperFile::isValidFileName($formName)) {
throw new \UserFormException(json_encode([
......
......@@ -999,17 +999,17 @@ class QuickFormQuery {
}
// Load form
FormAsFile::loadForm($formName, $this->dbArray[$this->dbIndexQfq]);
FormAsFile::importForm($formName, $this->dbArray[$this->dbIndexQfq]);
$constant = F_NAME; // PhpStorm complains if the constant is directly defined in the string below
$form = $this->dbArray[$this->dbIndexQfq]->sql("SELECT * FROM `Form` AS f WHERE `f`.`$constant` LIKE ? AND `f`.`deleted`='no'", ROW_EXPECT_1,
[$formName], 'Form "' . $formName . '" not found or multiple forms with the same name.');
// If form operates on Form/FormElement then update form from file (If form was changed, throw exception)
// If form operates on Form/FormElement then import form file (If form was changed, throw exception)
$formChanged = false;
if ($form[F_TABLE_NAME] === TABLE_NAME_FORM) {
$formChanged = FormAsFile::loadFormWithId($recordId, $this->dbArray[$this->dbIndexQfq]);
$formChanged = FormAsFile::importFormWithId($recordId, $this->dbArray[$this->dbIndexQfq]);
} elseif ($form[F_TABLE_NAME] === TABLE_NAME_FORM_ELEMENT) {
$formChanged = FormAsFile::loadFormElementWithId($recordId, $this->dbArray[$this->dbIndexQfq]);
$formChanged = FormAsFile::importFormElementWithId($recordId, $this->dbArray[$this->dbIndexQfq]);
}
if($formChanged) {
throw new \UserFormException(json_encode([
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment