diff --git a/extension/Source/api/rest.php b/extension/Source/api/rest.php index 2631e2755abb88028304264dd4eef37a653cb14b..4aca469d8283d098fc07d45ce8cba38a835660c8 100644 --- a/extension/Source/api/rest.php +++ b/extension/Source/api/rest.php @@ -15,40 +15,40 @@ require_once(__DIR__ . '/../core/exceptions/UserFormException.php'); require_once(__DIR__ . '/../core/exceptions/CodeException.php'); require_once(__DIR__ . '/../core/exceptions/DbException.php'); -$restId=array(); -$restForm=array(); +$restId = array(); +$restForm = array(); -$status='HTTP/1.0 409 Bad Request'; +$status = 'HTTP/1.0 409 Bad Request'; try { try { $form = OnString::splitPathInfoToIdForm($_SERVER['PATH_INFO'], $restId, $restForm); // get latest `ìd` - $id=end($restId); + $id = end($restId); // Fake Bodytext setup $bodytext = TYPO3_RECORD_ID . '=' . $id . PHP_EOL; $bodytext .= TYPO3_FORM . '=' . $form . PHP_EOL; - $method=$_SERVER['REQUEST_METHOD']; - switch($method){ + $method = $_SERVER['REQUEST_METHOD']; + switch ($method) { case REQUEST_METHOD_GET: break; case REQUEST_METHOD_POST: - if($id!=0){ + if ($id != 0) { throw new UserFormException('Method POST needs no id or id=0', ERROR_REST_INVALID_ID); } - $_POST = json_decode(file_get_contents('php://input'), true); + $_POST = json_decode(file_get_contents('php://input'), true); break; case REQUEST_METHOD_PUT: - if($id==0){ + if ($id == 0) { throw new UserFormException('Method PUT needs an id>0', ERROR_REST_INVALID_ID); } $_POST = json_decode(file_get_contents('php://input'), true); break; case REQUEST_METHOD_DELETE: - if($id==0){ + if ($id == 0) { throw new UserFormException('Method DELETE needs an id>0', ERROR_REST_INVALID_ID); } break; @@ -58,7 +58,7 @@ try { $qfq = new QuickFormQuery(['bodytext' => $bodytext]); $answer = $qfq->rest($restId, $restForm); - $status='HTTP/1.0 200 OK'; + $status = 'HTTP/1.0 200 OK'; } catch (qfq\CodeException $e) { $answer[API_MESSAGE] = $e->formatMessage(); diff --git a/extension/Source/core/QuickFormQuery.php b/extension/Source/core/QuickFormQuery.php index c3e2b943cbdd8183ae450725e3681841c72d16a1..d9636c2b12863ea4152a0b7a914707b1a3ce3a8b 100644 --- a/extension/Source/core/QuickFormQuery.php +++ b/extension/Source/core/QuickFormQuery.php @@ -344,9 +344,13 @@ class QuickFormQuery { $flagApiStructureReGroup = true; // Fill STORE_FORM - if ($formMode === FORM_UPDATE || $formMode === FORM_SAVE) { - $fillStoreForm = new FillStoreForm(); - $fillStoreForm->process($formMode); + switch ($formMode) { + case FORM_UPDATE: + case FORM_SAVE: + case FORM_REST: + $fillStoreForm = new FillStoreForm(); + $fillStoreForm->process($formMode); + break; } $recordId = $this->store->getVar(SIP_RECORD_ID, STORE_SIP . STORE_TYPO3 . STORE_CLIENT . STORE_ZERO); @@ -372,8 +376,9 @@ class QuickFormQuery { Session::checkSessionExpired($this->formSpec[F_SESSION_TIMEOUT_SECONDS]); if ($formName !== false) { - // Validate only if there is a 'real' form (not a FORM_DELETE with only a tablename). - $sipFound = $this->validateForm($foundInStore, $formMode); + // Validate (only if there is a 'real' form, not a FORM_DELETE with only a tablename). + // Attention: $formModeNew will be set + $sipFound = $this->validateForm($foundInStore, $formMode, $formModeNew); } else { // FORM_DELETE without a form definition: Fake the form with only a tableName. @@ -414,10 +419,10 @@ class QuickFormQuery { } // Check (and release) dirtyRecord. - if ($formMode === FORM_DELETE || $formMode === FORM_SAVE) { + if ($formModeNew === FORM_DELETE || $formModeNew === FORM_SAVE) { $dirty = new Dirty(false, $this->dbIndexData, $this->dbIndexQfq); - $answer = $dirty->checkDirtyAndRelease($formMode, $this->formSpec[F_RECORD_LOCK_TIMEOUT_SECONDS], + $answer = $dirty->checkDirtyAndRelease($formModeNew, $this->formSpec[F_RECORD_LOCK_TIMEOUT_SECONDS], $this->formSpec[F_DIRTY_MODE], $this->formSpec[F_TABLE_NAME], $this->formSpec[F_PRIMARY_KEY], $recordId, true); // In case of a conflict, return immediately @@ -429,7 +434,7 @@ class QuickFormQuery { } // FORM_LOAD: if there is a foreign exclusive record lock - show form in F_MODE_READONLY mode. - if ($formMode === FORM_LOAD) { + if ($formModeNew === FORM_LOAD) { $dirty = new Dirty(false, $this->dbIndexData, $this->dbIndexQfq); $recordDirty = array(); $rcLockFound = $dirty->getCheckDirty($this->formSpec[F_TABLE_NAME], $recordId, $recordDirty, $msg); @@ -438,7 +443,7 @@ class QuickFormQuery { } } - switch ($formMode) { + switch ($formModeNew) { case FORM_DELETE: $build = new Delete($this->dbIndexData); break; @@ -471,10 +476,10 @@ class QuickFormQuery { } $formAction = new FormAction($this->formSpec, $this->dbArray[$this->dbIndexData], $this->phpUnit); - switch ($formMode) { + switch ($formModeNew) { case FORM_LOAD: $formAction->elements($recordId, $this->feSpecAction, FE_TYPE_BEFORE_LOAD); - $data = $build->process($formMode); + $data = $build->process($formModeNew); $tmpClass = is_numeric($this->formSpec[F_BS_COLUMNS]) ? ('col-md-' . $this->formSpec[F_BS_COLUMNS]) : $this->formSpec[F_BS_COLUMNS]; // $data = Support::wrapTag("<div class='" . 'col-md-' . $this->formSpec[F_BS_COLUMNS] . "'>", $data); $data = Support::wrapTag('<div class="' . $tmpClass . '">', $data); @@ -485,7 +490,7 @@ class QuickFormQuery { case FORM_UPDATE: $formAction->elements($recordId, $this->feSpecAction, FE_TYPE_BEFORE_LOAD); // data['form-update']=.... - $data = $build->process($formMode); + $data = $build->process($formModeNew); $formAction->elements($recordId, $this->feSpecAction, FE_TYPE_AFTER_LOAD); break; @@ -500,7 +505,7 @@ class QuickFormQuery { case FORM_SAVE: $this->logFormSubmitRequest(); - $recordId = $this->store->getVar(SIP_RECORD_ID, STORE_SIP); + $recordId = $this->store->getVar(SIP_RECORD_ID, STORE_SIP . STORE_TYPO3); // Action: Before $feTypeList = FE_TYPE_BEFORE_SAVE . ',' . ($recordId == 0 ? FE_TYPE_BEFORE_INSERT : FE_TYPE_BEFORE_UPDATE); @@ -539,6 +544,11 @@ class QuickFormQuery { // Action: Sendmail $formAction->elements($rc, $this->feSpecAction, FE_TYPE_SENDMAIL); + if ($formMode == FORM_REST) { + $data = ['id' => $rc]; + $flagApiStructureReGroup=false; + break; + } $customForward = $this->setForwardModePage(); @@ -563,10 +573,7 @@ class QuickFormQuery { $feSpecNative = HelperFormElement::setLanguage($feSpecNative, $parameterLanguageFieldName); $this->feSpecNative = HelperFormElement::setFeContainerFormElementId($feSpecNative, $this->formSpec[F_ID], $recordId); - // Retrieve FE Values as JSON - // $data['form-update']=... - // $data = $build->process($formMode, $htmlElementNameIdZero); - $data = $build->process($formMode, false, $this->feSpecNative); + $data = $build->process($formModeNew, false, $this->feSpecNative); } break; @@ -581,15 +588,15 @@ class QuickFormQuery { break; case FORM_REST: + $flagApiStructureReGroup=false; $data = $this->doRestGet(); - $flagApiStructureReGroup = false; break; default: throw new CodeException("This statement should never be reached", ERROR_CODE_SHOULD_NOT_HAPPEN); } - if ($flagApiStructureReGroup && is_array($data)) { + if ($flagApiStructureReGroup && is_array($data) ) { // $data['element-update']=... $data = $this->groupElementUpdateEntries($data); } @@ -1091,6 +1098,7 @@ class QuickFormQuery { case FORM_SAVE: case FORM_UPDATE: + case FORM_REST: $feSpecNative = $this->getNativeFormElements(SQL_FORM_ELEMENT_NATIVE_TG_COUNT, [$this->formSpec[F_ID]], $this->formSpec); break; @@ -1419,12 +1427,14 @@ class QuickFormQuery { * @throws \qfq\UserFormException * @internal param $foundInStore */ - private function validateForm($formNameFoundInStore, $formMode) { + private function validateForm($formNameFoundInStore, $formMode, &$formModeNew) { + + $formModeNew = $formMode; // Retrieve record_id either from SIP (preferred) or via URL $r = $this->store->getVar(SIP_RECORD_ID, STORE_SIP . STORE_TYPO3 . STORE_CLIENT, '', $recordIdFoundInStore); - // no record id: Fake a definition in STORE_TYPO3. + // No record id: Fake a definition in STORE_TYPO3. if ($r === false) { $r = 0; $this->store->setVar(TYPO3_RECORD_ID, $r, STORE_TYPO3); @@ -1465,23 +1475,32 @@ class QuickFormQuery { 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) { - $method = strtolower($this->store::getVar(CLIENT_REQUEST_METHOD, STORE_CLIENT)); - if (false === Support::findInSet($method, $this->formSpec[F_REST_METHOD])) { - throw new UserFormException("Form '". $this->formSpec[F_NAME]. "' is not allowed with method '$method'", ERROR_FORM_REST); + $method = $this->store::getVar(CLIENT_REQUEST_METHOD, STORE_CLIENT); + if (false === Support::findInSet(strtolower($method), $this->formSpec[F_REST_METHOD])) { + throw new UserFormException("Form '" . $this->formSpec[F_NAME] . "' is not allowed with method '$method'", ERROR_FORM_REST); } $this->restCheckAuthToken($this->formSpec[F_REST_TOKEN] ?? ''); + + switch ($method) { + case REQUEST_METHOD_GET: + break; + case REQUEST_METHOD_POST: + case REQUEST_METHOD_PUT: + $formModeNew = FORM_SAVE; + break; + case REQUEST_METHOD_DELETE: + $formModeNew = FORM_DELETE; + break; + default: + throw new CodeException('Unknown Request Method: ' . $method, ERROR_UNKNOWN_MODE); + } } // Form Definition valid? @@ -1898,6 +1917,9 @@ EOF; $ii++; } + $this->store::setVar(SIP_FORM, end($restForm), STORE_SIP); + $this->store::setVar(SIP_RECORD_ID, end($restId), STORE_SIP); + return $this->doForm(FORM_REST); } diff --git a/extension/Source/core/Save.php b/extension/Source/core/Save.php index 9df3c42d02f44e3ecc0ba40a22722df3c2dbf8cd..f0b2504bea97b763eac3213a174af547fa409dfb 100644 --- a/extension/Source/core/Save.php +++ b/extension/Source/core/Save.php @@ -64,7 +64,7 @@ class Save { } /** - * Starts save process. On succcess, returns forwardmode/page. + * Starts save process. Returns recordId. * * @return int * @throws CodeException diff --git a/extension/Source/core/store/FillStoreForm.php b/extension/Source/core/store/FillStoreForm.php index 16ca6dd8719761b202812120b76348ff5115cd93..5426cfed4056036343d230b5efb8ecac760e8327 100644 --- a/extension/Source/core/store/FillStoreForm.php +++ b/extension/Source/core/store/FillStoreForm.php @@ -182,11 +182,12 @@ class FillStoreForm { $formModeGlobal = $this->store->getVar(F_MODE_GLOBAL, STORE_SIP . STORE_EMPTY); if ($formMode == FORM_UPDATE && $formModeGlobal == '') { + # During 'update': fake all elements to be not 'required'. $formModeGlobal = F_MODE_REQUIRED_OFF; } // If called through 'api/...': get STORE_TYPO3 via SIP parameter. - if (isset($clientValues[CLIENT_TYPO3VARS])) { + if (isset($clientValues[CLIENT_TYPO3VARS]) && $formMode != FORM_REST) { $this->store->fillTypo3StoreFromSip($clientValues[CLIENT_TYPO3VARS]); } @@ -209,10 +210,12 @@ class FillStoreForm { } } - // Check if there is a 'new record already saved' situation: - // yes: the names of the input fields are submitted with '<fieldname>:0' instead of '<fieldname>:<id>' - // no: regular situation, take real 'recordid' - $fakeRecordId = isset($sipValues[SIP_MAKE_URLPARAM_UNIQ]) ? 0 : $sipValues[SIP_RECORD_ID]; + if ($formMode != FORM_REST) { + // Check if there is a 'new record already saved' situation: + // yes: the names of the input fields are submitted with '<fieldname>:0' instead of '<fieldname>:<id>' + // no: regular situation, take real 'recordid' + $fakeRecordId = isset($sipValues[SIP_MAKE_URLPARAM_UNIQ]) ? 0 : $sipValues[SIP_RECORD_ID]; + } // Iterate over all FormElements. Sanatize values. Built an assoc array $newValues. foreach ($this->feSpecNative AS $formElement) { @@ -229,7 +232,7 @@ class FillStoreForm { $formElement = $this->evaluate->parseArray($formElement, $skip, $debugStack); // Get related formElement. Construct the field name used in the form. - $clientFieldName = HelperFormElement::buildFormElementName($formElement, $fakeRecordId); + $clientFieldName = ($formMode == FORM_REST) ? $formElement[FE_NAME] : HelperFormElement::buildFormElementName($formElement, $fakeRecordId); // Some Defaults $formElement = Support::setFeDefaults($formElement, [F_MODE => $formModeGlobal]); @@ -309,7 +312,7 @@ class FillStoreForm { // Check only if there is something. if ($val !== '' && $formMode != FORM_UPDATE && $formElement[FE_MODE] != FE_MODE_HIDDEN) { $val = Sanitize::sanitize($val, $formElement[FE_CHECK_TYPE], $formElement[FE_CHECK_PATTERN], - $formElement[FE_DECIMAL_FORMAT], SANITIZE_EXCEPTION, $formElement[F_FE_DATA_PATTERN_ERROR]??''); + $formElement[FE_DECIMAL_FORMAT], SANITIZE_EXCEPTION, $formElement[F_FE_DATA_PATTERN_ERROR] ?? ''); if ($formElement[FE_ENCODE] === FE_ENCODE_SPECIALCHAR) { // $val = htmlspecialchars($val, ENT_QUOTES);