Commit 05e52e3e authored by Carsten  Rose's avatar Carsten Rose
Browse files

Merge branch 'develop' into F10715-puppeteer

parents 9d6d8a26 fca18b4b
......@@ -11,6 +11,7 @@
.project
.webprj
.vscode
.run
nbprojec
nohup.out
......
......@@ -2617,7 +2617,7 @@ record (defined by `multiSql`).
| multiMgsNoRecord | Default: No data | Message shown if `multiSql` selects no records |
+------------------+----------------------------------+------------------------------------------------+
.. note::
.. important::
Multi Form do not use 'record-locking' at all.
......@@ -2626,8 +2626,8 @@ The Form is shown as a HTML table.
* `multiSql`: Selects the records where the defined FormElements will work on each.
* A uniq column 'id' or '_id' (not shown) is mandatory and has to reflect an existing record id in table `primary table`.
* Additional columns, defined in `multiSql`, will be shown on the form in the same line, before the FormElements.
* A uniq column `id` or `_id` (not shown) is mandatory and has to reference an existing record in table `primary table`.
* Additional columns, defined in `multiSql`, will be shown on the form on the same line, before the FormElements.
* Per row, the STORE_PARENT is filled with the current record of the primary table.
The following definition of *Simple* and *Advanced* is just for explanation, there is no *flag* or *mode* which
......@@ -2646,7 +2646,7 @@ FormElement:
* The FormElement.name represents a column of the defined primary table.
* The existing values of such FormElements are automatically loaded.
* No further definition (sqlInsert, sqlUpdate, ...) is required.
* No further definition (`sqlInsert`, `sqlUpdate`, ...) is required.
Advanced
^^^^^^^^
......
......@@ -41,6 +41,7 @@ Installation
The following features are only tested / supported on linux hosts:
* General: QFQ is coded to run on Linux hosts, preferable on Debian derivates like Ubuntu.
* PHP Module: curl
* HTML to PDF conversion - command `wkhtmltopdf`.
* Concatenation of PDF files - command `pdfunite`.
* Convert of images to PDF files - command `img2pdf`.
......@@ -498,7 +499,8 @@ Extension Manager: QFQ Configuration
+-----------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| securityVarsHoneypot | email,username,password | If empty: no check. All named variables will rendered as INPUT elements. |
+-----------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| securityAttackDelay | 5 | If an attack is detected, sleep 'x' seconds and exit PHP process. |
| securityAttackDelay | 5 | If an attack is detected, sleep 'x' seconds and exit PHP process. '-1' |
| | | Reports the attack and returns normally - use this with care. |
+-----------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| securityShowMessage | true | If an attack is detected, show a message. |
+-----------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
......
......@@ -155,7 +155,7 @@ GET Variables provided via URL are available via STORE_CLIENT as usual.
| Attribute | Description |
+===================+==================================================================================+
| restSqlData | Mandatory. SQL query selects content shown in data mode. |
| | | ``restSqlData={{!SELECT id, name, gender FROM Person WHERE id='{{r:T0}}'' }}`` |
| | | ``restSqlData={{!SELECT id, name, gender FROM Person WHERE id='{{r:T0}}' }} `` |
+-------------------+----------------------------------------------------------------------------------+
| restSqlList | Mandatory. SQL query selects content shown in data mode. |
| | | ``restSqlData={{!SELECT id, name FROM Person }}`` |
......
......@@ -707,7 +707,7 @@ Column: _link
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
|x | |Mail |m:<email> |m:info@example.com |Default link class: email |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
|x | |Page |p:<pageId> |p:impressum |Prepend '?' or '?id=', no hostname qualifier (automatically set by browser) |
|x | |Page |p:<pageId> |p:impressum |Prepend '?' or '?id=', no hostname qualifier (automatically set by browser). If omitted, default is current page id. |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
|x | |Download |d:[<exportFilename>] |d:complete.pdf |Link points to `.../typo3conf/ext/qfq/Api/download.php`. Additional parameter SIP encoded. 'Download' needs SIP. See :ref:`download`. |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
......@@ -722,7 +722,7 @@ Column: _link
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
| | |Render |r:<mode> |r:3 |See: :ref:`render-mode`, Default: 0 |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
| | |Button | b[:0|1|<btn class>] | b:0, b:1, b:success |'b', 'b:1': a bootstrap button is created. 'b:0' disable the button. <btn class>: default, primary, success, info, warning,danger |
| | |Button | b[:0|1|<btn class>] | b:0, b:1, b:success |'b', 'b:1': with Bootstrap class 'btn btn-...'. 'b:0' no Bootstrap class. <btn class>: default, primary, success, info, warning,danger |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
| |x |Picture |P:<filename> |P:bullet-red.gif |Picture '<img src="bullet-red.gif"alt="....">'. |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
......@@ -1761,8 +1761,9 @@ REST Client
POST and GET data to external REST interfaces or other API services.
Access to external services via HTTP / HTTPS is triggered via special column name *restClient*. The received data might
be processed in subsequent calls.
Access to external services via HTTP / HTTPS is triggered via special column name *restClient*.
QFQ uses the php stream interface for the API calls. Because of that, allow_url_fopen needs to be set to 1 on the installation.
The received data can be processed in subsequent calls.
Example::
......@@ -1782,6 +1783,9 @@ Example::
+-------------------+----------------------------------------------------+--------------------------------------------------------+
| content | content:{"name":"John";"surname":"Doe"} | Depending on the REST server JSON might be expected |
+-------------------+----------------------------------------------------+--------------------------------------------------------+
| contentFile | contentFile:fileadmin/_temp_/data.txt | Replaces content, if given. Recommended for large data |
| | | sections, such as binary data for files. |
+-------------------+----------------------------------------------------+--------------------------------------------------------+
| header | *see below* | |
+-------------------+----------------------------------------------------+--------------------------------------------------------+
| timeout | timeout:5 | Default: 5 seconds. |
......@@ -1797,13 +1801,19 @@ Example::
* *content-type: text/plain* - if *content* does not start with a ``{``.
* *connection: close* - Necessary for HTTP 1.1.
* Basic Authorization Example
Warning: Only use base64 for SSL encrypted connections::
10.sql = SELECT CONCAT('n:https://sample.com/id/1234|header:Authorization: Basic ', TO_BASE64('{{username}}:{{password}}') )
**Result received**
* After a *REST client* call is fired, QFQ will wait up to *timeout* seconds for the answer.
* By default, the whole received answer will be shown. To suppress the output: ``... AS '_restClient|_hide'``
* The variable ``{{http-status:C}}`` shows the `HTTP status code<https://en.wikipedia.org/wiki/List_of_HTTP_status_codes>`_.
A value starting with '2..' shows success.
* In case of an error, ``{{error-message:C:allbut}}`` shows some details.
* In case of an error, the HTTP status code is set to 0 and ``{{error-message:C:allbut}}`` shows some details.
* In case the returned answer is a valid JSON string, it is flattened and automatically copied to STORE_CLIENT with corresponding key names.
* NOTE: The CLIENT store is emptied beforehand!
......@@ -2925,8 +2935,8 @@ The *tablesorter* options:
* 'Views' can be saved as:
* public: every user will see the `view` and can modify it.
* private: only the user who created the `view` will see/modify it.
* group: every user will see the `view` and can modify it.
* personal: only the user who created the `view` will see/modify it.
* readonly: manually mark a `view` as readonly (no FE User can change it) by setting column `readonly='true'` in table
`Setting` of the corresponding view (identified by `name`).
......
......@@ -217,37 +217,47 @@ Store: *TYPO3* (Bodytext) - T
* Sanitized: *no*
+-------------------------+-------------------------------------------------------------------+----------+
| Name | Explanation | Note |
+=========================+===================================================================+==========+
| form | | Formname defined in ttcontent record bodytext | see note |
| | | * Fix. E.g. *form = person* | |
| | | * via SIP. E.g. *form = {{form:SE}}* | |
+-------------------------+-------------------------------------------------------------------+----------+
| pageId | Record id of current Typo3 page | see note |
+-------------------------+-------------------------------------------------------------------+----------+
| pageAlias | Alias of current Typo3 page. If empty, take pageId. | see note |
+-------------------------+-------------------------------------------------------------------+----------+
| pageTitle | Title of current Typo3 page | see note |
+-------------------------+-------------------------------------------------------------------+----------+
| pageType | Current selected page type (typically URL parameter 'type') | see note |
+-------------------------+-------------------------------------------------------------------+----------+
| pageLanguage | Current selected page language (typically URL parameter 'L') | see note |
+-------------------------+-------------------------------------------------------------------+----------+
| ttcontentUid | Record id of current Typo3 content element | see note |
+-------------------------+-------------------------------------------------------------------+----------+
| feUser | Logged in Typo3 FE User | |
+-------------------------+-------------------------------------------------------------------+----------+
| feUserUid | Logged in Typo3 FE User uid | |
+-------------------------+-------------------------------------------------------------------+----------+
| feUserGroup | FE groups of logged in Typo3 FE User | |
+-------------------------+-------------------------------------------------------------------+----------+
| beUser | Logged in Typo3 BE User | |
+-------------------------+-------------------------------------------------------------------+----------+
| beUserLoggedIn | 'yes' | 'no' - Status if a BE-User is logged in | |
+-------------------------+-------------------------------------------------------------------+----------+
* **note**: not available:
+-------------------------+-------------------------------------------------------------------+-----+
| Name | Explanation | API |
+=========================+===================================================================+=====+
| form | | Formname defined in ttcontent record bodytext | no |
| | | * Fix. E.g. *form = person* | |
| | | * via SIP. E.g. *form = {{form:SE}}* | |
+-------------------------+-------------------------------------------------------------------+-----+
| pageId | Record id of current Typo3 page | no |
+-------------------------+-------------------------------------------------------------------+-----+
| pageAbstract | Abstract of current Typo3 page | no |
+-------------------------+-------------------------------------------------------------------+-----+
| pageAlias | Alias of current Typo3 page. If empty, take pageId. | no |
+-------------------------+-------------------------------------------------------------------+-----+
| pageDescription | Description of current Typo3 page | no |
+-------------------------+-------------------------------------------------------------------+-----+
| pageKeywords | Keywords of current Typo3 page | no |
+-------------------------+-------------------------------------------------------------------+-----+
| pageLanguage | Current selected page language (typically URL parameter 'L') | no |
+-------------------------+-------------------------------------------------------------------+-----+
| pageNavTitle | Alternative navigation title of current Typo3 page | no |
+-------------------------+-------------------------------------------------------------------+-----+
| pageTitle | Title of current Typo3 page | no |
+-------------------------+-------------------------------------------------------------------+-----+
| pageType | Current selected page type (typically URL parameter 'type') | no |
+-------------------------+-------------------------------------------------------------------+-----+
| ttcontentSubheader | Subheader of the current ttcontent record | no |
+-------------------------+-------------------------------------------------------------------+-----+
| ttcontentUid | Record id of current Typo3 content element | no |
+-------------------------+-------------------------------------------------------------------+-----+
| feUser | Logged in Typo3 FE User | yes |
+-------------------------+-------------------------------------------------------------------+-----+
| feUserGroup | FE groups of logged in Typo3 FE User | yes |
+-------------------------+-------------------------------------------------------------------+-----+
| feUserUid | Logged in Typo3 FE User uid | yes |
+-------------------------+-------------------------------------------------------------------+-----+
| beUser | Logged in Typo3 BE User | yes |
+-------------------------+-------------------------------------------------------------------+-----+
| beUserLoggedIn | 'yes' | 'no' - Status if a BE-User is logged in | yes |
+-------------------------+-------------------------------------------------------------------+-----+
* **API**: available:
* in :ref:`dynamic-update` or
* by *FormElement* class 'action' with type 'beforeSave', 'afterSave', 'beforeDelete', 'afterDelete'.
......
......@@ -18,10 +18,10 @@ use IMATHUZH\Qfq\Core\Helper\KeyValueStringParser;
use IMATHUZH\Qfq\Core\Helper\Ldap;
use IMATHUZH\Qfq\Core\Helper\Logger;
use IMATHUZH\Qfq\Core\Helper\OnArray;
use IMATHUZH\Qfq\Core\Helper\OnString;
use IMATHUZH\Qfq\Core\Helper\Path;
use IMATHUZH\Qfq\Core\Helper\Sanitize;
use IMATHUZH\Qfq\Core\Helper\Support;
use IMATHUZH\Qfq\Core\Helper\OnString;
use IMATHUZH\Qfq\Core\Report\Link;
use IMATHUZH\Qfq\Core\Report\Report;
use IMATHUZH\Qfq\Core\Store\Sip;
......@@ -257,7 +257,8 @@ abstract class AbstractBuildForm {
$this->store->setStore($row, STORE_PARENT_RECORD, true);
$this->store->setVar(F_MULTI_COL_ID, $row[$idName], STORE_PARENT_RECORD); // In case '_id' is used, both '_id' and 'id' should be accessible.
$record = $this->dbArray[$this->dbIndexData]->sql('SELECT * FROM `' . $this->formSpec[F_TABLE_NAME] . '` WHERE `id`= ?', ROW_EXPECT_1, [$row[$idName]]);
$record = $this->dbArray[$this->dbIndexData]->sql('SELECT * FROM `' . $this->formSpec[F_TABLE_NAME] . '` WHERE `id`= ?',
ROW_EXPECT_1, [$row[$idName]], 'If you get 0 records: check that the primary table is the one used in multi SQL');
$this->store->setStore($record, STORE_RECORD, true);
$jsonTmp = array();
......@@ -513,12 +514,9 @@ abstract class AbstractBuildForm {
* @throws \UserFormException
*/
public function getFormTag() {
$md5 = '';
$attribute = $this->getFormTagAttributes();
$honeypot = $this->getHoneypotVars();
$md5 = $this->buildInputRecordHashMd5();
return '<form ' . OnArray::toString($attribute, '=', ' ', "'") . '>' . $honeypot . $md5;
......@@ -1346,8 +1344,11 @@ abstract class AbstractBuildForm {
}
if ($formElement[FE_MAX_LENGTH] > 0 && $value !== '') {
// Check if there are \r\n > those should be counted as one char, not two. #13030
$crlf = substr_count($value, "\r\n");
$max = $formElement[FE_MAX_LENGTH] + $crlf;
// crop string only if it's not empty (substr returns false on empty strings)
$value = mb_substr($value, 0, $formElement[FE_MAX_LENGTH]);
$value = mb_substr($value, 0, $max);
}
if ($formElement[FE_HIDE_ZERO] != '0' && $value == '0') {
......@@ -2403,8 +2404,14 @@ abstract class AbstractBuildForm {
}
}
if ($this->showDebugInfoFlag)
// Check if detail contains Typo3 reserved keywords
if(isset($queryStringArray[CLIENT_PAGE_ID]) || isset($queryStringArray[CLIENT_PAGE_TYPE]) ||isset($queryStringArray[CLIENT_PAGE_LANGUAGE])){
throw new \UserFormException("Reserved Typo3 keyword (id, type, L) in formElement.parameter.detail - please use something else.");
}
if ($this->showDebugInfoFlag) {
$toolTip .= PHP_EOL . OnArray::toString($queryStringArray, ' = ', PHP_EOL, "'");
}
Support::appendTypo3ParameterToArray($queryStringArray);
// If there is a specific targetpage defined, take it.
......@@ -2465,7 +2472,7 @@ abstract class AbstractBuildForm {
private function getSubrecordColumnControl(array $titleRaw) {
$control = array();
foreach ($titleRaw AS $columnName) {
foreach ($titleRaw as $columnName) {
switch ($columnName) {
case SUBRECORD_COLUMN_ROW_CLASS:
......
......@@ -42,7 +42,7 @@ 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_IN = 'logged_in';
const FORM_PERMISSION_LOGGED_OUT = 'logged_out';
const FORM_PERMISSION_ALWAYS = 'always';
const FORM_PERMISSION_NEVER = 'never';
......@@ -379,6 +379,7 @@ const ERROR_IMPORT_LIST_SHEET_NAMES = 2901;
const ERROR_FORM_REST = 3000;
const ERROR_REST_AUTHORIZATION = 3001;
const ERROR_REST_INVALID_ID = 3002;
const ERROR_REST_API_CALL = 3010;
// Tablesorter
const ERROR_TABLESORTER_SIP_NOT_FOUND = 3100;
......@@ -464,10 +465,16 @@ const TYPO3_FE_USER = 'feUser';
const TYPO3_FE_USER_UID = 'feUserUid';
const TYPO3_FE_USER_GROUP = 'feUserGroup';
const TYPO3_TT_CONTENT_UID = 'ttcontentUid';
const TYPO3_TT_CONTENT_SUBHEADER = 'ttcontentSubheader';
const TYPO3_PAGE_ID = 'pageId';
const TYPO3_PAGE_ALIAS = 'pageAlias';
const TYPO3_PAGE_TITLE = 'pageTitle';
const TYPO3_PAGE_TYPE = 'pageType';
const TYPO3_PAGE_ABSTRACT = 'pageAbstract';
const TYPO3_PAGE_DESCRIPTION = 'pageDescription';
const TYPO3_PAGE_KEYWORDS= 'pageKeywords';
const TYPO3_PAGE_NAV_TITLE = 'pageNavTitle';
const TYPO3_PAGE_LANGUAGE = 'pageLanguage';
const TYPO3_DEBUG_SHOW_BODY_TEXT = 'debugShowBodyText';
......@@ -1405,7 +1412,7 @@ const HTML_INPUT_TYPE_NUMBER = 'number';
const SHEBANG_REPORT = '#!report';
CONST TOKEN_COMMENT = '#';
const TOKEN_COMMENT = '#';
// SUPPORT
const PARAM_T3_ALL = 't3 all';
......@@ -1479,6 +1486,11 @@ const INDEX_PHP = 'index.php';
const T3DATA_BODYTEXT = 'bodytext';
const T3DATA_BODYTEXT_RAW = 'bodytext-raw';
const T3DATA_UID = 'uid';
const T3DATA_SUBHEADER = 'subheader';
const T3DATA_DESCRIPTION = 'description';
const T3DATA_ABSTRACT = 'abstract';
const T3DATA_NAV_TITLE = 'nav_title';
const T3DATA_KEYWORDS = 'keywords';
const T3DATA_PID = 'pid';
const T3DATA_HEADER = 'header';
const T3DATA_REPORT_PATH_FILENAME = 'reportPathFileName';
......@@ -1857,6 +1869,7 @@ const TOKEN_L_HTML_ID = 'htmlId';
const TOKEN_L_METHOD = 'method';
const TOKEN_L_HEADER = 'header';
const TOKEN_L_CONTENT = 'content';
const TOKEN_L_CONTENT_FILE = 'contentFile';
const TOKEN_L_TIMEOUT = 'timeout';
const TOKEN_L_SSL = 'ssl';
......
......@@ -14,6 +14,7 @@ use IMATHUZH\Qfq\Core\Helper\HelperFile;
use IMATHUZH\Qfq\Core\Helper\HelperFormElement;
use IMATHUZH\Qfq\Core\Helper\Logger;
use IMATHUZH\Qfq\Core\Helper\OnArray;
use IMATHUZH\Qfq\Core\Helper\OnString;
use IMATHUZH\Qfq\Core\Helper\Path;
use IMATHUZH\Qfq\Core\Helper\SqlQuery;
use IMATHUZH\Qfq\Core\Store\Store;
......@@ -433,6 +434,7 @@ class Database {
$command = 'FAILED';
}
$command = OnString::removeLeadingBrace($command);
switch ($command) {
case 'SELECT':
case 'SHOW':
......
......@@ -17,7 +17,6 @@ use IMATHUZH\Qfq\Core\Report\Link;
use IMATHUZH\Qfq\Core\Report\Tablesorter;
use IMATHUZH\Qfq\Core\Store\Sip;
use IMATHUZH\Qfq\Core\Store\Store;
use IMATHUZH\Qfq\Core\Typo3\T3Handler;
const EVALUATE_DB_INDEX_DEFAULT = 0;
......@@ -340,14 +339,19 @@ class Evaluate {
return '';
}
// Get SQL column / row separated
if ($token[0] === '!') {
$token = trim(substr($token, 1));
$sqlMode = ROW_REGULAR;
}
// In case there is a statement starting with '(' (multiple): remove them just to detect if the following is a SQL statement.
// E.g. original: "{{[1] ! ( SELECT name FROM person ORDER BY name UNION SELECT 'new'}}"
$tokenClean = OnString::removeLeadingBrace($token);
// Extract token: check if this is a 'variable', 'SQL Statement', 'link', 'data-dnd-api'
$arrToken = explode(' ', $token);
$arrToken = explode(' ', $tokenClean);
// Variable Type 'SQL Statement'
if (in_array(strtoupper($arrToken[VAR_INDEX_VALUE] . ' '), $this->sqlKeywords)) {
......@@ -356,7 +360,6 @@ class Evaluate {
return $this->dbArray[$dbIndex]->sql($token, $sqlMode);
}
// Variable Type '... AS _link', '... as data-dnd-api', '... AS _tablesorter-view-saver'
$countToken = count($arrToken);
if ($countToken > 2 && strtolower($arrToken[$countToken - 2]) == 'as') {
......
......@@ -645,5 +645,29 @@ class OnString {
return $new;
}
/**
* Checks for any leading braces in $data. Spaces will be ignored.
*
* 'SELE..': returns $data unchanged
* ' ( SELECT...': returns 'SELECT...'
* ' ( (SELECT...': returns 'SELECT...'
*
* @param $data
* @return string
*/
public static function removeLeadingBrace($data) {
$trimmed = false;
$value = trim($data);
while ($value != '' && $value[0] == '(') {
$trimmed = true;
$value = trim(substr($value, 1));
}
if ($trimmed) {
$data = $value;
}
return $value;
}
}
......@@ -37,19 +37,19 @@ class Support {
self::$store = Store::getInstance();
if ($mode === PARAM_T3_ALL) {
$queryArray['id'] = self::$store->getVar(TYPO3_PAGE_ID, STORE_TYPO3);
$queryArray[CLIENT_PAGE_ID] = self::$store->getVar(TYPO3_PAGE_ID, STORE_TYPO3);
}
// TYPE
$tmp = self::$store->getVar(TYPO3_PAGE_TYPE, STORE_TYPO3);
if ($tmp !== false && $tmp != 0) {
$queryArray['type'] = $tmp;
$queryArray[CLIENT_PAGE_TYPE] = $tmp;
}
// Language
$tmp = self::$store->getVar(TYPO3_PAGE_LANGUAGE, STORE_TYPO3);
if ($tmp !== false && $tmp != 0) {
$queryArray['L'] = $tmp;
$queryArray[CLIENT_PAGE_LANGUAGE] = $tmp;
}
}
......@@ -84,11 +84,11 @@ class Support {
$type = self::$store->getVar(TYPO3_PAGE_TYPE, STORE_TYPO3);
$language = self::$store->getVar(TYPO3_PAGE_LANGUAGE, STORE_TYPO3);
if ($type != 0 && $type !== false && !isset($arr['type'])) {
if ($type != 0 && $type !== false && !isset($arr[CLIENT_PAGE_TYPE])) {
$uri .= '&type=' . $type;
}
if ($language != 0 && $language !== false && !isset($arr['L'])) {
if ($language != 0 && $language !== false && !isset($arr[CLIENT_PAGE_LANGUAGE])) {
$uri .= '&L=' . $language;
}
......@@ -455,7 +455,6 @@ class Support {
break;
default:
throw new \UserFormException('Date/time format not recognised.', ERROR_DATE_TIME_FORMAT_NOT_RECOGNISED);
break;
}
}
......@@ -537,7 +536,6 @@ class Support {
case '00.00.0000':
case '00:00:00':
return (self::dateTimeZero($dateFormat, $showZero, $showTime, $showSeconds));
break;
default:
break;
......
......@@ -48,16 +48,19 @@ use IMATHUZH\Qfq\Core\Store\Store;
*/
class QuickFormQuery {
/**
* @var Store instantiated class
*/
protected $store = null;
private $dbIndexData = false;
private $dbIndexQfq = false;
/**
* @var Database[] - Array of Database instantiated class
*/
protected $dbArray = array();
/**
* @var Store instantiated class
*/
protected $store = null;
/**
* @var Evaluate instantiated class
*/
......@@ -88,9 +91,6 @@ class QuickFormQuery {
*/
private $session = null;
private $dbIndexData = false;
private $dbIndexQfq = false;
/*
* TODO:
* Preparation: setup logging, database access, record locking
......@@ -173,6 +173,8 @@ class QuickFormQuery {
}
$this->store->setVar(TYPO3_TT_CONTENT_UID, $t3data[T3DATA_UID], STORE_TYPO3);
$this->store->setVar(TYPO3_TT_CONTENT_SUBHEADER, $t3data[T3DATA_SUBHEADER], STORE_TYPO3);
$this->dbIndexData = $this->store->getVar(SYSTEM_DB_INDEX_DATA, STORE_SYSTEM);
$this->dbIndexQfq = $this->store->getVar(SYSTEM_DB_INDEX_QFQ, STORE_SYSTEM);
......@@ -266,7 +268,8 @@ class QuickFormQuery {
* @throws \UserFormException
* @throws \UserReportException
*/
public function process() {
public function process(): string
{
$html = '';
$render = $this->store->getVar(SYSTEM_RENDER, STORE_TYPO3 . STORE_SYSTEM);
......@@ -544,6 +547,7 @@ class QuickFormQuery {
// Build FORM
$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);
......@@ -571,36 +575,12 @@ class QuickFormQuery {
$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);
$formAction->elements($recordId, $this->feSpecAction, $feTypeList);
// If an old record exist: load it. Necessary to delete uploaded files which should be overwritten.
$this->store->fillStoreWithRecord($this->formSpec[F_TABLE_NAME], $recordId,
$this->dbArray[$this->dbIndexData], $this->formSpec[F_PRIMARY_KEY]);
$this->ifPillIsHiddenSetChildFeToHidden();
// SAVE
$save = new Save($this->formSpec, $this->feSpecAction, $this->feSpecNative, $this->feSpecNativeRaw);
$save->processAllImageCutFE();
$save->checkRequiredHidden();
$rc = $save->process();
$save->processAllUploads($rc);
// Action: After*, Sendmail
$feTypeList = FE_TYPE_SENDMAIL . ',' . FE_TYPE_AFTER_SAVE . ',' . ($recordId == 0 ? FE_TYPE_AFTER_INSERT : FE_TYPE_AFTER_UPDATE);
$status = $formAction->elements($rc, $this->feSpecAction, $feTypeList);
if ($status != ACTION_ELEMENT_NO_CHANGE) {
// Reload fresh saved record and fill STORE_RECORD with it.
$this->store->fillStoreWithRecord($this->formSpec[F_TABLE_NAME], $rc, $this->dbArray[$this->dbIndexData], $this->formSpec[F_PRIMARY_KEY]);
}
// Action: Paste
$this->pasteClipboard($this->formSpec[F_ID], $formAction);
$rc = $save->process($recordId);
if ($formMode == FORM_REST) {
$data = $this->doRestPostPut($rc);
......@@ -628,6 +608,7 @@ class QuickFormQuery {
$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);
$this->feSpecNative = HelperFormElement::setFeContainerFormElementId($feSpecNative, $this->formSpec[F_ID], $recordId);
$data = $build->process($formModeNew, false, $this->feSpecNative);
......@@ -898,54 +879,6 @@ class QuickFormQuery {
}
}
/**
* Iterate over all Clipboard source records and fire for each all FE.type=paste records.
*
* @param int $formId
* @param FormAction $formAction
*
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
* @throws \UserReportException
*/
private function pasteClipboard($formId, FormAction $formAction) {
if (!$this->isPasteRecord()) {
return;
}
$cookieQfq = $this->store->getVar(CLIENT_COOKIE_QFQ, STORE_CLIENT, SANITIZE_ALLOW_ALNUMX);
if ($cookieQfq === false || $cookieQfq == '') {
throw new \UserFormException('Qfq Session missing', ERROR_QFQ_SESSION_MISSING);
}