Commit cb2e2a70 authored by Elias Villiger's avatar Elias Villiger
Browse files

Add F_TABLE_ID and improve dirty mode 'none'

parent 2968dc8e
Pipeline #710 passed with stage
in 1 minute and 46 seconds
......@@ -234,7 +234,7 @@ abstract class AbstractBuildForm {
// element-update: with 'value'
$recordId = $this->store->getVar(SIP_RECORD_ID, STORE_SIP . STORE_ZERO);
$md5 = $this->buildRecordHashMd5($this->formSpec[F_TABLE_NAME], $recordId);
$md5 = $this->buildRecordHashMd5($this->formSpec[F_TABLE_NAME], $recordId, $this->formSpec[F_TABLE_ID]);
// Via 'element-update'
$json[][API_ELEMENT_UPDATE][DIRTY_RECORD_HASH_MD5][API_ELEMENT_ATTRIBUTE]['value'] = $md5;
......@@ -365,7 +365,7 @@ abstract class AbstractBuildForm {
public function buildInputRecordHashMd5() {
$recordId = $this->store->getVar(SIP_RECORD_ID, STORE_SIP . STORE_ZERO);
$md5 = $this->buildRecordHashMd5($this->formSpec[F_TABLE_NAME], $recordId);
$md5 = $this->buildRecordHashMd5($this->formSpec[F_TABLE_NAME], $recordId, $this->formSpec[F_TABLE_ID]);
$data = "<input id='" . DIRTY_RECORD_HASH_MD5 . "' name='" . DIRTY_RECORD_HASH_MD5 . "' type='hidden' value='$md5'>";
......@@ -378,17 +378,18 @@ abstract class AbstractBuildForm {
/**
* @param $tableName
* @param $recordId
* @param $tableId
*
* @return string
* @throws CodeException
* @throws DbException
* @throws UserFormException
*/
public function buildRecordHashMd5($tableName, $recordId) {
public function buildRecordHashMd5($tableName, $recordId, $tableId = F_TABLE_ID_DEFAULT) {
$record = array();
if ($recordId != 0) {
$record = $this->dbArray[$this->dbIndexData]->sql("SELECT * FROM $tableName WHERE id=?", ROW_EXPECT_1, [$recordId], "Record to load not found.");
$record = $this->dbArray[$this->dbIndexData]->sql("SELECT * FROM $tableName WHERE $tableId=?", ROW_EXPECT_1, [$recordId], "Record to load not found.");
}
return OnArray::getMd5($record);
......@@ -556,9 +557,10 @@ abstract class AbstractBuildForm {
$skip = [FE_SQL_UPDATE, FE_SQL_INSERT, FE_SQL_DELETE, FE_SQL_AFTER, FE_SQL_BEFORE, FE_PARAMETER, FE_FILL_STORE_VAR, FE_FILE_DOWNLOAD_BUTTON];
// get current data record
if ($recordId > 0 && $this->store->getVar('id', STORE_RECORD) === false) {
if ($recordId > 0 && $this->store->getVar($this->formSpec[F_TABLE_ID], STORE_RECORD) === false) {
$tableName = $this->formSpec[F_TABLE_NAME];
$row = $this->dbArray[$this->dbIndexData]->sql("SELECT * FROM $tableName WHERE id = ?", ROW_EXPECT_1,
$tableId = $this->formSpec[F_TABLE_ID];
$row = $this->dbArray[$this->dbIndexData]->sql("SELECT * FROM $tableName WHERE $tableId = ?", ROW_EXPECT_1,
array($recordId), "Form '" . $this->formSpec[F_NAME] . "' failed to load record '$recordId' from table '" .
$this->formSpec[F_TABLE_NAME] . "'.");
$this->store->setStore($row, STORE_RECORD);
......
......@@ -858,6 +858,9 @@ const F_TYPEAHEAD_LDAP_SEARCH = 'typeAheadLdapSearch';
const F_TYPEAHEAD_LDAP_SEARCH_PREFETCH = 'typeAheadLdapSearchPrefetch';
const F_TYPEAHEAD_LDAP_SEARCH_PER_TOKEN = 'typeAheadLdapSearchPerToken';
const F_TABLE_ID = 'tableId';
const F_TABLE_ID_DEFAULT = 'id';
const F_MODE = 'mode';
const F_MODE_READONLY = 'readonly';
const F_MODE_REQUIRED_OFF = 'requiredOff';
......
......@@ -380,8 +380,8 @@ class QuickFormQuery {
$this->store->createSipAfterFormLoad($formName);
}
if ($this->store->getVar('id', STORE_BEFORE) === false) {
$this->fillStoreWithRecord($this->formSpec[F_TABLE_NAME], $recordId, STORE_BEFORE);
if ($this->store->getVar($this->formSpec[F_TABLE_ID], STORE_BEFORE) === false) {
$this->fillStoreWithRecord($this->formSpec, $recordId, STORE_BEFORE);
}
// Check (and release) dirtyRecord.
......@@ -464,7 +464,7 @@ class QuickFormQuery {
$formAction->elements($recordId, $this->feSpecAction, FE_TYPE_BEFORE_INSERT . ',' . FE_TYPE_BEFORE_UPDATE . ',' . FE_TYPE_BEFORE_SAVE);
// If an old record exist: load it. Necessary to delete uploaded files which should be overwritten.
$this->fillStoreWithRecord($this->formSpec[F_TABLE_NAME], $recordId, STORE_RECORD);
$this->fillStoreWithRecord($this->formSpec, $recordId, STORE_RECORD);
// SAVE
$save = new Save($this->formSpec, $this->feSpecAction, $this->feSpecNative, $this->feSpecNativeRaw);
......@@ -475,7 +475,7 @@ class QuickFormQuery {
$rc = $save->process();
// Reload fresh saved record and fill STORE_RECORD with it.
$this->fillStoreWithRecord($this->formSpec[F_TABLE_NAME], $rc, STORE_RECORD);
$this->fillStoreWithRecord($this->formSpec, $rc, STORE_RECORD);
$save->processAllUploads($rc);
......@@ -483,7 +483,7 @@ class QuickFormQuery {
$status = $formAction->elements($rc, $this->feSpecAction, FE_TYPE_AFTER_INSERT . ',' . FE_TYPE_AFTER_UPDATE . ',' . FE_TYPE_AFTER_SAVE);
if ($status != ACTION_ELEMENT_NO_CHANGE) {
// Reload fresh saved record and fill STORE_RECORD with it.
$this->fillStoreWithRecord($this->formSpec[F_TABLE_NAME], $rc, STORE_RECORD);
$this->fillStoreWithRecord($this->formSpec, $rc, STORE_RECORD);
}
// Action: Paste
......@@ -801,6 +801,7 @@ class QuickFormQuery {
} else {
$form[F_DB_INDEX] = $this->eval->parse($form[F_DB_INDEX]);
}
$form[F_TABLE_ID] = $form[F_TABLE_ID] ?? F_TABLE_ID_DEFAULT;
// Some forms load/save the form data on extra defined databases.
if ($this->dbIndexData != $form[F_DB_INDEX]) {
......@@ -815,7 +816,7 @@ class QuickFormQuery {
// This is needed for filling templateGroup records with their default values
// and for evaluating variables in the Form title
$this->fillStoreWithRecord($form[F_TABLE_NAME], $recordId, STORE_RECORD);
$this->fillStoreWithRecord($form, $recordId, STORE_RECORD);
$formSpec = $this->eval->parseArray($form);
......@@ -1273,7 +1274,7 @@ class QuickFormQuery {
/**
* Load record $id from $table and saves them in $store
*
* @param string $table tablename from where to load record wiht $recordId
* @param array $formSpec tablename and table id column from where to load record with $recordId
* @param string $recordId record ID of current record
* @param string $store name of store where to save the record
*
......@@ -1281,9 +1282,11 @@ class QuickFormQuery {
* @throws DbException
* @throws UserFormException
*/
private function fillStoreWithRecord($table, $recordId, $store = STORE_RECORD) {
private function fillStoreWithRecord($formSpec, $recordId, $store = STORE_RECORD) {
$table = $formSpec[F_TABLE_NAME];
$tableId = $formSpec[F_TABLE_ID];
if ($recordId !== false && $recordId > 0) {
$record = $this->dbArray[$this->dbIndexData]->sql("SELECT * FROM $table WHERE id = ?", ROW_EXPECT_1, [$recordId]);
$record = $this->dbArray[$this->dbIndexData]->sql("SELECT * FROM $table WHERE $tableId = ?", ROW_EXPECT_1, [$recordId]);
$this->store->setStore($record, $store, true);
}
}
......@@ -1343,14 +1346,17 @@ class QuickFormQuery {
*
* @return string - the html code
* @throws CodeException
* @throws DbException
* @throws DownloadException
* @throws UserFormException
* @throws UserReportException
*/
private function doInlineReport() {
$uid = $this->t3data[T3DATA_UID];
$icon = Support::wrapTag('<span class="' . GLYPH_ICON . ' ' . GLYPH_ICON_TASKS . '">', '');
$showEditBoxJs = '$("#tt-content-edit-' . $uid . '").toggleClass("hidden")';
$editBtn = Support::wrapTag("<a href='#' onclick='$showEditBoxJs' style='float:right;'>", $icon);
$toggleBtn = Support::wrapTag("<a href='#' onclick='$showEditBoxJs' style='float:right;'>", $icon);
$saveBtnAttributes = Support::doAttribute('class', 'btn btn-default btn-block');
$saveBtnAttributes .= Support::doAttribute('id', "tt-content-save-$uid");
......@@ -1364,7 +1370,10 @@ class QuickFormQuery {
$editBox = join(' ', [$saveBtn, $codeBox]);
$editBox = Support::wrapTag("<div id='tt-content-edit-$uid' class='hidden'>", $editBox);
return $editBtn . $editBox;
// $this->store->setStore(['form' => 'ReportForm', 'r' => $uid], STORE_TYPO3, true);
// $reportForm = $this->doForm(FORM_LOAD);
return $toggleBtn . $editBox;
}
/**
......
......@@ -229,7 +229,7 @@ class Save {
$rc = $this->insertRecord($this->formSpec[F_TABLE_NAME], $newValues);
} else {
$this->updateRecord($this->formSpec[F_TABLE_NAME], $newValues, $recordId);
$this->updateRecord($this->formSpec[F_TABLE_NAME], $newValues, $recordId, $this->formSpec[F_TABLE_ID]);
$rc = $recordId;
}
......@@ -287,13 +287,14 @@ class Save {
* @param string $tableName
* @param array $values
* @param int $recordId
* @param string $tableId
*
* @return bool|int false if $values is empty, else affectedrows
* @throws CodeException
* @throws DbException
* @throws UserFormException
*/
public function updateRecord($tableName, array $values, $recordId) {
public function updateRecord($tableName, array $values, $recordId, $tableId = F_TABLE_ID_DEFAULT) {
if (count($values) === 0)
return 0; // nothing to write, 0 rows affected
......@@ -309,7 +310,7 @@ class Save {
$sql .= '`' . $column . '` = ?, ';
}
$sql = substr($sql, 0, strlen($sql) - 2) . ' WHERE id = ?';
$sql = substr($sql, 0, strlen($sql) - 2) . " WHERE $tableId = ?";
$values[] = $recordId;
$rc = $this->db->sql($sql, ROW_REGULAR, array_values($values));
......@@ -386,7 +387,7 @@ class Save {
// Only used in 'Simple Upload'
if (count($newValues) > 0) {
$this->updateRecord($this->formSpec[F_TABLE_NAME], $newValues, $recordId);
$this->updateRecord($this->formSpec[F_TABLE_NAME], $newValues, $recordId, $this->formSpec[F_TABLE_ID]);
}
}
......
......@@ -152,26 +152,25 @@ class Dirty {
$formDirtyMode = $tableVars[F_DIRTY_MODE];
$rcMd5 = '';
// Check for changed record. Compute $rcMd5
$flagModified = $this->isRecordModified($tableName, $recordId, $recordHashMd5, $rcMd5);
if (($recordHashMd5 != '') && $flagModified) {
return [API_STATUS => API_ANSWER_STATUS_CONFLICT, API_MESSAGE => 'The record has been modified in the meantime. Please reload the form, edit and save again.'];
}
$feUser = $this->session->get(SESSION_FE_USER);
if ($formDirtyMode == DIRTY_MODE_NONE) {
$answer = [API_STATUS => 'success', API_MESSAGE => ''];
} else {
// Check for changed record. Compute $rcMd5
$flagModified = $this->isRecordModified($tableName, $recordId, $recordHashMd5, $rcMd5);
if (($recordHashMd5 != '') && $flagModified) {
return [API_STATUS => API_ANSWER_STATUS_CONFLICT, API_MESSAGE => 'The record has been modified in the meantime. Please reload the form, edit and save again.'];
}
// Look for already existing dirty record.
$recordDirty = $this->getRecordDirty($tableName, $recordId);
// Look for already existing dirty record.
$recordDirty = $this->getRecordDirty($tableName, $recordId);
if (count($recordDirty) == 0) {
if ($formDirtyMode == DIRTY_MODE_NONE) {
$answer = [API_STATUS => 'success', API_MESSAGE => ''];
} else {
if (count($recordDirty) == 0) {
// No dirty record found.
$feUser = $this->session->get(SESSION_FE_USER);
$answer = $this->writeDirty($this->client[SIP_SIP], $recordId, $tableVars, $feUser, $rcMd5);
} else {
$answer = $this->conflict($recordDirty, $formDirtyMode);
}
} else {
$answer = $this->conflict($recordDirty, $formDirtyMode);
}
return $answer;
......@@ -277,17 +276,18 @@ class Dirty {
* @param string $tableName
* @param int $recordId
* @param string $recordHashMd5 - timestamp e.g. '2017-07-27 14:06:56'
*
* @param $rcMd5
* @param string $tableId
*
* @return bool true if $recordHashMd5 is different from current record md5 hash.
*/
private function isRecordModified($tableName, $recordId, $recordHashMd5, &$rcMd5) {
private function isRecordModified($tableName, $recordId, $recordHashMd5, &$rcMd5, $tableId = F_TABLE_ID_DEFAULT) {
if ($recordHashMd5 == '') {
return false; // If there is no recordHashMd5, the check is not possible. Always return 'not modified' (=ok)
}
$record = $this->dbArray[$this->dbIndexData]->sql("SELECT * FROM $tableName WHERE id=?", ROW_EXPECT_1, [$recordId], "Record to lock not found.");
$record = $this->dbArray[$this->dbIndexData]->sql("SELECT * FROM $tableName WHERE $tableId=?", ROW_EXPECT_1, [$recordId], "Record to lock not found.");
$rcMd5 = OnArray::getMd5($record);
......@@ -359,8 +359,9 @@ class Dirty {
$answer = [API_STATUS => API_ANSWER_STATUS_SUCCESS, API_MESSAGE => ''];
if ($recordId == 0) {
return $answer; // New records never have a recordDirty nor a conflict.
if ($recordId == 0 || // New records never have a recordDirty nor a conflict.
$dirtyMode == DIRTY_MODE_NONE) { // mode none -> no lock checking
return $answer;
}
// Check if the record has changed in the meantime.
......@@ -371,13 +372,9 @@ class Dirty {
$lockStatus = $this->getCheckDirty($tableName, $recordId, $rcRecordDirty, $rcMsg);
if (empty($rcRecordDirty)) {
if ($dirtyMode == DIRTY_MODE_NONE) {
return $answer; // only situation where it's ok that there is no dirtyRecord.
}
if ($formMode == FORM_DELETE) {
return $answer;
}
// This is pessimistic, but secure.
// throw new UserFormException("Missing record lock: please reload the form, edit and save again.", ERROR_DIRTY_MISSING_LOCK);
......
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