Commit 4000736f authored by Carsten  Rose's avatar Carsten Rose
Browse files

AdministratorManual/Index.rst: added note to install mysqlnd Driver.

UsersManual/Index.rst: added Form.showButton
Support: added findInSet()
AbstractBuildForm: added createDeleteUrl(), prepareSubrecord(), getFormTable(). Rewrote buildSubrecord(): added 'delete' link, rearranged 'new' link. 'ShowDebugInfo' enhanced.
BuildFormBootstrap: rewrote BuildButton() to switch New/Delete Button on or off. Show debugInfo as tooltip.
Constants: New Subrecord contants.
formEditor.sql: added Form.showButton. Adjusted records
parent 4cfe7b62
...@@ -116,3 +116,14 @@ Page loaded: www.example.com?index.php&id=start&s=badcaffee1234&type=2&L=3, with ...@@ -116,3 +116,14 @@ Page loaded: www.example.com?index.php&id=start&s=badcaffee1234&type=2&L=3, with
* $_SESSION[$urlparam] => <sip> >> $_SESSION['form=Person&r=1'] => 'badcaffee1234' * $_SESSION[$urlparam] => <sip> >> $_SESSION['form=Person&r=1'] => 'badcaffee1234'
FormElement
===========
Checkbox
--------
<div class="checkbox">
<label>
<input type="checkbox">label 1
</label>
</div>
\ No newline at end of file
...@@ -96,8 +96,9 @@ abstract class AbstractBuildForm { ...@@ -96,8 +96,9 @@ abstract class AbstractBuildForm {
'pill' => 'Pill' 'pill' => 'Pill'
]; ];
$this->symbol['edit'] = "<span class='glyphicon glyphicon-pencil'></span>"; $this->symbol[SYMBOL_EDIT] = "<span class='glyphicon glyphicon-pencil'></span>";
$this->symbol['new'] = "<span class='glyphicon glyphicon-plus'></span>"; $this->symbol[SYMBOL_NEW] = "<span class='glyphicon glyphicon-plus'></span>";
$this->symbol[SYMBOL_DELETE] = "<span class='glyphicon glyphicon-trash'></span>";
$this->inputCheckPattern = OnArray::inputCheckPatternArray(); $this->inputCheckPattern = OnArray::inputCheckPatternArray();
} }
...@@ -233,8 +234,6 @@ abstract class AbstractBuildForm { ...@@ -233,8 +234,6 @@ abstract class AbstractBuildForm {
*/ */
public function getFormTagAtrributes() { public function getFormTagAtrributes() {
//TODO: ttcontent id eintragen
// $attribute['id'] = $this->store->getVar(STORE_TYPO3,'1234');
$attribute['id'] = $this->getFormId(); $attribute['id'] = $this->getFormId();
$attribute['method'] = 'post'; $attribute['method'] = 'post';
$attribute['action'] = $this->getActionUrl(); $attribute['action'] = $this->getActionUrl();
...@@ -308,14 +307,14 @@ abstract class AbstractBuildForm { ...@@ -308,14 +307,14 @@ abstract class AbstractBuildForm {
// Iterate over all FormElements // Iterate over all FormElements
foreach ($this->feSpecNative as $fe) { foreach ($this->feSpecNative as $fe) {
$debugStack = array();
if (($filter === FORM_ELEMENTS_NATIVE && $fe['type'] === 'subrecord') || if (($filter === FORM_ELEMENTS_NATIVE && $fe['type'] === 'subrecord') ||
($filter === FORM_ELEMENTS_SUBRECORD && $fe['type'] !== 'subrecord') ($filter === FORM_ELEMENTS_SUBRECORD && $fe['type'] !== 'subrecord')
) { ) {
continue; // skip this FE continue; // skip this FE
} }
$debugStack = array();
// Log / Debug // Log / Debug
$this->store->setVar(SYSTEM_FORM_ELEMENT, $fe['name'] . ' / ' . $fe['id'], STORE_SYSTEM); $this->store->setVar(SYSTEM_FORM_ELEMENT, $fe['name'] . ' / ' . $fe['id'], STORE_SYSTEM);
...@@ -355,25 +354,6 @@ abstract class AbstractBuildForm { ...@@ -355,25 +354,6 @@ abstract class AbstractBuildForm {
abstract public function doSubrecords(); abstract public function doSubrecords();
/**
* Create a link (incl. SIP) to delete the current record.
*
* @return string String: "API_DIR/delete.php?sip=...."
*/
public function createDeleteUrl($table, $recordId) {
$queryStringArray = [
SIP_TABLE => $table,
SIP_RECORD_ID => $recordId
];
$queryString = Support::arrayToQueryString($queryStringArray);
$sip = $this->store->getSipInstance();
return $sip->queryStringToSip($queryString, RETURN_URL, API_DIR . '/delete.php');
}
abstract public function buildRowNative($formElement, $elementHtml); abstract public function buildRowNative($formElement, $elementHtml);
abstract public function buildRowPill($formElement, $elementHtml); abstract public function buildRowPill($formElement, $elementHtml);
...@@ -997,12 +977,83 @@ abstract class AbstractBuildForm { ...@@ -997,12 +977,83 @@ abstract class AbstractBuildForm {
* @throws UserException * @throws UserException
*/ */
public function buildSubrecord(array $formElement, $htmlFormElementId, $value) { public function buildSubrecord(array $formElement, $htmlFormElementId, $value) {
$html = ''; $rcText = false;
$nameColumnId = 'id';
$targetTableName = '';
$flagNew = false;
$flagEdit = false;
$flagDelete = false;
$toolTipDelete = '';
$linkNew = '';
$showDebugInfo = false;
$primaryRecord = $this->store->getStore(STORE_RECORD); $primaryRecord = $this->store->getStore(STORE_RECORD);
if (!$this->prepareSubrecod($formElement, $primaryRecord, $rcText, $nameColumnId)) {
return $rcText;
}
if (isset($formElement[SUBRECORD_PARAMETER_FORM])) {
$showDebugInfo = $this->store->getVar(SYSTEM_SHOW_DEBUG_INFO, STORE_SYSTEM);
$linkNew = Support::wrapTag('<th>', $this->createFormLink($formElement, 0, $primaryRecord, $this->symbol[SYMBOL_NEW], 'New', $showDebugInfo));
// Decode settings in subrecordOption
$flagNew = Support::findInSet(SUBRECORD_NEW, $formElement['subrecordOption']);
$flagEdit = Support::findInSet(SUBRECORD_EDIT, $formElement['subrecordOption']);
if ($flagDelete = Support::findInSet(SUBRECORD_DELETE, $formElement['subrecordOption'])) {
$targetTableName = $this->getFormTable($formElement[SUBRECORD_PARAMETER_FORM]);
}
}
// construct column attributes
$control = $this->getSubrecordColumnControl(array_keys($formElement['sql1'][0]));
// Subrecord: Column titles
$columns = $linkNew;
$columns .= '<th>' . implode('</th><th>', $control['title']) . '</th>';
if ($flagDelete)
$columns .= '<th></th>';
$html = Support::wrapTag('<tr>', $columns);
foreach ($formElement['sql1'] as $row) {
$rowHtml = '';
if ($flagEdit) {
$rowHtml .= Support::wrapTag('<td>', $this->createFormLink($formElement, $row[$nameColumnId], $primaryRecord, $this->symbol[SYMBOL_EDIT], 'Edit', $showDebugInfo));
} elseif ($flagNew) {
$rowHtml .= Support::wrapTag('<td>', $rowHtml, false);
}
// All columns
foreach ($row as $columnName => $value) {
$rowHtml .= Support::wrapTag('<td>', $this->renderCell($control, $columnName, $value));
}
if ($flagDelete) {
$rowHtml .= Support::wrapTag('<td>', $this->createDeleteLink($targetTableName, $row['id'], $this->symbol[SYMBOL_DELETE], 'Delete', $showDebugInfo));
}
$html .= Support::wrapTag('<tr>', $rowHtml, true);
}
return Support::wrapTag('<table class="table">', $html, true);
}
/**
* @param $formElement
* @param $primaryRecord
* @param $rcText
* @param $nameColumnId
* @return bool
* @throws \qfq\UserException
*/
private function prepareSubrecod(array $formElement, array $primaryRecord, &$rcText, &$nameColumnId) {
if (!isset($primaryRecord['id'])) { if (!isset($primaryRecord['id'])) {
return 'Please save main record fist.'; $rcText = 'Please save record fist.';
return false;
} }
if (!is_array($formElement['sql1'])) { if (!is_array($formElement['sql1'])) {
...@@ -1011,10 +1062,10 @@ abstract class AbstractBuildForm { ...@@ -1011,10 +1062,10 @@ abstract class AbstractBuildForm {
// No records? // No records?
if (count($formElement['sql1']) == 0) { if (count($formElement['sql1']) == 0) {
return ''; $rcText = '';
return false;
} }
$nameColumnId = 'id';
if (!isset($formElement['sql1'][0][$nameColumnId])) if (!isset($formElement['sql1'][0][$nameColumnId]))
$nameColumnId = '_id'; $nameColumnId = '_id';
...@@ -1022,31 +1073,85 @@ abstract class AbstractBuildForm { ...@@ -1022,31 +1073,85 @@ abstract class AbstractBuildForm {
throw new UserException('Missing column \'id\' (or "@_id") in \'sql1\' Query', ERROR_DB_MISSING_COLUMN_ID); throw new UserException('Missing column \'id\' (or "@_id") in \'sql1\' Query', ERROR_DB_MISSING_COLUMN_ID);
} }
// construct column attributes return true;
$control = $this->getSubrecordColumnControl(array_keys($formElement['sql1'][0])); }
// $html .= '<b>' . $formElement['label'] . '</b>'; /**
// $html .= '<table border="1">'; * Renders an Link with a symbol (edit/new) and register a new SIP to grant permission to the link..
*
* Returns <a href="<Link>">[icon]</a>
*
* Link: <page>?s=<SIP>&<standard typo3 params>
* SIP: form = $formElement['form'] (provided via formElement['parameter'])
* r = $targetRecordId
* Parse $formElement['detail'] with possible key/value pairs. E.g.: detail=id:gr_id,#{{a}}:p_id,#12:x_id
* gr_id = <<primarytable.id>>
* p_id = <<variable defined in SIP or Client>>
* x_id = 12 (constant)
*
*
* @param $formElement
* @param $targetRecordId
* @param $record
* @return string
* @throws UserException
*/
private function createFormLink(array $formElement, $targetRecordId, array $record, $symbol, $toolTip, $showDebugInfo = false) {
$linkNew = $this->createFormLink($formElement, 0, $primaryRecord, $this->symbol[SYMBOL_NEW], 'New'); $queryStringArray = [
$html .= '<p>' . $linkNew . '</p>'; SIP_FORM => $formElement[SUBRECORD_PARAMETER_FORM],
SIP_RECORD_ID => $targetRecordId
];
$html .= '<table class="table">'; // Add custom query parameter
$html .= '<tr><th></th><th>' . implode('</th><th>', $control['title']) . '</th></tr>'; if (isset($formElement[SUBRECORD_PARAMETER_DETAIL])) {
$detailParam = KeyValueStringParser::parse($formElement[SUBRECORD_PARAMETER_DETAIL]);
foreach ($detailParam as $src => $dest) {
// Constants
if ($src[0] == '#') {
$queryStringArray[$dest] = substr($src, 1);
continue;
}
// Form record values or parameter
if (isset($record[$src])) {
$queryStringArray[$dest] = $record[$src];
}
}
}
foreach ($formElement['sql1'] as $row) { if ($showDebugInfo)
$toolTip .= PHP_EOL . OnArray::toString($queryStringArray, ' = ', PHP_EOL, "'");
$html .= '<tr>'; Support::appendTypo3ParameterToArray($queryStringArray);
$html .= '<td>' . $this->createFormLink($formElement, $row[$nameColumnId], $primaryRecord, $this->symbol[SYMBOL_EDIT], 'Edit') . '</td>'; // If there is a specific targetpage defined, take it.
if (isset($formElement[SUBRECORD_PARAMETER_PAGE]) && $formElement[SUBRECORD_PARAMETER_PAGE] !== '') {
$queryStringArray['id'] = $formElement[SUBRECORD_PARAMETER_PAGE];
}
foreach ($row as $columnName => $value) { //-----------------
$html .= '<td>' . $this->renderCell($control, $columnName, $value) . '</td>'; $queryString = Support::arrayToQueryString($queryStringArray);
$sip = $this->store->getSipInstance();
$url = $sip->queryStringToSip($queryString);
return Support::wrapTag('<a href="' . $url . '" title="' . $toolTip . '">', $symbol);
} }
$html .= '</tr>';
/**
* Get the name for the given form $formName. If not found, return ''.
*
* @param $formName
* @return string tableName for $formName
* @throws CodeException
* @throws DbException
*/
private function getFormTable($formName) {
$row = $this->db->sql("SELECT tableName FROM Form AS f WHERE f.name = ?", ROW_EXPECT_0_1, [$formName]);
if (isset($row['tableName'])) {
return $row['tableName'];
} }
$html .= '</table>';
return $html; return '';
} }
/** /**
...@@ -1110,64 +1215,6 @@ abstract class AbstractBuildForm { ...@@ -1110,64 +1215,6 @@ abstract class AbstractBuildForm {
return $control; return $control;
} }
/**
* Renders an Link with a symbol (edit) and register a new SIP to grant permission to the link..
*
* Returns <a href="<Link>">[icon]</a>
*
* Link: <page>?s=<SIP>&<standard typo3 params>
* SIP: form = $formElement['form'] (provided via formElement['parameter'])
* r = $targetRecordId
* Parse $formElement['detail'] with possible key/value pairs. E.g.: detail=id:gr_id,#{{a}}:p_id,#12:x_id
* gr_id = <<primarytable.id>>
* p_id = <<variable defined in SIP or Client>>
* x_id = 12 (constant)
*
*
* @param $formElement
* @param $targetRecordId
* @param $record
* @return string
* @throws UserException
*/
private function createFormLink(array $formElement, $targetRecordId, array $record, $symbol, $linkTitle) {
$queryStringArray = [
'form' => $formElement['form'],
'r' => $targetRecordId
];
// Add custom query parameter
if (isset($formElement['detail'])) {
$detailParam = KeyValueStringParser::parse($formElement['detail']);
foreach ($detailParam as $src => $dest) {
// Constants
if ($src[0] == '#') {
$queryStringArray[$dest] = substr($src, 1);
continue;
}
// Form record values or parameter
if (isset($record[$src])) {
$queryStringArray[$dest] = $record[$src];
}
}
}
Support::appendTypo3ParameterToArray($queryStringArray);
// If there is a specific targetpage defined, take it.
if (isset($formElement['page']) && $formElement['page'] !== '') {
$queryStringArray['id'] = $formElement['page'];
}
//-----------------
$queryString = Support::arrayToQueryString($queryStringArray);
$sip = $this->store->getSipInstance();
$url = $sip->queryStringToSip($queryString);
return "<a href='$url' title='$linkTitle'>$symbol</a>";
}
/** /**
* Renders $value as specified in array $control * Renders $value as specified in array $control
* *
...@@ -1209,6 +1256,44 @@ abstract class AbstractBuildForm { ...@@ -1209,6 +1256,44 @@ abstract class AbstractBuildForm {
return $cell; return $cell;
} }
/**
* @param $table
* @param $recordId
* @param $symbol
* @param $toolTip
* @return string
*/
private function createDeleteLink($table, $recordId, $symbol, $toolTip, $showDebugInfo = false) {
if ($showDebugInfo) {
$toolTip .= PHP_EOL . "table = '$table'" . PHP_EOL . "id = '$recordId'";
}
$url = $this->createDeleteUrl($table, $recordId);
return Support::wrapTag('<a href="' . $url . '" title="' . $toolTip . '">', $symbol);
}
/**
* Create a link (incl. SIP) to delete the current record.
*
* @return string String: "API_DIR/delete.php?sip=...."
*/
public function createDeleteUrl($table, $recordId) {
$queryStringArray = [
SIP_TABLE => $table,
SIP_RECORD_ID => $recordId
];
$queryString = Support::arrayToQueryString($queryStringArray);
$sip = $this->store->getSipInstance();
return $sip->queryStringToSip($queryString, RETURN_URL, API_DIR . '/delete.php');
}
/** /**
* Builds an Upload (File) Button. * Builds an Upload (File) Button.
* *
......
...@@ -181,37 +181,59 @@ class BuildFormBootstrap extends AbstractBuildForm { ...@@ -181,37 +181,59 @@ class BuildFormBootstrap extends AbstractBuildForm {
* @return string * @return string
*/ */
private function buildButtons() { private function buildButtons() {
$toolTipNew = 'New';
$toolTipDelete = 'Delete';
$buttonDelete = '';
$buttonNew = '';
if ($this->store->getVar(SYSTEM_SHOW_DEBUG_INFO, STORE_SYSTEM) === 'yes') {
$toolTipNew .= PHP_EOL . "form = '" . $this->formSpec['name'] . "'" . PHP_EOL . "r = 0";
$toolTipDelete .= PHP_EOL . "table = '" . $this->formSpec['tableName'] . "'" . PHP_EOL . "r = '" . $this->store->getVar(SIP_RECORD_ID, STORE_SIP) . "'";
}
$sipParamString = OnArray::toString($this->store->getStore(STORE_SIP), ' = ', PHP_EOL, "'"); $sipParamString = OnArray::toString($this->store->getStore(STORE_SIP), ' = ', PHP_EOL, "'");
$formEditUrl = $this->createFormEditUrl(); $formEditUrl = $this->createFormEditUrl();
$debugButtons = <<<BUTTONS $buttonDebug = <<<BUTTON
<div class="btn-group" role="group"> <div class="btn-group" role="group">
<button id="debug-button" type="button" class="btn btn-default navbar-btn" title="$sipParamString"><span class="glyphicon glyphicon-eye-open"></span></button> <button id="debug-button" type="button" class="btn btn-default navbar-btn" title="$sipParamString"><span class="glyphicon glyphicon-eye-open"></span></button>
<a href="$formEditUrl" id="form-edit-button" class="btn btn-default navbar-btn" title="Edit form"><span class="glyphicon glyphicon-wrench"></span></a> <a href="$formEditUrl" id="form-edit-button" class="btn btn-default navbar-btn" title="Edit form"><span class="glyphicon glyphicon-wrench"></span></a>
</div> </div>
BUTTONS; BUTTON;
$formEditButton = ($this->store->getVar(SYSTEM_SHOW_DEBUG_INFO, STORE_SYSTEM) === 'yes') ? $debugButtons : ''; if (Support::findInSet(FORM_BUTTON_DELETE, $this->formSpec['showButton'])) {
$buttonDelete = <<<BUTTON
<div class="btn-group" role="group">
<button id="delete-button" type="button" class="btn btn-default navbar-btn" title="$toolTipDelete"><span class="glyphicon glyphicon-trash"></span></button>
</div>
BUTTON;
}
if (Support::findInSet(FORM_BUTTON_NEW, $this->formSpec['showButton'])) {
$buttonNew = <<<BUTTON
<div class="btn-group" role="group">
<button id="delete-button" type="button" class="btn btn-default navbar-btn" title="$toolTipNew"><span class="glyphicon glyphicon-plus"></span></button>
</div>
BUTTON;
}
$html = <<<BUTTONS $buttonFormEdit = ($this->store->getVar(SYSTEM_SHOW_DEBUG_INFO, STORE_SYSTEM) === 'yes') ? $buttonDebug : '';
$html = <<<BUTTON
<div class="col-md-3 "> <div class="col-md-3 ">
<div class="btn-toolbar pull-right" role="toolbar"> <div class="btn-toolbar pull-right" role="toolbar">
$formEditButton $buttonFormEdit
<div class="btn-group" role="group"> <div class="btn-group" role="group">
<button id="save-button" type="button" class="btn btn-default navbar-btn" title="Save"><span class="glyphicon glyphicon-ok"></span></button> <button id="save-button" type="button" class="btn btn-default navbar-btn" title="Save"><span class="glyphicon glyphicon-ok"></span></button>
<button id="close-button" type="button" class="btn btn-default navbar-btn" title="Close"><span class="glyphicon glyphicon-remove"></span></button> <button id="close-button" type="button" class="btn btn-default navbar-btn" title="Close"><span class="glyphicon glyphicon-remove"></span></button>
</div> </div>
<div class="btn-group" role="group"> $buttonDelete
<button id="delete-button" type="button" class="btn btn-default navbar-btn" title="Delete"><span class="glyphicon glyphicon-trash"></span></button> $buttonNew
</div>
<div class="btn-group" role="group">
<button id="new-button" type="button" class="btn btn-default navbar-btn" title="New"><span class="glyphicon glyphicon-plus"></span></button>
</div>
</div> </div>
</div> </div>
BUTTONS; BUTTON;
return $html; return $html;
} }
...@@ -332,6 +354,4 @@ EOF; ...@@ -332,6 +354,4 @@ EOF;
return $html; return $html;
} }
} }
\ No newline at end of file
...@@ -10,7 +10,7 @@ const EXT_KEY = 'qfq'; ...@@ -10,7 +10,7 @@ const EXT_KEY = 'qfq';
const CONFIG_INI = "config.ini"; // QFQ configuration file: db access const CONFIG_INI = "config.ini"; // QFQ configuration file: db access
const GFX_INFO = 'typo3conf/ext/qfq/Resources/Public/icons/note.gif'; const GFX_INFO = 'typo3conf/ext/qfq/Resources/Public/icons/note.gif';
const API_DIR = 'typo3conf/ext/qfq/qfq/api/'; const API_DIR = 'typo3conf/ext/qfq/qfq/api';
const QFQ_LOG = 'qfq.log'; const QFQ_LOG = 'qfq.log';
...@@ -23,6 +23,8 @@ const FORM_PERMISSION_LOGGED_IN = 'logged_id'; ...@@ -23,6 +23,8 @@ const FORM_PERMISSION_LOGGED_IN = 'logged_id';
const FORM_PERMISSION_LOGGED_OUT = 'logged_out'; const FORM_PERMISSION_LOGGED_OUT = 'logged_out';
const FORM_PERMISSION_ALWAYS = 'always'; const FORM_PERMISSION_ALWAYS = 'always';
const FORM_PERMISSION_NEVER = 'never'; const FORM_PERMISSION_NEVER = 'never';
const FORM_BUTTON_NEW = 'new';
const FORM_BUTTON_DELETE = 'delete';
const FORM_FORWARD_MODE_NO = 'no'; const FORM_FORWARD_MODE_NO = 'no';
const FORM_FORWARD_MODE_AUTO = 'auto'; const FORM_FORWARD_MODE_AUTO = 'auto';
...@@ -66,12 +68,6 @@ const ROW_KEYS = "keys"; ...@@ -66,12 +68,6 @@ const ROW_KEYS = "keys";
const KVP_IF_VALUE_EMPTY_COPY_KEY = 'if_value_empty_copy_key'; const KVP_IF_VALUE_EMPTY_COPY_KEY = 'if_value_empty_copy_key';
const KVP_VALUE_GIVEN = 'value_given'; const KVP_VALUE_GIVEN = 'value_given';
// BuildForm
const SUBRECORD_COLUMN_WIDTH = 20;
const FORM_ELEMENTS_NATIVE = 'native';
const FORM_ELEMENTS_SUBRECORD = 'subrecord';
const FORM_ELEMENTS_NATIVE_SUBRECORD = 'native_subrecord';
// QFQ Error Codes // QFQ Error Codes
const ERROR_UNKNOW_SANITIZE_CLASS = 1001; const ERROR_UNKNOW_SANITIZE_CLASS = 1001;
...@@ -267,12 +263,24 @@ const API_ANSWER_REDIRECT_CLIENT = 'client'; ...@@ -267,12 +263,24 @@ const API_ANSWER_REDIRECT_CLIENT = 'client';
const API_ANSWER_REDIRECT_NO = 'no'; const API_ANSWER_REDIRECT_NO = 'no';
const API_ANSWER_REDIRECT_URL = 'url'; const API_ANSWER_REDIRECT_URL = 'url';
// FORM // BuildForm
const SYMBOL_NEW = 'new'; const SYMBOL_NEW = 'new';
const SYMBOL_EDIT = 'edit'; const SYMBOL_EDIT = 'edit';
const SYMBOL_DELETE = 'delete';
//CHECKBOX //CHECKBOX
const CHECKBOX_VALUE_CHECKED = 'checked'; const CHECKBOX_VALUE_CHECKED = 'checked';
const