Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
typo3
qfq
Commits
9b1ef2ce
Commit
9b1ef2ce
authored
Mar 21, 2021
by
Carsten Rose
Browse files
Merge branch 'F11998CustomQFQ-Function' into 'develop'
F11998 custom qfq function See merge request
!321
parents
5744133f
92963fb7
Pipeline
#5060
passed with stages
in 3 minutes and 39 seconds
Changes
13
Pipelines
1
Expand all
Hide whitespace changes
Inline
Side-by-side
Documentation/Concept.rst
View file @
9b1ef2ce
...
...
@@ -320,8 +320,8 @@ In :ref:`config-qfq-php` mutliple database credentials can be prepared. Mandator
`DB_1_USER`, `DB_1_SERVER`, `DB_1_PASSWORD`, `DB_1_NAME`. The number '1' indicates the `dbIndex`. Increment the number
to specify further database credential setups.
Typically the credentials for `DB_1`
also have access to the T3 database.
By convention, it's necessary that `DB_1` is the one who
also have access to the T
ypo
3 database.
E.q. `QFQ Function`_ or
download links (based on QFQ functions) needs access to the T3 database to directly fetch tt-content records.
Different QFQ versions, shared database
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
...
Documentation/Report.rst
View file @
9b1ef2ce
This diff is collapsed.
Click to expand it.
Documentation/index.rst
View file @
9b1ef2ce
...
...
@@ -22,7 +22,7 @@ Quick Form Query Extension
en
:Copyright:
2017-202
0
2017-202
1
:Authors:
Carsten Rose, Benjamin Baer
...
...
extension/Classes/Core/Constants.php
View file @
9b1ef2ce
...
...
@@ -490,9 +490,6 @@ const SYSTEM_DB_INIT = 'init';
const
SYSTEM_DB_INDEX_DATA
=
"indexData"
;
const
SYSTEM_DB_INDEX_QFQ
=
"indexQfq"
;
//const SYSTEM_DB_INDEX_DATA_DEPRECATED = "DB_INDEX_DATA";
//const SYSTEM_DB_INDEX_QFQ_DEPRECATED = "DB_INDEX_QFQ";
// Automatically filled by QFQ
const
SYSTEM_DB_NAME_DATA
=
'dbNameData'
;
const
SYSTEM_DB_NAME_QFQ
=
'dbNameQfq'
;
...
...
@@ -1010,6 +1007,7 @@ const F_PARAMETER = 'parameter'; // valid for F_ and FE_
// Form columns: via parameter field
const
F_DB_INDEX
=
'dbIndex'
;
const
DB_INDEX_DEFAULT
=
"1"
;
const
DB_INDEX_T3
=
DB_INDEX_DEFAULT
;
const
PARAM_DB_INDEX_DATA
=
'__dbIndexData'
;
// Submitted via SIP to make record locking DB aware.
const
F_FORM_SUBMIT_LOG_MODE
=
'formSubmitLogMode'
;
...
...
@@ -1529,6 +1527,7 @@ const SENDMAIL_TOKEN_ATTACHMENT_PAGE = 'p';
// Report, BodyText
const
TOKEN_SQL
=
'sql'
;
const
TOKEN_FUNCTION
=
'function'
;
const
TOKEN_TWIG
=
'twig'
;
const
TOKEN_HEAD
=
'head'
;
const
TOKEN_ALT_HEAD
=
'althead'
;
...
...
@@ -1553,7 +1552,7 @@ const TOKEN_DB_INDEX = F_DB_INDEX;
const
TOKEN_CONTENT
=
'content'
;
const
TOKEN_REPORT_FILE
=
'file'
;
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_VALID_LIST
=
'sql|
function|
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
=
'_'
;
...
...
@@ -1704,6 +1703,7 @@ const NAME_URL = 'url';
const
NAME_MAIL
=
'mail'
;
const
NAME_PAGE
=
'page'
;
const
NAME_UID
=
'uid'
;
const
NAME_SOURCE
=
'source'
;
const
NAME_TEXT
=
'text'
;
const
NAME_DROPDOWN
=
'dropdown'
;
const
NAME_DOWNLOAD
=
DOWNLOAD_EXPORT_FILENAME
;
...
...
@@ -1775,6 +1775,7 @@ const TOKEN_URL = 'u';
const
TOKEN_MAIL
=
'm'
;
const
TOKEN_PAGE
=
'p'
;
const
TOKEN_UID
=
'uid'
;
const
TOKEN_SOURCE
=
'source'
;
const
TOKEN_DOWNLOAD
=
'd'
;
const
TOKEN_COPY_TO_CLIPBOARD
=
'y'
;
const
TOKEN_DROPDOWN
=
'z'
;
...
...
@@ -2019,6 +2020,8 @@ const SETTING_TABLESORTER_MODE = 'mode';
const
SETTING_TABLESORTER_MODE_DELETE
=
'delete'
;
const
SETTING_TABLESORTER_CLEAR
=
'Clear'
;
const
COLUMN_FUNCTION_OUTPUT
=
'_output'
;
// Object: Type
const
T_LABEL
=
't_label'
;
const
T_INPUT
=
't_input'
;
...
...
extension/Classes/Core/Database/Database.php
View file @
9b1ef2ce
...
...
@@ -54,7 +54,8 @@ class Database {
*/
private
$sqlLogModePrio
=
[
SQL_LOG_MODE_NONE
=>
1
,
SQL_LOG_MODE_ERROR
=>
2
,
SQL_LOG_MODE_MODIFY
=>
3
,
SQL_LOG_MODE_ALL
=>
4
];
private
$dbName
=
''
;
private
$dbName
=
null
;
private
$dbIndex
=
null
;
/**
* Returns current data base handle from Store[System][SYSTEM_DBH].
...
...
@@ -72,6 +73,7 @@ class Database {
if
(
empty
(
$dbIndex
))
{
$dbIndex
=
DB_INDEX_DEFAULT
;
}
$this
->
dbIndex
=
$dbIndex
;
$this
->
store
=
Store
::
getInstance
();
$storeSystem
=
$this
->
store
->
getStore
(
STORE_SYSTEM
);
...
...
@@ -98,6 +100,13 @@ class Database {
}
}
/**
* @return mixed|string
*/
public
function
getDbIndex
()
{
return
$this
->
dbIndex
;
}
/**
* @return mixed|string
*/
...
...
@@ -1076,8 +1085,7 @@ class Database {
* @throws \DbException
* @throws \UserFormException
*/
public
function
selectFormByName
(
string
$formName
,
array
$columnsToSelect
=
null
)
{
public
function
selectFormByName
(
string
$formName
,
array
$columnsToSelect
=
null
)
{
// make sure to select column 'name'
if
(
is_array
(
$columnsToSelect
)
&&
!
in_array
(
F_NAME
,
$columnsToSelect
))
{
$columnsToSelect
[]
=
F_NAME
;
...
...
@@ -1102,4 +1110,25 @@ class Database {
}
}
/**
* Load tt-content record with subheader=$uid or uid=$uid (depending if $uid is numeric).
* It's important that the current DB class has access to the Typo3 DB.
*
* @param $uid
* @return array // The full T3 tt-content record.
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
* @throws \UserReportException
*/
public
function
getBodyText
(
$uid
)
{
$column
=
(
is_numeric
(
$uid
))
?
'uid'
:
'subheader'
;
$dbT3
=
$this
->
store
->
getVar
(
SYSTEM_DB_NAME_T3
,
STORE_SYSTEM
);
$sql
=
"SELECT * FROM `
$dbT3
`.`tt_content` WHERE `
$column
` = ?"
;
$arr
=
$this
->
sql
(
$sql
,
ROW_EXPECT_1
,
[
$uid
],
'Function "'
.
$column
.
'='
.
$uid
.
'" not found or more than one found.'
);
return
(
$arr
);
}
}
\ No newline at end of file
extension/Classes/Core/Helper/KeyValueStringParser.php
View file @
9b1ef2ce
...
...
@@ -216,16 +216,16 @@ class KeyValueStringParser {
*
* E.g.: "a,b,'c,d',e" with delimiter ',' will result in [ 'a', 'b', 'c,d', 'e' ]
*
* @param $delim
e
ter
* @param $delim
i
ter
* @param $str
* @param int $limit
*
* @return array|bool
* @throws \CodeException
*/
public
static
function
explodeWrapped
(
$delim
e
ter
,
$str
,
$limit
=
PHP_INT_MAX
)
{
public
static
function
explodeWrapped
(
$delim
i
ter
,
$str
,
$limit
=
PHP_INT_MAX
)
{
if
(
$delim
e
ter
==
''
)
{
if
(
$delim
i
ter
==
''
)
{
return
false
;
}
...
...
@@ -242,7 +242,7 @@ class KeyValueStringParser {
$onHold
=
''
;
$cnt
=
0
;
$arr
=
explode
(
$delim
e
ter
,
$str
,
PHP_INT_MAX
);
$arr
=
explode
(
$delim
i
ter
,
$str
,
PHP_INT_MAX
);
foreach
(
$arr
as
$value
)
{
$trimmed
=
trim
(
$value
);
if
(
$value
==
''
&&
$startToken
==
''
)
{
...
...
@@ -269,19 +269,19 @@ class KeyValueStringParser {
}
if
(
$cnt
>=
$limit
)
{
$final
[
$cnt
-
1
]
.
=
$delim
e
ter
.
$value
;
$final
[
$cnt
-
1
]
.
=
$delim
i
ter
.
$value
;
}
else
{
$final
[]
=
$value
;
$cnt
++
;
}
continue
;
}
else
{
$onHold
.
=
$delim
e
ter
.
$value
;
$onHold
.
=
$delim
i
ter
.
$value
;
$lastChar
=
substr
(
$trimmed
,
-
1
);
if
(
$startToken
==
$lastChar
)
{
if
(
$cnt
>=
$limit
)
{
$final
[
$cnt
-
1
]
.
=
$delim
e
ter
.
$onHold
;
$final
[
$cnt
-
1
]
.
=
$delim
i
ter
.
$onHold
;
}
else
{
$final
[]
=
$onHold
;
$cnt
++
;
...
...
extension/Classes/Core/Helper/OnArray.php
View file @
9b1ef2ce
...
...
@@ -130,7 +130,7 @@ class OnArray {
/**
* Converts a onedimensional array by using htmlentities on all elements
* Converts a one
-
dimensional array by using html
entities on all elements
.
*
* @param array $arr
*
...
...
extension/Classes/Core/Helper/OnString.php
View file @
9b1ef2ce
...
...
@@ -337,4 +337,40 @@ class OnString {
public
static
function
strContains
(
string
$haystack
,
string
$needle
):
bool
{
return
strpos
(
$haystack
,
$needle
)
!==
false
;
}
/**
* Split a cmd "getFeUser(pId, pName, ...) : accountId, feUserUid, ..." into:
* rcFunctionName = getFeUser
* rcFunctionParam = [ 'pId', 'pName', ... ]
* rcReturnParam = [ 'accountId', 'feUserUid', ... ]
*
* @param $cmd
* @param $rcFunctionName
* @param $rcFunctionParam
* @param $rcReturnParam
*/
public
static
function
splitFunctionCmd
(
$cmd
,
&
$rcFunctionName
,
&
$rcFunctionParam
,
&
$rcReturnParam
)
{
$rcFunctionName
=
''
;
$rcFunctionParam
=
array
();
$rcReturnParam
=
array
();
if
(
$cmd
==
''
)
{
return
;
}
// $cmd = "getFeUser(pId, pName) : accountId, feUserUid"
$split
=
explode
(
'=>'
,
$cmd
,
2
);
// $split[0] = getFeUser(pId, pName), $split[1]=accountId, feUserUid
$functionArr
=
explode
(
'('
,
$split
[
0
],
2
);
// $functionArr[0]='getFeUser', $functionArr[1]='pId, pName) '
$args
=
explode
(
')'
,
$functionArr
[
1
]
??
''
,
2
);
// $args[0]='pId, pName', $args[1]=' '
$rcFunctionName
=
trim
(
$functionArr
[
0
]);
$rcFunctionParam
=
OnArray
::
trimArray
(
explode
(
','
,
$args
[
0
]
??
''
));
$rcReturnParam
=
OnArray
::
trimArray
(
explode
(
','
,
$split
[
1
]
??
''
));
}
}
extension/Classes/Core/Report/Download.php
View file @
9b1ef2ce
...
...
@@ -353,6 +353,35 @@ class Download {
}
}
/**
* @param string $uid
* @param array $urlParam
* @return string
* @throws \CodeException
* @throws \DbException
* @throws \DownloadException
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
* @throws \UserFormException
* @throws \UserReportException
*/
private
function
getEvaluatedBodytext
(
$uid
,
array
$urlParam
)
{
$bodyTextArr
=
$this
->
db
->
getBodytext
(
$uid
);
// Copy $urlParam to STORE_SIP
foreach
(
$urlParam
as
$key
=>
$paramValue
)
{
$this
->
store
->
setVar
(
$key
,
$paramValue
,
STORE_SIP
);
}
$qfq
=
new
QuickFormQuery
(
$bodyTextArr
,
false
,
false
);
return
$qfq
->
process
();
}
/**
* Interprets $element and fetches corresponding content, either as a file or the content in a variable.
*
...
...
@@ -387,7 +416,7 @@ class Download {
$token
=
$arr
[
0
];
$value
=
$arr
[
1
];
if
(
$token
===
TOKEN_UID
)
{
// extract uid
if
(
$token
===
TOKEN_UID
||
$token
===
TOKEN_SOURCE
)
{
// extract uid
$uidParamsArr
=
explode
(
'&'
,
$value
,
2
);
$uid
=
$uidParamsArr
[
0
];
$value
=
$uidParamsArr
[
1
]
??
''
;
// additional params
...
...
@@ -445,36 +474,6 @@ class Download {
return
$filename
;
}
/**
* @param $uid
* @param array $urlParam
*
* @return string
* @throws \CodeException
* @throws \DbException
* @throws \DownloadException
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
* @throws \UserFormException
* @throws \UserReportException
*/
private
function
getEvaluatedBodyText
(
$uid
,
array
$urlParam
)
{
foreach
(
$urlParam
as
$key
=>
$paramValue
)
{
$this
->
store
->
setVar
(
$key
,
$paramValue
,
STORE_SIP
);
}
$dbT3
=
$this
->
store
->
getVar
(
SYSTEM_DB_NAME_T3
,
STORE_SYSTEM
);
$sql
=
"SELECT `bodytext` FROM `
$dbT3
`.`tt_content` WHERE `uid` = ?"
;
$tt_content
=
$this
->
db
->
sql
(
$sql
,
ROW_EXPECT_1
,
[
$uid
]);
$qfq
=
new
QuickFormQuery
([
T3DATA_BODYTEXT
=>
$tt_content
[
T3DATA_BODYTEXT
]],
false
,
false
);
return
$qfq
->
process
();
}
/**
* Creates a ZIP Files of all given $files
*
...
...
@@ -515,6 +514,63 @@ class Download {
return
$zipFile
;
}
/**
* Check $param for 'source:.<function name>&arg1=val1&arg2=val2,....'.
* For each found, expand it by fire the given QFQ function with the arguments.
* Be aware, the result might contain again a 'source:..' definition ... do it recursively.
*
* Returns a string withut any 'source:' definition.
*
* @param string $param
* @return string
* @throws \CodeException
* @throws \DbException
* @throws \DownloadException
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
* @throws \UserFormException
* @throws \UserReportException
*/
private
function
checkAndExpandSource
(
$param
)
{
if
(
$param
==
''
)
{
return
''
;
}
$final
=
''
;
// $param = 'F:file.pdf|uid:123&pId=22|p:htmlcontent&appId=1|source:myFunction&accId=33'
$elements
=
explode
(
PARAM_DELIMITER
,
$param
);
// $elements = [ 'F:file.pdf', 'uid:123&pId=22;, 'p:htmlcontent&appId=1', 'source:myFunction&accId=33' ]
foreach
(
$elements
as
$element
)
{
// E.g.: $element = 'source:myFunction&accId=33' >>
$arr
=
explode
(
PARAM_TOKEN_DELIMITER
,
$element
,
2
);
// Check for 'source:...' - $arr[0] = 'source'
if
(
0
===
strcmp
(
$arr
[
0
],
TOKEN_SOURCE
))
{
// $arr[1] = 'myFunction&accId=33&grId=44'
$args
=
explode
(
'&'
,
$arr
[
1
],
2
);
$urlParam
=
KeyValueStringParser
::
parse
(
$args
[
1
]
??
''
,
'='
,
'&'
);
// Return a list of
$element
=
$this
->
checkAndExpandSource
(
$this
->
getEvaluatedBodytext
(
$args
[
0
],
$urlParam
));
if
(
$element
==
''
)
{
continue
;
}
}
$final
.
=
'|'
.
$element
;
}
return
substr
(
$final
,
1
);
}
/**
* $vars[DOWNLOAD_EXPORT_FILENAME] - Optional. '<new filename>'
* $vars[DOWNLOAD_MODE] - Optional. file | pdf | excel | thumbnail | monitor - default is a) 'file' in case of only one or b) 'pdf' in case of multiple sources.
...
...
@@ -563,7 +619,8 @@ class Download {
$vars
[
SIP_DOWNLOAD_PARAMETER
]
=
TOKEN_FILE
.
':'
.
$pathFilenameThumbnail
;
}
$elements
=
explode
(
PARAM_DELIMITER
,
$vars
[
SIP_DOWNLOAD_PARAMETER
]);
// Check and expand 'source:...'
$elements
=
explode
(
PARAM_DELIMITER
,
$this
->
checkAndExpandSource
(
$vars
[
SIP_DOWNLOAD_PARAMETER
]));
// Get all files / content
$tmpData
=
array
();
...
...
extension/Classes/Core/Report/Link.php
View file @
9b1ef2ce
...
...
@@ -147,6 +147,7 @@ class Link {
TOKEN_MAIL
=>
NAME_MAIL
,
TOKEN_PAGE
=>
NAME_PAGE
,
TOKEN_UID
=>
NAME_UID
,
TOKEN_SOURCE
=>
NAME_SOURCE
,
TOKEN_DROPDOWN
=>
NAME_DROPDOWN
,
TOKEN_DOWNLOAD
=>
NAME_DOWNLOAD
,
TOKEN_DOWNLOAD_MODE
=>
NAME_DOWNLOAD_MODE
,
...
...
@@ -814,8 +815,8 @@ class Link {
// Store value
if
((
isset
(
$rcTokenGiven
[
TOKEN_DOWNLOAD
])
||
isset
(
$rcTokenGiven
[
TOKEN_COPY_TO_CLIPBOARD
]))
&&
(
$key
==
TOKEN_PAGE
||
$key
==
TOKEN_URL
||
$key
==
TOKEN_URL_PARAM
||
$key
==
TOKEN_UID
||
$key
==
TOKEN_FILE
||
$key
==
TOKEN_FILE_DEPRECATED
))
{
(
$key
==
TOKEN_PAGE
||
$key
==
TOKEN_URL
||
$key
==
TOKEN_URL_PARAM
||
$key
==
TOKEN_UID
||
$key
==
TOKEN_SOURCE
||
$key
==
TOKEN_FILE
||
$key
==
TOKEN_FILE_DEPRECATED
))
{
$vars
[
NAME_COLLECT_ELEMENTS
][]
=
$key
.
':'
.
$value
;
...
...
extension/Classes/Core/Report/Report.php
View file @
9b1ef2ce
...
...
@@ -23,6 +23,7 @@
namespace
IMATHUZH\Qfq\Core\Report
;
use
IMATHUZH\Qfq\Core\BodytextParser
;
use
IMATHUZH\Qfq\Core\Database\Database
;
use
IMATHUZH\Qfq\Core\Evaluate
;
use
IMATHUZH\Qfq\Core\Form\FormAsFile
;
...
...
@@ -60,6 +61,11 @@ class Report {
*/
private
$store
=
null
;
/**
* @var Evaluate
*/
private
$evaluate
=
null
;
/**
* @var string
*/
...
...
@@ -117,19 +123,19 @@ class Report {
* Report constructor.
*
* @param array $t3data
* @param Evaluate $eval
* @param Evaluate $eval
uate
* @param bool $phpUnit
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
* @throws \UserReportException
*/
public
function
__construct
(
array
$t3data
,
Evaluate
$eval
,
$phpUnit
=
false
)
{
public
function
__construct
(
array
$t3data
,
Evaluate
$eval
uate
,
$phpUnit
=
false
)
{
#TODO: rewrite $phpUnit to: "if (!defined('PHPUNIT_QFQ')) {...}"
$this
->
phpUnit
=
$phpUnit
;
Support
::
setIfNotSet
(
$t3data
,
"uid"
,
0
)
;
$t3data
[
"uid"
]
=
$t3data
[
"uid"
]
??
0
;
$this
->
sip
=
new
Sip
(
$phpUnit
);
if
(
$phpUnit
)
{
...
...
@@ -138,6 +144,7 @@ class Report {
$_SERVER
[
'REQUEST_URI'
]
=
'localhost'
;
}
$this
->
evaluate
=
$evaluate
;
$this
->
store
=
Store
::
getInstance
();
$this
->
showDebugInfoFlag
=
(
Support
::
findInSet
(
SYSTEM_SHOW_DEBUG_INFO_YES
,
$this
->
store
->
getVar
(
SYSTEM_SHOW_DEBUG_INFO
,
STORE_SYSTEM
)));
...
...
@@ -167,7 +174,7 @@ class Report {
}
$this
->
db
=
new
Database
(
$this
->
dbIndexData
);
$this
->
variables
=
new
Variables
(
$eval
,
$t3data
[
"uid"
]);
$this
->
variables
=
new
Variables
(
$eval
uate
,
$t3data
[
"uid"
]);
$this
->
link
=
new
Link
(
$this
->
sip
,
$this
->
dbIndexData
,
$phpUnit
);
...
...
@@ -279,7 +286,7 @@ class Report {
// frCmd = "sql"
$frCmd
=
$arrKey
[
count
(
$arrKey
)
-
1
];
// Check if token is known
if
(
strpos
(
'|'
.
strtolower
(
TOKEN_VALID_LIST
)
.
'|'
,
'|'
.
$frCmd
.
'|'
)
===
false
)
{
throw
new
\
UserReportException
(
"Unknown token:
$frCmd
in Line '
$ttLine
''"
,
ERROR_UNKNOWN_TOKEN
);
}
...
...
@@ -307,7 +314,7 @@ class Report {
$index
=
$level
.
"."
.
$frCmd
;
// throw exception if this level was already defined
if
(
!
empty
(
$this
->
frArray
[
$index
]))
{
if
(
!
empty
(
$this
->
frArray
[
$index
]))
{
throw
new
\
UserReportException
(
"Double definition:
$index
is defined more than once."
,
ERROR_DOUBLE_DEFINITION
);
}
// store complete line reformatted in frArray
...
...
@@ -315,9 +322,7 @@ class Report {
// per sql command
//pro sql cmd wird der Indexarray abgefüllt. Dieser wird später verwendet um auf den $frArray zuzugreifen
//if(preg_match("/^sql/i", $frCmd) == 1){
// if ($frCmd === TOKEN_FORM || $frCmd === TOKEN_SQL) {
if
(
$frCmd
===
TOKEN_SQL
)
{
if
(
$frCmd
===
TOKEN_SQL
||
$frCmd
===
TOKEN_FUNCTION
)
{
// Remember max level
$this
->
levelCount
=
max
(
substr_count
(
$level
,
'.'
)
+
1
,
$this
->
levelCount
);
// $indexArray[10][50][5]
...
...
@@ -417,6 +422,85 @@ class Report {
return
$sortArg
;
}
/**
* Split $cmd into a) function name, b) call parameter and c) return values.
* Fire function: tt-content QFQ report
* Return 'return values' in STORE_RECORD and QFQ function output in {{_output:R}}.
* BTW: the QFQ function is cached and read only once. The evaluation is not cached.
*
* @param $cmd # 'getFirstName(pId) => firstName, myLink'
* @throws \CodeException
* @throws \DbException
* @throws \DownloadException
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
* @throws \UserFormException
* @throws \UserReportException
*/
private
function
doQfqFunction
(
$cmd
)
{
// QFQ function cache
static
$functionCache
=
array
();
// Explode cmd
OnString
::
splitFunctionCmd
(
$cmd
,
$rcFunctionName
,
$rcFunctionParam
,
$rcReturnParam
);
// Save STORE_RECORD, STORE_TYPO3
$storeRecord
=
$this
->
store
->
getStore
(
STORE_RECORD
);
$storeTypo3
=
$this
->
store
->
getStore
(
STORE_TYPO3
);
// Fill STORE_RECORD with parameter
$tmp
=
array
();
foreach
(
$rcFunctionParam
as
$key
)
{
$tmp
[
$key
]
=
$storeRecord
[
$key
]
??
''
;
}
$this
->
store
->
setStore
(
$tmp
,
STORE_RECORD
,
true
);
// Get tt_content record bodytext
if
(
isset
(
$functionCache
[
$rcFunctionName
]))
{
// Already cached: get it from cache
$bodytextArr
=
$functionCache
[
$rcFunctionName
];
}
else
{
// Multi DB setup: check for the correct DB
if
(
DB_INDEX_T3
!=
$this
->
db
->
getDbIndex
())
{
// Current DB is wrong: get DB with DB_INDEX_T3
$db
=
new
Database
(
DB_INDEX_T3
);
}
else
{
$db
=
$this
->
db
;
}
$bodytextArr
=
$db
->
getBodyText
(
$rcFunctionName
);
$btp
=
new
BodytextParser
();
$bodytextArr
[
T3DATA_BODYTEXT
]
=
$btp
->
process
(
$bodytextArr
[
T3DATA_BODYTEXT
]);
$functionCache
[
$rcFunctionName
]
=
$bodytextArr
;
}
// Fake uid/pid for meaningful error messages
$this
->
store
->
setVar
(
TYPO3_PAGE_ID
,
$bodytextArr
[
T3DATA_PID
],
STORE_TYPO3
);
$this
->
store
->
setVar
(
TYPO3_TT_CONTENT_UID
,
$bodytextArr
[
T3DATA_UID
],
STORE_TYPO3
);
// Fire bodytext. output is purged
$report
=
new
Report
(
array
(),
$this
->
evaluate
,
$this
->
phpUnit
);
$storeRecord
[
COLUMN_FUNCTION_OUTPUT
]
=
$report
->
process
(
$bodytextArr
[
T3DATA_BODYTEXT
]);
unset
(
$report
);
// Copy defined 'return values' to STORE_RECORD
$tmp
=
$this
->
store
->
getStore
(
STORE_RECORD
);
foreach
(
$rcReturnParam
as
$key
)
{
$storeRecord
[
$key
]
=
$tmp
[
$key
]
??
''
;
$storeRecord
[
'&'
.
$key
]
=
$tmp
[
'&'
.
$key
]
??
''
;
}
// Restore old state
$this
->
store
->
setStore
(
$storeRecord
,
STORE_RECORD
,
true
);
$this
->
store
->
setStore
(
$storeTypo3
,
STORE_TYPO3
,
true
);
}
/**
* Executes the queries recursive. This Method is called for each sublevel.
*
...
...
@@ -495,6 +579,11 @@ class Report {
unset
(
$this
->
variables
->
resultArray
[
$fullLevel
.
".line."
][
LINE_TOTAL
]);
unset
(
$this
->
variables
->
resultArray
[
$fullLevel
.
".line."
][
LINE_COUNT
]);
// If defined, fire QFQ function
if
(
$this
->
frArray
[
$fullLevel
.
"."
.
TOKEN_FUNCTION
]
!=
''
)
{
$this
->
doQfqFunction
(
$this
->
frArray
[
$fullLevel
.
"."
.
TOKEN_FUNCTION
]);
}
$sql
=
$this
->
variables
->
doVariables
(
$this
->
frArray
[
$fullLevel
.
"."
.
TOKEN_SQL
]);
$this
->
store
->
setVar
(
SYSTEM_SQL_FINAL
,
$sql
,
STORE_SYSTEM
);
...
...
@@ -504,9 +593,14 @@ class Report {