Commit daa66804 authored by Marc Egger's avatar Marc Egger
Browse files

Refs #12345 Add key filter toggle to json form editor

parent ae8316eb
Pipeline #5122 passed with stages
in 4 minutes and 17 seconds
......@@ -1648,7 +1648,6 @@ const COLUMN_WRAP_TOKEN = '+';
const COLUMN_STORE_USER = '=';
const COLUMN_FORM_JSON = 'formJson';
const COLUMN_FORM_JSON_BASE_64 = 'formJsonBase64';
const FORM_NAME_FORM = 'form';
const FORM_NAME_FORM_ELEMENT = 'formElement';
......@@ -1826,6 +1825,9 @@ const TOKEN_DOWNLOAD_MODE = 'M';
const TOKEN_ATTRIBUTE = 'A';
const TOKEN_FUNCTION_CALL = 'call';
const TOKEN_ARGUMENT = 'arg';
const TOKEN_FORM_ID = 'fid';
const TOKEN_ENCODING_BASE_64 = 'b64';
const TOKEN_REDUCE_KEYS = 'reduce';
const TOKEN_THUMBNAIL = 'T';
const TOKEN_THUMBNAIL_DIMENSION = 'W';
......
......@@ -6,6 +6,7 @@ namespace IMATHUZH\Qfq\Core\Form;
use IMATHUZH\Qfq\Core\Database\Database;
use IMATHUZH\Qfq\Core\Exception\Thrower;
use IMATHUZH\Qfq\Core\Helper\HelperFile;
use IMATHUZH\Qfq\Core\Helper\KeyValueStringParser;
use IMATHUZH\Qfq\Core\Helper\Logger;
use IMATHUZH\Qfq\Core\Helper\OnArray;
use IMATHUZH\Qfq\Core\Helper\OnString;
......@@ -139,23 +140,27 @@ class FormAsFile {
// make sure container names are unique and non-empty
$containerNames = [];
foreach ($formFromJson[F_FILE_FORM_ELEMENT] as $formElementFromJson) {
$keysNotSet = OnArray::keysNotSet([FE_CLASS, FE_NAME], $formElementFromJson);
// Check if mandatory keys are set. (Currently unused since no mandatory keys defined)
$keysNotSet = OnArray::keysNotSet([], $formElementFromJson);
if (!empty($keysNotSet)) {
Thrower::userFormException('Failed to import form json.',
"One or more required keys are missing in FormElement definition. Missing keys: " . implode(', ', $keysNotSet)
. ($absoluteFormFilePath !== null ? ". Form file path: '$absoluteFormFilePath'" : ''));
}
if ($formElementFromJson[FE_CLASS] === FE_CLASS_CONTAINER) {
// collect names of container FormElements
if (($formElementFromJson[FE_CLASS] ?? '') === FE_CLASS_CONTAINER) {
if (!key_exists(FE_NAME, $formElementFromJson) || $formElementFromJson[FE_NAME] == '') {
Thrower::userFormException('Failed to import form json.',
"Found formElement of class container with empty or non-existing name."
. ($absoluteFormFilePath !== null ? " Form file path: '$absoluteFormFilePath'" : ''));
}
if (in_array($formElementFromJson[FE_NAME], $containerNames)) {
Thrower::userFormException('Failed to import form json.',
"Multiple formElements of class container with the same name '" . $formElementFromJson[FE_NAME]
. ($absoluteFormFilePath !== null ? ". Form file path: '$absoluteFormFilePath'" : ''));
}
if ($formElementFromJson[FE_NAME] == '') {
Thrower::userFormException('Failed to import form json.',
"Found formElement of class container with empty name."
. ($absoluteFormFilePath !== null ? " Form file path: '$absoluteFormFilePath'" : ''));
}
$containerNames[] = $formElementFromJson[FE_NAME];
}
}
......@@ -182,7 +187,8 @@ class FormAsFile {
foreach ($formFromJson[F_FILE_FORM_ELEMENT] as &$formElementFromJson) {
$feId = self::insertFormElement($formElementFromJson, $formIdNew, $database);
$formElementFromJson[FE_ID] = $feId;
if ($formElementFromJson[FE_CLASS] === FE_CLASS_CONTAINER) {
if (($formElementFromJson[FE_CLASS] ?? '') === FE_CLASS_CONTAINER) {
// the existence of the key FE_NAME is ensured above for FE container
$containerIds[$formElementFromJson[FE_NAME]] = $feId;
}
}
......@@ -507,13 +513,25 @@ class FormAsFile {
*/
public static function renderColumnFormJson($columnValue, $database): string
{
$formJson = '';
if (!ctype_digit($columnValue)) {
Thrower::userFormException('Rendering Json Form failed.', "The special column '_" . COLUMN_FORM_JSON . "' Expects an integer form id but '$columnValue' given.");
// Parse arguments
$param = KeyValueStringParser::parse($columnValue, PARAM_TOKEN_DELIMITER, PARAM_DELIMITER);
foreach ($param as $key => $value) {
if (!in_array($key, [TOKEN_FORM_ID, TOKEN_ENCODING_BASE_64, TOKEN_REDUCE_KEYS])) {
Thrower::userFormException('Rendering Json Form failed.', "Token '$key' not recognized for column _" . COLUMN_FORM_JSON);
}
}
if (empty($param[TOKEN_FORM_ID]) || !ctype_digit($param[TOKEN_FORM_ID])) {
Thrower::userFormException('Rendering Json Form failed.', "The special column '_" . COLUMN_FORM_JSON . "' expects token " . TOKEN_FORM_ID . ' with an integer value.');
}
$formId = intval($columnValue);
$formId = intval($param[TOKEN_FORM_ID]);
$base64 = key_exists(TOKEN_ENCODING_BASE_64, $param);
$reduceKeys = key_exists(TOKEN_REDUCE_KEYS, $param);
$formJson = '';
if ($formId !== 0) {
list($_, $_, $formJson) = self::formToJson('', $database, $formId);
list($_, $_, $formJson) = self::formToJson('', $database, $formId, $reduceKeys);
$formJson = $base64 ? base64_encode($formJson) : $formJson;
}
return $formJson;
}
......@@ -759,12 +777,13 @@ class FormAsFile {
* @param string $formName
* @param Database $database
* @param int|null $formId If given, $formName is ignored
* @param bool $removeUnnecessaryKeys
* @return array [string $formName, int $formId, string $formJson, bool ($adjustedContainerNames > 0), array $form]
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
private static function formToJson(string $formName, Database $database, ?int $formId = null): array {
private static function formToJson(string $formName, Database $database, ?int $formId = null, bool $removeUnnecessaryKeys = false): array {
// Get form from DB (either by id or by name)
if ($formId !== null) {
list($sql, $parameterArray) = SqlQuery::selectFormById($formId);
......@@ -783,6 +802,11 @@ class FormAsFile {
unset($form[F_ID]);
unset($form[F_NAME]);
unset($form[F_FILE_STATS]);
if ($removeUnnecessaryKeys) {
unset($form[COLUMN_CREATED]);
unset($form[COLUMN_MODIFIED]);
$form = self::filterNonDefaultColumns($form, TABLE_NAME_FORM, $database);
}
// Get formElements from DB
list($sql, $parameterArray) = SqlQuery::selectFormElementById($formId);
......@@ -811,7 +835,7 @@ class FormAsFile {
}, []); // array(id => name)
// ajdust formElements for export
$formElements = array_map(function ($formElement) use ($containerNames) {
$formElements = array_map(function ($formElement) use ($containerNames, $removeUnnecessaryKeys, $database) {
// in case container name was auto adjusted above we set new name
if (isset($containerNames[$formElement[FE_ID]])) {
......@@ -829,6 +853,12 @@ class FormAsFile {
unset($formElement[FE_ID]);
unset($formElement[FE_FORM_ID]);
if ($removeUnnecessaryKeys) {
unset($formElement[COLUMN_CREATED]);
unset($formElement[COLUMN_MODIFIED]);
$formElement = self::filterNonDefaultColumns($formElement, TABLE_NAME_FORM_ELEMENT, $database);
}
return $formElement;
}, $formElements);
......@@ -875,4 +905,53 @@ class FormAsFile {
}
return $absoluteBackupFilePath;
}
/**
*
* Returns an associative array with the default value for each column in table $tableName
* return: array(column name => default value)
*
* @param string $tableName
* @param Database $database
* @return array array(column name => default value)
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
private static function getColumnDefaults(string $tableName, Database $database): array
{
$tableDefinition = $database->getTableDefinition($tableName);
return array_reduce($tableDefinition, function ($result, $column) {
$result[$column['Field']] = ($column['Default'] ?? '');
return $result;
}, []);
}
/**
*
* Receives a row $row from table $tableName and returns a new array with only the columns of $row which do not
* contain the default value set for that column.
* Keeps the default values of $tableName in a cache for multiple use of function.
*
* @param array $row
* @param string $tableName
* @param Database $database
* @return array
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
private static function filterNonDefaultColumns(array $row, string $tableName, Database $database): array
{
static $cache = [];
if (!key_exists($tableName, $cache)) {
$cache[$tableName] = self::getColumnDefaults($tableName, $database);
}
$columnDefaults = $cache[$tableName];
// return $formNoDefault: array(column name => value)
return array_filter($row, function ($value, $columnName) use ($columnDefaults) {
return $value !== ($columnDefaults[$columnName] ?? null);
}, ARRAY_FILTER_USE_BOTH);
}
}
\ No newline at end of file
......@@ -29,7 +29,7 @@ class ColumnScript {
* @throws \UserFormException
* @throws \UserReportException
*/
public function render(string $columnValue) {
public static function render(string $columnValue) {
// Parse arguments
$param = KeyValueStringParser::parse($columnValue, PARAM_TOKEN_DELIMITER, PARAM_DELIMITER);
......
......@@ -1298,10 +1298,6 @@ class Report {
$dbQfq = new Database($this->store->getVar(SYSTEM_DB_INDEX_QFQ, STORE_SYSTEM));
$content .= Support::encryptDoubleCurlyBraces(FormAsFile::renderColumnFormJson($columnValue, $dbQfq));
break;
case COLUMN_FORM_JSON_BASE_64:
$dbQfq = new Database($this->store->getVar(SYSTEM_DB_INDEX_QFQ, STORE_SYSTEM));
$content .= base64_encode(FormAsFile::renderColumnFormJson($columnValue, $dbQfq));
break;
default :
......
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