diff --git a/extension/Classes/Core/Form/FormAsFile.php b/extension/Classes/Core/Form/FormAsFile.php index 09ae07e3f0a0dc42f9d04ff0e416d6a8d9aa077d..ecdfa4fe9c54c507ac0037110bcb9d34503ddd81 100644 --- a/extension/Classes/Core/Form/FormAsFile.php +++ b/extension/Classes/Core/Form/FormAsFile.php @@ -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\OnArray; use IMATHUZH\Qfq\Core\Helper\OnString; use IMATHUZH\Qfq\Core\Helper\Path; use IMATHUZH\Qfq\Core\Helper\SqlQuery; @@ -32,16 +33,16 @@ class FormAsFile public static function importForm(string $formName, Database $database): bool { // Get file stats both from file system and DB and exit if they are equal - $pathFileName = self::formPathFileName($formName, $database); + $cwdToFormFile = self::formPathFileName($formName, $database); $fileReadException = new \UserFormException(json_encode([ - ERROR_MESSAGE_TO_USER => "Form file not found or missing permission: " . baseName($pathFileName), - ERROR_MESSAGE_TO_DEVELOPER => "Form definition file not found or no permission to read file: '$pathFileName'"]), + ERROR_MESSAGE_TO_USER => "Form file not found or missing permission: " . baseName($cwdToFormFile), + ERROR_MESSAGE_TO_DEVELOPER => "Form definition file not found or no permission to read file: '$cwdToFormFile'"]), ERROR_FORM_NOT_FOUND); - if(!file_exists($pathFileName)) { + if(!file_exists($cwdToFormFile)) { self::deleteFormDB($formName, $database); throw $fileReadException; } - $fileStatsNew = self::formFileStatsJson($pathFileName); + $fileStatsNew = self::formFileStatsJson($cwdToFormFile); if ($fileStatsNew === false) { self::deleteFormDB($formName, $database); throw $fileReadException; @@ -54,22 +55,31 @@ class FormAsFile } // Read form file - $fileContents = file_get_contents($pathFileName); + $fileContents = file_get_contents($cwdToFormFile); if ($fileContents === false) { self::deleteFormDB($formName, $database); throw $fileReadException; } $formFromFile = json_decode($fileContents, true); + // form elements exist? + if (!isset($formFromFile[F_FILE_FORM_ELEMENT])) { + Thrower::userFormException('Failed to import form file.', "Json key '" . F_FILE_FORM_ELEMENT . "' in file '$cwdToFormFile' is missing."); + } + // make sure container names are unique and non-empty $containerNames = []; foreach ($formFromFile[F_FILE_FORM_ELEMENT] as $formElementFromFile) { + $keysNotSet = OnArray::keysNotSet([FE_CLASS, FE_NAME], $formElementFromFile); + if (!empty($keysNotSet)) { + Thrower::userFormException('Failed to import form file.', "One or more required keys are missing in FormElement definition in file: '$cwdToFormFile'. Missing keys: " . implode(', ', $keysNotSet)); + } if ($formElementFromFile[FE_CLASS] === FE_CLASS_CONTAINER) { if (in_array($formElementFromFile[FE_NAME], $containerNames)) { - Thrower::userFormException('Failed to import form file.', "Multiple formElements of class container with the same name '" . $formElementFromFile[FE_NAME] . "' in form file '$pathFileName'"); + Thrower::userFormException('Failed to import form file.', "Multiple formElements of class container with the same name '" . $formElementFromFile[FE_NAME] . "' in form file '$cwdToFormFile'"); } if ($formElementFromFile[FE_NAME] == '') { - Thrower::userFormException('Failed to import form file.', "Found formElement of class container with empty name in form file '$pathFileName'"); + Thrower::userFormException('Failed to import form file.', "Found formElement of class container with empty name in form file '$cwdToFormFile'"); } $containerNames[] = $formElementFromFile[FE_NAME]; } @@ -77,8 +87,7 @@ class FormAsFile // Delete old form with that name from DB if it exists. if (array_key_exists(F_ID, $formFromDb)) { - $formId = $formFromDb[F_ID]; - self::deleteFormDBWithId($formId, $database); + self::deleteFormDBWithId($formFromDb[F_ID], $database); } // Insert new Form to DB (after filtering allowed columns and adding column 'name') @@ -108,6 +117,9 @@ class FormAsFile foreach ($formFromFile[F_FILE_FORM_ELEMENT] as &$formElementFromFile) { if (array_key_exists(FE_FILE_CONTAINER_NAME, $formElementFromFile)) { $containerName = $formElementFromFile[FE_FILE_CONTAINER_NAME]; + if (!isset($containerIds[$containerName])) { + Thrower::userFormException('Failed to import form file.', "Key '" . FE_FILE_CONTAINER_NAME . "' points to non-existing container with name '$containerName' in definition of formElement with name '" . $formElementFromFile[FE_NAME] . "' in file '$cwdToFormFile'"); + } $containerId = $containerIds[$containerName]; $feId = $formElementFromFile[FE_ID]; list($sql, $parameterArray) = SqlQuery::updateRecord(TABLE_NAME_FORM_ELEMENT, [FE_ID_CONTAINER => $containerId], $feId); @@ -604,7 +616,7 @@ class FormAsFile } return $jsonFileNames = array_reduce($files, function ($result, $file) { $fileInfo = pathinfo($file); - if (array_key_exists('extension', $fileInfo) && $fileInfo['extension'] === 'json') { + if (isset($fileInfo['extension']) && isset($fileInfo['filename']) && $fileInfo['extension'] === 'json') { $result[] = $fileInfo['filename']; } return $result; @@ -629,12 +641,11 @@ class FormAsFile */ private static function formToJson(string $formName, Database $database, ?int $formId = null): array { - // Get form from DB + // Get form from DB (either by id or by name) if ($formId !== null) { list($sql, $parameterArray) = SqlQuery::selectFormById($formId); $form = $database->sql($sql, ROW_EXPECT_1, $parameterArray, "Form with id $formId not found."); // array(column name => value) - $formName = $form[F_NAME]; } else { list($sql, $parameterArray) = SqlQuery::selectFormByName($formName); $form = $database->sql($sql, ROW_EXPECT_1, @@ -678,13 +689,13 @@ class FormAsFile $formElements = array_map(function ($formElement) use ($containerNames) { // in case container name was auto adjusted above we set new name - if (array_key_exists($formElement[FE_ID], $containerNames)) { + if (isset($containerNames[$formElement[FE_ID]])) { $formElement[FE_NAME] = $containerNames[$formElement[FE_ID]]; } // Replace container id references with name references $containerId = $formElement[FE_ID_CONTAINER]; - if ($containerId !== 0 && array_key_exists($containerId, $containerNames)) { + if ($containerId !== 0 && isset($containerNames[$containerId])) { $formElement[FE_FILE_CONTAINER_NAME] = $containerNames[$containerId]; } diff --git a/extension/Classes/Core/Helper/OnArray.php b/extension/Classes/Core/Helper/OnArray.php index 7e9be89d1224fe5da2b51d82f972629aab4f72d3..18def73c29e67922455a8a33acb1ed595dfc626d 100644 --- a/extension/Classes/Core/Helper/OnArray.php +++ b/extension/Classes/Core/Helper/OnArray.php @@ -450,4 +450,16 @@ class OnArray { return '[' . substr($json, 1) . ']'; } + + /** + * return subset of keys in $keys which are not set in $array. + * + * @param array $keys + * @param array $array + * @return array + */ + public static function keysNotSet(array $keys, array $array) + { + return array_filter($keys, function($key) use ($array) {return !isset($array[$key]);}); + } } \ No newline at end of file