Commit f116b3b5 authored by Carsten  Rose's avatar Carsten Rose
Browse files

Merge branch 'master' into F10013CodeMirror

parents 59844782 ced8891f
Pipeline #3230 passed with stages
in 5 minutes and 1 second
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
Release Release
======= =======
Version 19.x.x Version 20.x.x
-------------- --------------
Date: <date> Date: <date>
...@@ -36,6 +36,63 @@ Features ...@@ -36,6 +36,63 @@ Features
Bug Fixes Bug Fixes
^^^^^^^^^ ^^^^^^^^^
Version 20.2.0
--------------
Date: 02.02.2020
Notes
^^^^^
* Add new keyword 'render' in tt-content Report and QFQ config. 'render' will control if a) only Form OR Report will be
rendered (render=single) or b) as previous Form AND Report together (render=both).
Advantage: with 'render=single' no more SELECT ... FROM (SELECT '') AS fake WHERE '{{form:SE}}'=''.
Attention: NEW default behaviour in new QFQ installations - render=single. Behaviour in old installations is unchanged.
* tt-content records with 'render = api' can stay on the same page as the link to get the content (e.g. Excel Export).
* Change default doc page to qfq.io/doc.
* Add new specialColumnName: '_noWrap' - skips wrapping of fbeg,fsep,fend.
* First version of 'FullCalendar.io' - new SpecialColumnName will follow in the future.
Features
^^^^^^^^
* #9929 / New keyword '_noWrap' for column names (alias) - skips wrapping of fbeg/fskip/fend.
* #9905 / Keyword 'render' in Report. Final implementation. Doc updated.
* #9959 / Update QFQ Config on the fly.
* #9990 / Describe order of FormElement processing - https://qfq.io/doc/#form-process-order.
* #8658 / FullCalendar.io V3 implemented.
* #9535 / VerticalText new implementation.
* Manual.rst: Add list of icons. Enhance sendmail doc.
* Change color of qfq-info-* from blue to light-blue. Add qfq-primary, qfq-danger.
Bug Fixes
^^^^^^^^^
* #5869 / Table names not properly escaped.
* #10010 / FE.type=sendmail will now be fired together with fe.type=after* (not after).
* Fixed problem with border showing when qfq-color-white is set.
* Fix selenium tests, remove chromedriver from npm.
* Log problem that crashes qfq when calendar dependencies are missing.
* Fixed gruntfile problem.
Version 20.1.1
--------------
Date: 13.01.2020
Bug Fixes
^^^^^^^^^
* #7705 / Fix problem with wrong value after save and form update.
* #8587 / A form triggers a save only, if there are real table columns.
Version 20.1.0
--------------
Date: 09.01.2020 Date: 09.01.2020
Notes Notes
......
...@@ -11,7 +11,11 @@ Neue Versionsnummer ...@@ -11,7 +11,11 @@ Neue Versionsnummer
0) Fuer jede neue Version ein Ticket erstellen. Template: #6994 0) Fuer jede neue Version ein Ticket erstellen. Template: #6994
1) Alle offenen Branches auf **Develop** und dann auf **Master mergen**. 1) Alle offenen Branches auf **Develop** mergen.
1a) Develop auf **Master mergen**.
1b) Wechseln auf **Master**.
2) Die aktuellen Commits anschauen und wichtige Topics uebernehmen (git log > ~/qfq.log, alles bis zum letzten TAG anschauen): 2) Die aktuellen Commits anschauen und wichtige Topics uebernehmen (git log > ~/qfq.log, alles bis zum letzten TAG anschauen):
...@@ -43,7 +47,7 @@ Neue Versionsnummer ...@@ -43,7 +47,7 @@ Neue Versionsnummer
**Achtung**: die Release Minor darf KEINE fuehrenden Nullen enthalten!!! Ansonsten funktioniert die Verteilung vie TER nicht. **Achtung**: die Release Minor darf KEINE fuehrenden Nullen enthalten!!! Ansonsten funktioniert die Verteilung vie TER nicht.
**Auto**: ./setVersion.sh <MAJOR>.<MINOR>.<MICRO> **Auto**: ./setVersion.sh 20.2.0
Manuell: Manuell:
* extension/Documentation/_make/conf.py: release, version- * extension/Documentation/_make/conf.py: release, version-
...@@ -59,12 +63,12 @@ Neue Versionsnummer ...@@ -59,12 +63,12 @@ Neue Versionsnummer
* Update the version number in this document (topic 6) * Update the version number in this document (topic 6)
* Commit & Push new version changes to master branch: * Commit & Push new version changes to master branch:
New version 20.1.1 New version 20.2.0
6) **New Tag**: 6) **New Tag**:
git tag v20.1.1 git tag v20.2.0
git push -u origin v20.1.1 git push -u origin v20.2.0
7) Tickets: 7) Tickets:
* Schliessen und der QFQ Version zuweisen. * Schliessen und der QFQ Version zuweisen.
......
...@@ -22,7 +22,7 @@ Quick Form Query Extension ...@@ -22,7 +22,7 @@ Quick Form Query Extension
en en
:Copyright: :Copyright:
2017-2019 2017-2020
:Authors: :Authors:
Carsten Rose, Benjamin Baer, Marc Egger Carsten Rose, Benjamin Baer, Marc Egger
...@@ -63,7 +63,7 @@ Quick Form Query Extension ...@@ -63,7 +63,7 @@ Quick Form Query Extension
**Extension Manual** **Extension Manual**
This documentation is for the TYPO3 extension qfq. This documentation is for the TYPO3 extension **qfq**.
**Sitemap:** **Sitemap:**
...@@ -80,3 +80,4 @@ Quick Form Query Extension ...@@ -80,3 +80,4 @@ Quick Form Query Extension
README README
License License
Sitemap Sitemap
This diff is collapsed.
...@@ -36,6 +36,50 @@ Features ...@@ -36,6 +36,50 @@ Features
Bug Fixes Bug Fixes
^^^^^^^^^ ^^^^^^^^^
Version 20.2.0
--------------
Date: 02.02.2020
Notes
^^^^^
* Add new keyword 'render' in tt-content Report and QFQ config. 'render' will control if a) only Form OR Report will be
rendered (render=single) or b) as previous Form AND Report together (render=both).
Advantage: with 'render=single' no more SELECT ... FROM (SELECT '') AS fake WHERE '{{form:SE}}'=''.
Attention: NEW default behaviour in new QFQ installations - render=single. Behaviour in old installations is unchanged.
* tt-content records with 'render = api' can stay on the same page as the link to get the content (e.g. Excel Export).
* Change default doc page to qfq.io/doc.
* Add new specialColumnName: '_noWrap' - skips wrapping of fbeg,fsep,fend.
* First version of 'FullCalendar.io' - new SpecialColumnName will follow in the future.
Features
^^^^^^^^
* #9929 / New keyword '_noWrap' for column names (alias) - skips wrapping of fbeg/fskip/fend.
* #9905 / Keyword 'render' in Report. Final implementation. Doc updated.
* #9959 / Update QFQ Config on the fly.
* #9990 / Describe order of FormElement processing - https://qfq.io/doc/#form-process-order.
* #8658 / FullCalendar.io V3 implemented.
* #9535 / VerticalText new implementation.
* Manual.rst: Add list of icons. Enhance sendmail doc.
* Change color of qfq-info-* from blue to light-blue. Add qfq-primary, qfq-danger.
Bug Fixes
^^^^^^^^^
* #10010 / FE.type=sendmail will now be fired together with fe.type=after* (not after).
* #5869 / Table names not properly escaped.
* #9638 / TextArea: Autosize - broken when using clipboard,
* Fixed problem with border showing when qfq-color-white is set.
* Fix selenium tests, remove chromedriver from npm.
* Log problem that crashes qfq when calendar dependencies are missing.
* Fixed gruntfile problem.
Version 20.1.1 Version 20.1.1
-------------- --------------
......
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
; you can use in 'conf.py' ; you can use in 'conf.py'
project = QFQ - Quick Form Query project = QFQ - Quick Form Query
version = 20.1 version = 20.2
release = 20.1.1 release = 20.2.0
t3author = Carsten Rose t3author = Carsten Rose
copyright = since 2017 by the author copyright = since 2017 by the author
......
...@@ -253,7 +253,7 @@ abstract class AbstractBuildForm { ...@@ -253,7 +253,7 @@ abstract class AbstractBuildForm {
$this->store->setStore($row, STORE_PARENT_RECORD, true); $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. $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[F_MULTI_COL_ID], ROW_EXPECT_1); $record = $this->dbArray[$this->dbIndexData]->sql('SELECT * FROM `' . $this->formSpec[F_TABLE_NAME] . '` WHERE `id`=' . $row[F_MULTI_COL_ID], ROW_EXPECT_1);
$this->store->setStore($record, STORE_RECORD, true); $this->store->setStore($record, STORE_RECORD, true);
$jsonTmp = array(); $jsonTmp = array();
...@@ -555,7 +555,7 @@ abstract class AbstractBuildForm { ...@@ -555,7 +555,7 @@ abstract class AbstractBuildForm {
$record = array(); $record = array();
if ($recordId != 0) { if ($recordId != 0) {
$record = $this->dbArray[$this->dbIndexData]->sql("SELECT * FROM $tableName WHERE $primaryKey=?", ROW_EXPECT_1, [$recordId], "Record to load not found."); $record = $this->dbArray[$this->dbIndexData]->sql("SELECT * FROM `$tableName` WHERE `$primaryKey`=?", ROW_EXPECT_1, [$recordId], "Record to load not found.");
} }
return OnArray::getMd5($record); return OnArray::getMd5($record);
...@@ -742,7 +742,7 @@ abstract class AbstractBuildForm { ...@@ -742,7 +742,7 @@ abstract class AbstractBuildForm {
$primaryKey = $this->formSpec[F_PRIMARY_KEY]; $primaryKey = $this->formSpec[F_PRIMARY_KEY];
if ($recordId > 0 && $this->store->getVar($primaryKey, STORE_RECORD) === false) { if ($recordId > 0 && $this->store->getVar($primaryKey, STORE_RECORD) === false) {
$tableName = $this->formSpec[F_TABLE_NAME]; $tableName = $this->formSpec[F_TABLE_NAME];
$row = $this->dbArray[$this->dbIndexData]->sql("SELECT * FROM $tableName WHERE $primaryKey = ?", ROW_EXPECT_1, $row = $this->dbArray[$this->dbIndexData]->sql("SELECT * FROM `$tableName` WHERE `$primaryKey` = ?", ROW_EXPECT_1,
array($recordId), "Form '" . $this->formSpec[F_NAME] . "' failed to load record '$primaryKey'='$recordId' from table '" . array($recordId), "Form '" . $this->formSpec[F_NAME] . "' failed to load record '$primaryKey'='$recordId' from table '" .
$this->formSpec[F_TABLE_NAME] . "'."); $this->formSpec[F_TABLE_NAME] . "'.");
$this->store->setStore($row, STORE_RECORD); $this->store->setStore($row, STORE_RECORD);
...@@ -2108,7 +2108,7 @@ abstract class AbstractBuildForm { ...@@ -2108,7 +2108,7 @@ abstract class AbstractBuildForm {
} elseif (!empty($formElement[SUBRECORD_PARAMETER_FORM])) { } elseif (!empty($formElement[SUBRECORD_PARAMETER_FORM])) {
// Read table from form specified in subrecord // Read table from form specified in subrecord
$formName = $formElement[SUBRECORD_PARAMETER_FORM]; $formName = $formElement[SUBRECORD_PARAMETER_FORM];
$form = $this->dbArray[$this->dbIndexQfq]->sql("SELECT * FROM Form AS f WHERE f." . F_NAME . " LIKE ? AND f.deleted='no'", $form = $this->dbArray[$this->dbIndexQfq]->sql("SELECT * FROM `Form` AS f WHERE `f`.`" . F_NAME . "` LIKE ? AND `f`.`deleted`='no'",
ROW_REGULAR, [$formName]); ROW_REGULAR, [$formName]);
if (count($form) > 0) { if (count($form) > 0) {
$dndTable = $form[0][F_TABLE_NAME]; $dndTable = $form[0][F_TABLE_NAME];
...@@ -2371,7 +2371,7 @@ abstract class AbstractBuildForm { ...@@ -2371,7 +2371,7 @@ abstract class AbstractBuildForm {
* @throws \UserFormException * @throws \UserFormException
*/ */
private function getFormTable($formName) { private function getFormTable($formName) {
$row = $this->dbArray[$this->dbIndexQfq]->sql("SELECT " . F_TABLE_NAME . " FROM Form AS f WHERE f.name = ?", ROW_EXPECT_0_1, [$formName]); $row = $this->dbArray[$this->dbIndexQfq]->sql("SELECT `" . F_TABLE_NAME . "` FROM `Form` AS f WHERE `f`.`name` = ?", ROW_EXPECT_0_1, [$formName]);
if (isset($row[F_TABLE_NAME])) { if (isset($row[F_TABLE_NAME])) {
return $row[F_TABLE_NAME]; return $row[F_TABLE_NAME];
} }
......
...@@ -252,7 +252,7 @@ class BuildFormBootstrap extends AbstractBuildForm { ...@@ -252,7 +252,7 @@ class BuildFormBootstrap extends AbstractBuildForm {
break; break;
case 'formElement': case 'formElement':
if (false !== ($formId = $this->store->getVar(FE_FORM_ID, STORE_SIP . STORE_RECORD))) { if (false !== ($formId = $this->store->getVar(FE_FORM_ID, STORE_SIP . STORE_RECORD))) {
$row = $this->dbArray[$this->dbIndexQfq]->sql("SELECT f.name FROM Form AS f WHERE id=" . $formId, ROW_EXPECT_1); $row = $this->dbArray[$this->dbIndexQfq]->sql("SELECT `f`.`name` FROM `Form` AS f WHERE `id`=" . $formId, ROW_EXPECT_1);
$form = current($row); $form = current($row);
} }
break; break;
......
...@@ -63,15 +63,15 @@ const RETURN_URL = 'return_url'; ...@@ -63,15 +63,15 @@ const RETURN_URL = 'return_url';
const RETURN_SIP = 'return_sip'; const RETURN_SIP = 'return_sip';
const RETURN_ARRAY = 'return_array'; const RETURN_ARRAY = 'return_array';
const SQL_FORM_ELEMENT_BY_ID = "SELECT * FROM FormElement AS fe WHERE fe.id = ?"; const SQL_FORM_ELEMENT_BY_ID = "SELECT * FROM `FormElement` AS fe WHERE `fe`.`id` = ?";
const SQL_FORM_ELEMENT_RAW = "SELECT * FROM FormElement AS fe WHERE fe.formId = ? AND fe.deleted = 'no' AND fe.enabled='yes' ORDER BY fe.ord, fe.id"; const SQL_FORM_ELEMENT_RAW = "SELECT * FROM `FormElement` AS `fe` WHERE `fe`.`formId` = ? AND `fe`.`deleted` = 'no' AND `fe`.`enabled`='yes' ORDER BY `fe`.`ord`, `fe`.`id`";
const SQL_FORM_ELEMENT_SPECIFIC_CONTAINER = "SELECT *, ? AS 'nestedInFieldSet' FROM FormElement AS fe WHERE fe.formId = ? AND fe.deleted = 'no' AND FIND_IN_SET(fe.class, ? ) AND fe.feIdContainer = ? AND fe.enabled='yes' ORDER BY fe.ord, fe.id"; const SQL_FORM_ELEMENT_SPECIFIC_CONTAINER = "SELECT *, ? AS 'nestedInFieldSet' FROM `FormElement` AS fe WHERE `fe`.`formId` = ? AND `fe`.`deleted` = 'no' AND FIND_IN_SET(`fe`.`class`, ? ) AND `fe`.`feIdContainer` = ? AND `fe`.`enabled`='yes' ORDER BY `fe`.`ord`, `fe`.`id`";
const SQL_FORM_ELEMENT_ALL_CONTAINER = "SELECT *, ? AS 'nestedInFieldSet' FROM FormElement AS fe WHERE fe.formId = ? AND fe.deleted = 'no' AND FIND_IN_SET(fe.class, ? ) AND fe.enabled='yes' ORDER BY fe.ord, fe.id"; const SQL_FORM_ELEMENT_ALL_CONTAINER = "SELECT *, ? AS 'nestedInFieldSet' FROM `FormElement` AS `fe` WHERE `fe`.`formId` = ? AND `fe`.`deleted` = 'no' AND FIND_IN_SET(`fe`.`class`, ? ) AND `fe`.`enabled`='yes' ORDER BY `fe`.`ord`, `fe`.`id`";
const SQL_FORM_ELEMENT_SIMPLE_ALL_CONTAINER = "SELECT fe.id, fe.feIdContainer, fe.name, fe.value, fe.label, fe.type, fe.encode, fe.checkType, fe.checkPattern, fe.mode, fe.modeSql, fe.parameter, fe.dynamicUpdate FROM FormElement AS fe, Form AS f WHERE f.name = ? AND f.id = fe.formId AND fe.deleted = 'no' AND fe.class = 'native' AND fe.enabled='yes' ORDER BY fe.ord, fe.id"; const SQL_FORM_ELEMENT_SIMPLE_ALL_CONTAINER = "SELECT `fe`.`id`, `fe`.`feIdContainer`, `fe`.`name`, `fe`.`value`, `fe`.`label`, `fe`.`type`, `fe`.`encode`, `fe`.`checkType`, `fe`.`checkPattern`, `fe`.`mode`, `fe`.`modeSql`, `fe`.`parameter`, `fe`.`dynamicUpdate` FROM `FormElement` AS fe, `Form` AS f WHERE `f`.`name` = ? AND `f`.`id` = `fe`.`formId` AND `fe`.`deleted` = 'no' AND `fe`.`class` = 'native' AND `fe`.`enabled`='yes' ORDER BY `fe`.`ord`, `fe`.`id`";
const SQL_FORM_ELEMENT_CONTAINER_TEMPLATE_GROUP = "SELECT fe.id, fe.name, fe.label, fe.maxLength, fe.parameter FROM FormElement AS fe, Form AS f WHERE f.name = ? AND f.id = fe.formId AND fe.deleted = 'no' AND fe.class = 'container' AND fe.type='templateGroup' AND fe.enabled='yes' ORDER BY fe.ord, fe.id"; const SQL_FORM_ELEMENT_CONTAINER_TEMPLATE_GROUP = "SELECT `fe`.`id`, `fe`.`name`, `fe`.`label`, `fe`.`maxLength`, `fe`.`parameter` FROM `FormElement` AS fe, `Form` AS f WHERE `f`.`name` = ? AND `f`.`id` = `fe`.`formId` AND `fe`.`deleted` = 'no' AND `fe`.`class` = 'container' AND `fe`.`type`='templateGroup' AND `fe`.`enabled`='yes' ORDER BY `fe`.`ord`, `fe`.`id`";
const SQL_FORM_ELEMENT_TEMPLATE_GROUP_FE_ID = "SELECT * FROM FormElement AS fe WHERE fe.id = ? AND fe.deleted = 'no' AND fe.class = 'container' AND fe.type='templateGroup' AND fe.enabled='yes' "; const SQL_FORM_ELEMENT_TEMPLATE_GROUP_FE_ID = "SELECT * FROM `FormElement` AS fe WHERE `fe`.`id` = ? AND `fe`.`deleted` = 'no' AND `fe`.`class` = 'container' AND `fe`.`type`='templateGroup' AND `fe`.`enabled`='yes' ";
//const SQL_FORM_ELEMENT_NATIVE_TG_COUNT = "SELECT fe.*, IFNULL(feTg.maxLength,0) AS _tgCopies FROM FormElement AS fe LEFT JOIN FormElement AS feTg ON fe.feIdContainer=feTg.id AND feTg.deleted = 'no' AND feTg.class = 'container' AND feTg.type='templateGroup' AND feTg.enabled='yes' WHERE fe.formId = ? AND fe.deleted = 'no' AND fe.class = 'native' AND fe.enabled='yes'"; //const SQL_FORM_ELEMENT_NATIVE_TG_COUNT = "SELECT fe.*, IFNULL(feTg.maxLength,0) AS _tgCopies FROM FormElement AS fe LEFT JOIN FormElement AS feTg ON fe.feIdContainer=feTg.id AND feTg.deleted = 'no' AND feTg.class = 'container' AND feTg.type='templateGroup' AND feTg.enabled='yes' WHERE fe.formId = ? AND fe.deleted = 'no' AND fe.class = 'native' AND fe.enabled='yes'";
const SQL_FORM_ELEMENT_NATIVE_TG_COUNT = "SELECT fe.*, IFNULL(feTg.maxLength,0) AS _tgCopies FROM FormElement AS fe LEFT JOIN FormElement AS feTg ON fe.feIdContainer=feTg.id AND feTg.deleted = 'no' AND feTg.class = 'container' AND feTg.type='templateGroup' AND feTg.enabled='yes' WHERE fe.formId = ? AND fe.deleted = 'no' AND (fe.class = 'native' OR (fe.class = 'container' AND fe.type='pill')) AND fe.enabled='yes'"; const SQL_FORM_ELEMENT_NATIVE_TG_COUNT = "SELECT `fe`.*, IFNULL(`feTg`.`maxLength`,0) AS _tgCopies FROM `FormElement` AS fe LEFT JOIN `FormElement` AS feTg ON `fe`.`feIdContainer`=`feTg`.`id` AND `feTg`.`deleted` = 'no' AND `feTg`.`class` = 'container' AND `feTg`.`type`='templateGroup' AND `feTg`.`enabled`='yes' WHERE `fe`.`formId` = ? AND `fe`.`deleted` = 'no' AND (`fe`.`class` = 'native' OR (`fe`.`class` = 'container' AND `fe`.`type`='pill')) AND `fe`.`enabled`='yes'";
const NAME_TG_COPIES = '_tgCopies'; // Number of templatesGroup copies to create on the fly. Also used in SQL_FORM_ELEMENT_NATIVE_TG_COUNT. const NAME_TG_COPIES = '_tgCopies'; // Number of templatesGroup copies to create on the fly. Also used in SQL_FORM_ELEMENT_NATIVE_TG_COUNT.
const FE_TG_INDEX = '_tgIndex'; // Index of the current copy of a templateGroup FE. const FE_TG_INDEX = '_tgIndex'; // Index of the current copy of a templateGroup FE.
...@@ -516,6 +516,10 @@ const SYSTEM_REDIRECT_ALL_MAIL_TO = 'redirectAllMailTo'; ...@@ -516,6 +516,10 @@ const SYSTEM_REDIRECT_ALL_MAIL_TO = 'redirectAllMailTo';
const SYSTEM_THROW_GENERAL_ERROR = 'throwExceptionGeneralError'; const SYSTEM_THROW_GENERAL_ERROR = 'throwExceptionGeneralError';
const SYSTEM_FLAG_PRODUCTION = 'flagProduction'; const SYSTEM_FLAG_PRODUCTION = 'flagProduction';
const SYSTEM_RENDER = 'render';
const SYSTEM_RENDER_SINGLE = 'single';
const SYSTEM_RENDER_BOTH = 'both';
const SYSTEM_RENDER_API = 'api';
const SYSTEM_SHOW_DEBUG_INFO = 'showDebugInfo'; const SYSTEM_SHOW_DEBUG_INFO = 'showDebugInfo';
const SYSTEM_SHOW_DEBUG_INFO_YES = 'yes'; const SYSTEM_SHOW_DEBUG_INFO_YES = 'yes';
...@@ -650,10 +654,10 @@ const SYSTEM_THUMBNAIL_DIR_PUBLIC = 'thumbnailDirPublic'; ...@@ -650,10 +654,10 @@ const SYSTEM_THUMBNAIL_DIR_PUBLIC = 'thumbnailDirPublic';
const SYSTEM_THUMBNAIL_DIR_PUBLIC_DEFAULT = 'typo3temp/qfqThumbnail'; const SYSTEM_THUMBNAIL_DIR_PUBLIC_DEFAULT = 'typo3temp/qfqThumbnail';
const SYSTEM_DOCUMENTATION_QFQ = 'documentation'; const SYSTEM_DOCUMENTATION_QFQ = 'documentation';
const SYSTEM_DOCUMENTATION_QFQ_URL = 'https://docs.typo3.org/p/IMATHUZH/qfq/master/en-us/Manual.html'; const SYSTEM_DOCUMENTATION_QFQ_URL = 'https://qfq.io/doc';
// Not stored in config.qfq.ini, but used in STORE_SYSTEM // Not stored in config.qfq.php, but used in STORE_SYSTEM
// Information for: Log / Debug / Exception // Information for: Log / Debug / Exception
const SYSTEM_SQL_RAW = 'sqlRaw'; // Type: SANITIZE_ALL / String. SQL Query (before substitute). Useful for error reporting. const SYSTEM_SQL_RAW = 'sqlRaw'; // Type: SANITIZE_ALL / String. SQL Query (before substitute). Useful for error reporting.
const SYSTEM_SQL_FINAL = 'sqlFinal'; // Type: SANITIZE_ALL / String. SQL Query (after substitute). Useful for error reporting. const SYSTEM_SQL_FINAL = 'sqlFinal'; // Type: SANITIZE_ALL / String. SQL Query (after substitute). Useful for error reporting.
...@@ -1516,7 +1520,7 @@ const TOKEN_DEBUG_BODYTEXT = TYPO3_DEBUG_SHOW_BODY_TEXT; ...@@ -1516,7 +1520,7 @@ const TOKEN_DEBUG_BODYTEXT = TYPO3_DEBUG_SHOW_BODY_TEXT;
const TOKEN_DB_INDEX = F_DB_INDEX; const TOKEN_DB_INDEX = F_DB_INDEX;
const TOKEN_CONTENT = 'content'; const TOKEN_CONTENT = 'content';
const TOKEN_VALID_LIST = 'sql|twig|head|althead|altsql|tail|shead|stail|rbeg|rend|renr|rsep|fbeg|fend|fsep|fskipwrap|rbgd|debug|form|r|debugShowBodyText|dbIndex|sqlLog|sqlLogMode|content'; const TOKEN_VALID_LIST = 'sql|twig|head|althead|altsql|tail|shead|stail|rbeg|rend|renr|rsep|fbeg|fend|fsep|fskipwrap|rbgd|debug|form|r|debugShowBodyText|dbIndex|sqlLog|sqlLogMode|content|render';
const TOKEN_COLUMN_CTRL = '_'; const TOKEN_COLUMN_CTRL = '_';
...@@ -1584,9 +1588,18 @@ const COLUMN_MAILTO = "mailto"; ...@@ -1584,9 +1588,18 @@ const COLUMN_MAILTO = "mailto";
const COLUMN_SENDMAIL = "sendmail"; const COLUMN_SENDMAIL = "sendmail";
const COLUMN_VERTICAL = "vertical"; const COLUMN_VERTICAL = "vertical";
const COLUMN_NO_WRAP = "noWrap";
const COLUMN_HIDE = "hide";
const C_FULL = 'full';
const C_TITLE = 'title';
const C_NO_WRAP = 'noWrap';
const C_SPECIAL = 'special';
const C_HIDE = 'hide';
const COLUMN_WRAP_TOKEN = '+'; const COLUMN_WRAP_TOKEN = '+';
const COLUMN_STORE_USER = '='; const COLUMN_STORE_USER = '=';
const FORM_NAME_FORM = 'form'; const FORM_NAME_FORM = 'form';
const FORM_NAME_FORM_ELEMENT = 'formElement'; const FORM_NAME_FORM_ELEMENT = 'formElement';
const FORM_LOG_MODE = '_formLogMode'; // Variable to call the form in debug mode. const FORM_LOG_MODE = '_formLogMode'; // Variable to call the form in debug mode.
......
...@@ -1055,7 +1055,7 @@ class Database { ...@@ -1055,7 +1055,7 @@ class Database {
*/ */
public function deleteSplitFileAndRecord($xId, $tableName) { public function deleteSplitFileAndRecord($xId, $tableName) {
$sql = 'SELECT pathFileName FROM ' . TABLE_NAME_SPLIT . ' WHERE tableName=? AND xId=?'; $sql = 'SELECT `pathFileName` FROM `' . TABLE_NAME_SPLIT . '` WHERE `tableName`=? AND `xId`=?';
$data = $this->sql($sql, ROW_REGULAR, [$tableName, $xId]); $data = $this->sql($sql, ROW_REGULAR, [$tableName, $xId]);
foreach ($data AS $row) { foreach ($data AS $row) {
...@@ -1064,7 +1064,7 @@ class Database { ...@@ -1064,7 +1064,7 @@ class Database {
} }
} }
$this->sql('DELETE FROM ' . TABLE_NAME_SPLIT . ' WHERE tableName=? AND xId=?', ROW_REGULAR, [$tableName, $xId]); $this->sql('DELETE FROM `' . TABLE_NAME_SPLIT . '` WHERE `tableName`=? AND `xId`=?', ROW_REGULAR, [$tableName, $xId]);
} }
} }
\ No newline at end of file
...@@ -10,6 +10,7 @@ namespace IMATHUZH\Qfq\Core\Database; ...@@ -10,6 +10,7 @@ namespace IMATHUZH\Qfq\Core\Database;
use IMATHUZH\Qfq\Core\Helper\Logger; use IMATHUZH\Qfq\Core\Helper\Logger;
use IMATHUZH\Qfq\Core\Store\Store; use IMATHUZH\Qfq\Core\Store\Store;
use IMATHUZH\Qfq\Core\Typo3\T3Handler;
/* /*
...@@ -129,14 +130,17 @@ class DatabaseUpdate { ...@@ -129,14 +130,17 @@ class DatabaseUpdate {
*/ */
public function checkNupdate($dbUpdate) { public function checkNupdate($dbUpdate) {
if ($dbUpdate === SYSTEM_DB_UPDATE_NEVER) {
return;
}
$new = $this->getExtensionVersion(); $new = $this->getExtensionVersion();
$versionInfo = $this->getDatabaseVersion(); $versionInfo = $this->getDatabaseVersion();
$old = $versionInfo[QFQ_VERSION_KEY] ?? false; $old = $versionInfo[QFQ_VERSION_KEY] ?? false;
$this->checkT3QfqConfig($old, $new);
if ($dbUpdate === SYSTEM_DB_UPDATE_NEVER) {
return;
}
if ($dbUpdate === SYSTEM_DB_UPDATE_ALWAYS || ($dbUpdate === SYSTEM_DB_UPDATE_AUTO && $new != $old)) { if ($dbUpdate === SYSTEM_DB_UPDATE_ALWAYS || ($dbUpdate === SYSTEM_DB_UPDATE_AUTO && $new != $old)) {
$newFunctionHash = $this->updateSqlFunctions($versionInfo[QFQ_VERSION_KEY_FUNCTION_HASH] ?? ''); $newFunctionHash = $this->updateSqlFunctions($versionInfo[QFQ_VERSION_KEY_FUNCTION_HASH] ?? '');
...@@ -167,6 +171,23 @@ class DatabaseUpdate { ...@@ -167,6 +171,23 @@ class DatabaseUpdate {
} }
/**
* Check Typo3 config if values needs to be updated.
* This is typically necessary if default config values change, to guarantee existing installations behave in legacy mode.
*
* @param $old
* @param $new
*/
private function checkT3QfqConfig($old, $new) {
if ($new == $old) {
return;
}
if (version_compare($old, '20.2.0') == -1) {
T3Handler::updateT3QfqConfig(SYSTEM_RENDER, SYSTEM_RENDER_BOTH); //Legacy behaviour.
}
}
/** /**
* Check if there are special columns without prepended underscore in the QFQ application. If yes, then throw an error. * Check if there are special columns without prepended underscore in the QFQ application. If yes, then throw an error.
* A link is provided to automatically prepend all found special columns. And another link to skip the auto-replacement. * A link is provided to automatically prepend all found special columns. And another link to skip the auto-replacement.
...@@ -201,14 +222,14 @@ class DatabaseUpdate { ...@@ -201,14 +222,14 @@ class DatabaseUpdate {
if (defined('PHPUNIT_QFQ')) { if (defined('PHPUNIT_QFQ')) {
$res = array(); $res = array();
} else { } else {
$res = $this->db->sql("SELECT uid, header, bodytext FROM " . $dbT3 . ".tt_content WHERE CType='qfq_qfq' AND deleted=0;"); $res = $this->db->sql("SELECT `uid`, `header`, `bodytext` FROM `" . $dbT3 . "`.`tt_content` WHERE `CType`='qfq_qfq' AND `deleted`=0;");
} }
foreach ($res as $i => $tt_content) { foreach ($res as $i => $tt_content) {
$replaced_placeholder = preg_replace($patterns, '${1}' . $placeholder . '${2}', $tt_content['bodytext']); $replaced_placeholder = preg_replace($patterns, '${1}' . $placeholder . '${2}', $tt_content['bodytext']);
if (strpos($replaced_placeholder, $placeholder) !== false) { if (strpos($replaced_placeholder, $placeholder) !== false) {
if ($actionSpecialColumn === ACTION_SPECIAL_COLUMN_DO_REPLACE) { if ($actionSpecialColumn === ACTION_SPECIAL_COLUMN_DO_REPLACE) {
$replace = str_replace($placeholder, '_', $replaced_placeholder); $replace = str_replace($placeholder, '_', $replaced_placeholder);
$query = "UPDATE " . $dbT3 . ".tt_content SET bodytext='" . addslashes($replace) . "' WHERE uid='" . $tt_content['uid'] . "'"; $query = "UPDATE `" . $dbT3 . "`.`tt_content` SET `bodytext`='" . addslashes($replace) . "' WHERE `uid`='" . $tt_content['uid'] . "'";
$this->db->sql($query); $this->db->sql($query);
} }
$message_fe .= '<hr><b>' . $tt_content['header'] . ' [uid:' . $tt_content['uid'] . ']</b><br><br>'; $message_fe .= '<hr><b>' . $tt_content['header'] . ' [uid:' . $tt_content['uid'] . ']</b><br><br>';
...@@ -226,7 +247,7 @@ class DatabaseUpdate { ...@@ -226,7 +247,7 @@ class DatabaseUpdate {
if (defined('PHPUNIT_QFQ')) { if (defined('PHPUNIT_QFQ')) {
$res = array(); $res = array();
} else { } else {
$res = $this->db->sql("SELECT fe.id, fe.name, fe.value, fe.note FROM FormElement as fe WHERE fe.type='note' AND fe.value LIKE '#!report%' OR fe.note LIKE '%#!report%';"); $res = $this->db->sql("SELECT `fe`.`id`, `fe`.`name`, `fe`.`value`, `fe`.`note` FROM `FormElement` AS fe WHERE `fe`.`type`='note' AND `fe`.`value` LIKE '#!report%' OR `fe`.`note` LIKE '%#!report%';");
} }
foreach ($res as $i => $tt_content) { foreach ($res as $i => $tt_content) {
...@@ -235,7 +256,7 @@ class DatabaseUpdate { ...@@ -235,7 +256,7 @@ class DatabaseUpdate {
if (strpos($replaced_placeholder, $placeholder) !== false) { if (strpos($replaced_placeholder, $placeholder) !== false) {
if ($actionSpecialColumn === ACTION_SPECIAL_COLUMN_DO_REPLACE) { if ($actionSpecialColumn === ACTION_SPECIAL_COLUMN_DO_REPLACE) {
$replace = str_replace($placeholder, '_', $replaced_placeholder); $replace = str_replace($placeholder, '_', $replaced_placeholder);
$query = "UPDATE FormElement SET " . $columnName . "='" . addslashes($replace) . "' WHERE id='" . $tt_content['id'] . "'"; $query = "UPDATE `FormElement` SET `" . $columnName . "`='" . addslashes($replace) . "' WHERE `id`='" . $tt_content['id'] . "'";
$this->db->sql($query); $this->db->sql($query);
} }
$message_ttc .= '<hr><b>' . $tt_content['name'] . ' [id:' . $tt_content['id'] . '] (FormElement.' . $columnName . ')</b><br><br>'; $message_ttc .= '<hr><b>' . $tt_content['name'] . ' [id:' . $tt_content['id'] . '] (FormElement.' . $columnName . ')</b><br><br>';
......
...@@ -23,7 +23,7 @@ $UPDATE_ARRAY = array( ...@@ -23,7 +23,7 @@ $UPDATE_ARRAY = array(
], ],
'0.15.0' => [ '0.15.0' => [
"UPDATE FormElement SET parameter = REPLACE(parameter, 'typeAheadLdapKeyPrintf', 'typeAheadLdapIdPrintf')", "UPDATE `FormElement` SET `parameter` = REPLACE(parameter, 'typeAheadLdapKeyPrintf', 'typeAheadLdapIdPrintf')",
"ALTER TABLE `FormElement` CHANGE `placeholder` `placeholder` VARCHAR( 2048 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' ", "ALTER TABLE `FormElement` CHANGE `placeholder` `placeholder` VARCHAR( 2048 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' ",
], ],
...@@ -44,7 +44,7 @@ $UPDATE_ARRAY = array( ...@@ -44,7 +44,7 @@ $UPDATE_ARRAY = array(