Commit 07c86019 authored by Carsten  Rose's avatar Carsten Rose
Browse files

Refs #7634. Refactor to evaluate REST queries after loadForm

parent ffb1215a
......@@ -11,34 +11,31 @@ namespace qfq;
use qfq;
require_once(__DIR__ . '/../core/QuickFormQuery.php');
require_once(__DIR__ . '/../core/helper/OnString.php');
require_once(__DIR__ . '/../core/Constants.php');
require_once(__DIR__ . '/../core/exceptions/UserFormException.php');
require_once(__DIR__ . '/../core/exceptions/CodeException.php');
require_once(__DIR__ . '/../core/exceptions/DbException.php');
$restIds=array();
try {
try {
$bodytext = OnString::extractFormRecordId($_SERVER['PATH_INFO'], $restIds);
$qfq = new QuickFormQuery(['bodytext' => $bodytext]);
$answer = $qfq->rest($restIds);
$bodytext=OnString::extractFormRecordId($_SERVER['PATH_INFO']);
$qfq = new QuickFormQuery(['bodytext' => $bodytext]);
// $data = $qfq->rest();
} catch (qfq\CodeException $e) {
$answer[API_MESSAGE] = $e->formatMessage();
} catch (qfq\CodeException $e) {
$answer[API_MESSAGE] = $e->formatMessage();
} catch (qfq\UserFormException $e) {
$answer[API_MESSAGE] = $e->formatMessage();
} catch (qfq\UserFormException $e) {
$answer[API_MESSAGE] = $e->formatMessage();
} catch (qfq\UserReportException $e) {
$answer[API_MESSAGE] = $e->formatMessage();
} catch (qfq\DbException $e) {
$answer[API_MESSAGE] = $e->formatMessage();
} catch (qfq\DbException $e) {
$answer[API_MESSAGE] = $e->formatMessage();
}
} catch (\Exception $e) {
$answer[API_MESSAGE] = "Generic Exception: " . $e->getMessage();
}
header("Content-Type: application/json");
echo json_encode($answer);
......@@ -32,16 +32,20 @@ const TABLE_NAME_FORM = 'Form';
const TABLE_NAME_FORM_ELEMENT = 'FormElement';
const TABLE_NAME_SPLIT = 'Split';
// Form Mode
const FORM_LOAD = 'form_load';
const FORM_SAVE = 'form_save';
const FORM_UPDATE = 'form_update';
const FORM_DELETE = 'form_delete';
const FORM_DRAG_AND_DROP = 'form_drag_and_drop';
const FORM_REST = 'form_rest';
const FORM_PERMISSION_SIP = 'sip';
const FORM_PERMISSION_LOGGED_IN = 'logged_id';
const FORM_PERMISSION_LOGGED_OUT = 'logged_out';
const FORM_PERMISSION_ALWAYS = 'always';
const FORM_PERMISSION_NEVER = 'never';
const FORM_PERMISSION_REST = 'rest';
const FORM_BUTTON_NEW = 'new';
const FORM_BUTTON_DELETE = 'delete';
const FORM_BUTTON_CLOSE = 'close';
......@@ -223,6 +227,7 @@ const ERROR_SMALLER_THAN_MIN = 1083;
const ERROR_LARGER_THAN_MAX = 1084;
const ERROR_INVALID_DECIMAL_FORMAT = 1085;
const ERROR_INVALID_DATE = 1086;
const ERROR_FORM_REST = 1087;
// Subrecord
const ERROR_SUBRECORD_MISSING_COLUMN_ID = 1100;
......@@ -425,7 +430,6 @@ const CLIENT_COOKIE_QFQ = 'cookieQfq';
// T3 Bodytext Keywords
const TYPO3_FORM = CLIENT_FORM;
const TYPO3_RECORD_ID = CLIENT_RECORD_ID;
const TYPO3_REST_PATH = 'restPath';
const TYPO3_BE_USER_LOGGED_IN = 'beUserLoggedIn'; // 'yes' | 'no'
const TYPO3_BE_USER = 'beUser'; // 'yes' | 'no'
const TYPO3_FE_USER = 'feUser';
......@@ -984,6 +988,10 @@ const F_ORDER_COLUMN_NAME = 'ord';
const F_SHOW_ID_IN_FORM_TITLE = SYSTEM_SHOW_ID_IN_FORM_TITLE;
const F_REST_SQL_LIST = 'restSqlList';
const F_REST_SQL_DATA = 'restSqlData';
const F_REST_PARAM = 'restParam';
// FORM_ELEMENT_STATI
const FE_MODE_SHOW = 'show';
const FE_MODE_READONLY = 'readonly';
......
......@@ -325,6 +325,7 @@ class QuickFormQuery {
*
* @param string $formMode FORM_LOAD | FORM_UPDATE | FORM_SAVE | FORM_DELETE
*
* @param array $restIds
* @return array|string
* @throws CodeException
* @throws DbException
......@@ -335,7 +336,7 @@ class QuickFormQuery {
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
*/
private function doForm($formMode) {
private function doForm($formMode, array $restIds=array()) {
$data = '';
$foundInStore = '';
$flagApiStructureReGroup = true;
......@@ -398,10 +399,13 @@ class QuickFormQuery {
// For 'new' record always create a new Browser TAB-uniq (for this current form, nowhere else used) SIP.
// With such a Browser TAB-uniq SIP, multiple Browser TABs and following repeated NEWs are easily implemented.
if (!$sipFound || ($formMode == FORM_LOAD && $recordId === 0)) {
$this->store->createSipAfterFormLoad($formName);
if ($formMode != FORM_REST) {
if (!$sipFound || ($formMode == FORM_LOAD && $recordId === 0)) {
$this->store->createSipAfterFormLoad($formName);
}
}
// Fill STORE_BEFORE
if ($this->store->getVar($this->formSpec[F_PRIMARY_KEY], STORE_BEFORE) === false) {
$this->store->fillStoreWithRecord($this->formSpec[F_TABLE_NAME], $recordId,
$this->dbArray[$this->dbIndexData], $this->formSpec[F_PRIMARY_KEY], STORE_BEFORE);
......@@ -422,7 +426,7 @@ class QuickFormQuery {
}
}
// FORM_LOAD: if there is an foreign exclusive record lock - show form in F_MODE_READONLY mode.
// FORM_LOAD: if there is a foreign exclusive record lock - show form in F_MODE_READONLY mode.
if ($formMode === FORM_LOAD) {
$dirty = new Dirty(false, $this->dbIndexData, $this->dbIndexQfq);
$recordDirty = array();
......@@ -432,27 +436,36 @@ class QuickFormQuery {
}
}
if ($formMode === FORM_DELETE) {
$build = new Delete($this->dbIndexData);
} else {
$tableDefinition = $this->dbArray[$this->dbIndexData]->getTableDefinition($this->formSpec[F_TABLE_NAME]);
$this->store->fillStoreTableDefaultColumnType($tableDefinition);
switch ($formMode) {
case FORM_DELETE:
$build = new Delete($this->dbIndexData);
break;
case FORM_REST:
break;
case FORM_LOAD:
case FORM_SAVE:
case FORM_UPDATE:
case FORM_DRAG_AND_DROP:
switch ($this->formSpec['render']) {
case 'plain':
$build = new BuildFormPlain($this->formSpec, $this->feSpecAction, $this->feSpecNative, $this->dbArray);
break;
case 'table':
$build = new BuildFormTable($this->formSpec, $this->feSpecAction, $this->feSpecNative, $this->dbArray);
break;
case 'bootstrap':
$build = new BuildFormBootstrap($this->formSpec, $this->feSpecAction, $this->feSpecNative, $this->dbArray);
break;
default:
throw new CodeException("This statement should never be reached", ERROR_CODE_SHOULD_NOT_HAPPEN);
}
$tableDefinition = $this->dbArray[$this->dbIndexData]->getTableDefinition($this->formSpec[F_TABLE_NAME]);
$this->store->fillStoreTableDefaultColumnType($tableDefinition);
switch ($this->formSpec['render']) {
case 'plain':
$build = new BuildFormPlain($this->formSpec, $this->feSpecAction, $this->feSpecNative, $this->dbArray);
break;
case 'table':
$build = new BuildFormTable($this->formSpec, $this->feSpecAction, $this->feSpecNative, $this->dbArray);
break;
case 'bootstrap':
$build = new BuildFormBootstrap($this->formSpec, $this->feSpecAction, $this->feSpecNative, $this->dbArray);
break;
default:
throw new CodeException("This statement should never be reached", ERROR_CODE_SHOULD_NOT_HAPPEN);
}
break;
default:
throw new CodeException("This statement should never be reached", ERROR_CODE_SHOULD_NOT_HAPPEN);
}
$formAction = new FormAction($this->formSpec, $this->dbArray[$this->dbIndexData], $this->phpUnit);
......@@ -543,7 +556,6 @@ class QuickFormQuery {
if ($getJson) {
// Values of FormElements might be changed during 'afterSave': rebuild the form to load the new values. Especially for non primary template groups.
// $this->loadFormSpecification($formMode, $recordId, $foundInStore);
$feSpecNative = $this->getNativeFormElements(SQL_FORM_ELEMENT_NATIVE_TG_COUNT, [$this->formSpec[F_ID]], $this->formSpec);
$parameterLanguageFieldName = $this->store->getVar(SYSTEM_PARAMETER_LANGUAGE_FIELD_NAME, STORE_SYSTEM);
$feSpecNative = HelperFormElement::setLanguage($feSpecNative, $parameterLanguageFieldName);
......@@ -566,6 +578,11 @@ class QuickFormQuery {
$formAction->elements($recordId, $this->feSpecAction, FE_TYPE_AFTER_LOAD);
break;
case FORM_REST:
$data = $this->doRestGet($restIds);
$flagApiStructureReGroup = false;
break;
default:
throw new CodeException("This statement should never be reached", ERROR_CODE_SHOULD_NOT_HAPPEN);
}
......@@ -578,6 +595,48 @@ class QuickFormQuery {
return $data;
}
/**
* @param array $restIds
* @return array
* @throws CodeException
* @throws DbException
* @throws UserFormException
* @throws UserReportException
*/
private function doRestGet(array $restIds) {
$param=array();
$paramNames=explode(',', $this->formSpec[F_REST_PARAM]??'');
foreach($paramNames as $key){
switch($key){
case TYPO3_FORM:
case TYPO3_RECORD_ID:
throw new UserFormException("Name '$key' is forbidden in " . F_REST_PARAM, ERROR_INVALID_VALUE);
break;
default:
break;
}
$param[$key]=array_shift($restIds);
if(null===$param[$key]){
throw new UserFormException("Parameter '$key' not found in REST path (typically too few parameter)", ERROR_MISSING_REQUIRED_PARAMETER);
}
}
// Copy url parameter to STORE_TYPO3
$this->store::appendToStore($param, STORE_TYPO3);
$r = $this->store::getVar(TYPO3_RECORD_ID, STORE_TYPO3);
$key = empty($r) ? F_REST_SQL_LIST : F_REST_SQL_DATA;
if(!isset($this->formSpec[$key])){
throw new UserFormException("Missing Parameter '$key'", ERROR_INVALID_VALUE);
}
return $this->evaluate->parse($this->formSpec[$key]);
}
/**
* Copies state 'hidden' from a FE pill to all FE child elements of that pill.
*
......@@ -838,7 +897,7 @@ class QuickFormQuery {
* Loaded 'action' FormElements are in $this->feSpecAction
* Loaded 'native' FormElements are in $this->feSpecNative
*
* @param string $mode FORM_LOAD|FORM_SAVE|FORM_UPDATE
* @param string $mode FORM_LOAD|FORM_SAVE|FORM_UPDATE|FORM_REST
* @param int $recordId
* @param string $foundInStore
* @param string $formLogMode
......@@ -873,7 +932,7 @@ class QuickFormQuery {
// Check if there is a recordId specified in Bodytext - as variable or query.
$rTmp = $this->store->getVar(CLIENT_RECORD_ID, STORE_TYPO3, SANITIZE_ALLOW_ALL);
if (false !== $rTmp && !is_int($rTmp)) {
if (false !== $rTmp && !ctype_digit($rTmp)) {
$rTmp = $this->evaluate->parse($rTmp);
$this->store->setVar(CLIENT_RECORD_ID, $rTmp, STORE_TYPO3);
}
......@@ -886,10 +945,6 @@ class QuickFormQuery {
$form = $this->checkFormLogMode($form);
$form = $this->modeCleanFormConfig($mode, $form);
// Save specific elements to be expanded later.
$parseLater = OnArray::getArrayItems($form, [F_FORWARD_PAGE]);
$form[F_FORWARD_PAGE] = '';
HelperFormElement::explodeParameter($form, F_PARAMETER);
unset($form[F_PARAMETER]);
if (isset($form[FE_FILL_STORE_VAR])) {
......@@ -897,6 +952,12 @@ class QuickFormQuery {
unset($form[FE_FILL_STORE_VAR]);
}
// Save specific elements to be expanded later.
$parseLater = OnArray::getArrayItems($form, [F_FORWARD_PAGE, F_REST_SQL_LIST, F_REST_SQL_DATA]);
$form[F_FORWARD_PAGE] = '';
$form[F_REST_SQL_LIST] = '';
$form[F_REST_SQL_DATA] = '';
// Setting defaults later is too late.
if (empty($form[F_DB_INDEX])) {
$form[F_DB_INDEX] = $this->dbIndexData;
......@@ -1104,7 +1165,7 @@ class QuickFormQuery {
* Specified in SIP
*
*
* @param string $mode FORM_LOAD|FORM_SAVE|FORM_UPDATE
* @param string $mode FORM_LOAD|FORM_SAVE|FORM_UPDATE|FORM_REST
* @param string $foundInStore
*
* @return bool|string Formname (Form.name) or FALSE (if no formname found)
......@@ -1118,6 +1179,7 @@ class QuickFormQuery {
switch ($mode) {
case FORM_LOAD:
case FORM_REST:
$store = STORE_TYPO3;
break;
case FORM_SAVE:
......@@ -1240,7 +1302,7 @@ class QuickFormQuery {
$formSpec[F_FE_LABEL_ALIGN] = $this->store->getVar(SYSTEM_LABEL_ALIGN, STORE_SYSTEM . STORE_EMPTY);
}
$storeSystem=$this->store::getStore(STORE_SYSTEM);
$storeSystem = $this->store::getStore(STORE_SYSTEM);
foreach ($keys as $key) {
......@@ -1248,7 +1310,7 @@ class QuickFormQuery {
$this->store->setVar($key, $formSpec[$key], STORE_SYSTEM);
} else {
// if not found set ''
$formSpec[$key] = $storeSystem[$key]??'';
$formSpec[$key] = $storeSystem[$key] ?? '';
}
}
......@@ -1357,10 +1419,20 @@ class QuickFormQuery {
break;
case FORM_PERMISSION_NEVER:
throw new UserFormException("Loading form forbidden.", ERROR_FORM_FORBIDDEN);
break;
case FORM_PERMISSION_REST:
if ($formMode != FORM_REST) {
throw new UserFormException("Try to load a REST form", ERROR_FORM_REST);
}
break;
default:
throw new CodeException("Unknown permission mode: '" . $permitMode . "'", ERROR_FORM_UNKNOWN_PERMISSION_MODE);
}
if ($formMode == FORM_REST && $permitMode != FORM_PERMISSION_REST) {
throw new UserFormException("Try to load a non-REST form in REST mode", ERROR_FORM_REST);
}
// Form Definition valid?
if ($this->formSpec['multiMode'] !== 'none' && $this->formSpec['multiSql'] === '') {
throw new UserFormException("MultiMode selected, but MultiSQL missing", ERROR_MULTI_SQL_MISSING);
......@@ -1746,5 +1818,22 @@ EOF;
}
/**
* @param array $restIds
* @return array|string
* @throws CodeException
* @throws DbException
* @throws DownloadException
* @throws UserFormException
* @throws UserReportException
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
*/
public function rest(array $restIds) {
return $this->doForm(FORM_REST, $restIds);
}
}
\ No newline at end of file
......@@ -14,8 +14,7 @@ require_once(__DIR__ . '/../Constants.php');
* Class OnString
* @package qfq
*/
class OnString
{
class OnString {
/**
* Returns part of haystack string starting from and including the last occurrence of needle to the end of haystack.
......@@ -214,51 +213,62 @@ class OnString
* restPath=form2/id2/form3/id3/...
*
* @param $pathInfo
* @param array $rcArrIds
* @return string
* @throws UserFormException
*/
public static function extractFormRecordId($pathInfo) {
$text = '';
public static function extractFormRecordId($pathInfo, array &$rcArrIds) {
// Empty: do nothing
if ($pathInfo == '') {
return '';
}
// Remove optional leading '/'
if ($pathInfo[0] == '/') {
$pathInfo = substr($pathInfo, 1);
}
// Remove optional trailing '/'
$len = strlen($pathInfo);
if ($len > 0 && $pathInfo[$len - 1] == '/') {
$pathInfo = substr($pathInfo, 0, $len - 1);
}
if ($pathInfo == '') {
// Empty now: do nothing
if ($pathInfo == '') {
return '';
}
$param = explode('/', $pathInfo);
$cnt = count($param);
if ($cnt % 2 == 0) {
$id = array_pop($param);
if (!ctype_digit($id)) {
throw new UserFormException('Expect numerial id', ERROR_BROKEN_PARAMETER);
}
$text = TYPO3_RECORD_ID . '=' . $id . PHP_EOL;
// No 'id'. Append '0'
if ($cnt % 2 == 1) {
array_push($param, 0);
}
$form = array_pop($param);
if (!ctype_alnum($form)) {
throw new UserFormException('Expect alphanumeric string', ERROR_BROKEN_PARAMETER);
}
$text .= TYPO3_FORM . '=' . $form . PHP_EOL;
$rcArrIds = array();
if (count($param) > 0) {
$text .= TYPO3_REST_PATH . '=' . implode('/', $param) . PHP_EOL;
while (count($param)>0) {
$form = array_shift($param);
if (!ctype_alnum($form)) {
throw new UserFormException('Expect alphanumeric string', ERROR_BROKEN_PARAMETER);
}
$id = array_shift($param);
// if (!ctype_digit($id)) {
// throw new UserFormException('Expect numerical id', ERROR_BROKEN_PARAMETER);
// }
$rcArrIds[] = $id;
}
// Fake Bodytext setup
$text = TYPO3_RECORD_ID . '=' . $id . PHP_EOL;
$text .= TYPO3_FORM . '=' . $form . PHP_EOL;
return $text;
}
}
Markdown is supported
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