Commit 5c7c1e2d authored by Carsten  Rose's avatar Carsten Rose
Browse files

REST: first successful POST

parent 446e7e7f
Pipeline #1547 passed with stage
in 2 minutes and 25 seconds
......@@ -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();
......
......@@ -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);
}
......
......@@ -64,7 +64,7 @@ class Save {
}
/**
* Starts save process. On succcess, returns forwardmode/page.
* Starts save process. Returns recordId.
*
* @return int
* @throws CodeException
......
......@@ -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);
......
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