From 13d39fbef60e9b859e68853cd7dd756253ef093c Mon Sep 17 00:00:00 2001
From: Carsten  Rose <carsten.rose@math.uzh.ch>
Date: Sun, 26 Feb 2017 23:41:58 +0100
Subject: [PATCH] #2064: Input Elemente die als JSON response 'value=false'
 bekommen, zeigen 'false' an. #3253: STORE_TYPO3: steht waehrend Update / Save
 nicht zur Verfuegung - wird aber benoetigt. Bsp: feUser, beUser, pageId, ...

Thought that problem of #2064 is based on #3253 - that was wrong.
#3253 implemented, but not heavily tested.

#2064: problem was that for a non existing tablecolumn, has been searched for a default value - which obviously does not exist. In AbstractBuildForm.php, Line 419, a check implemented if the current FormElement is an existing tablecolumn. If not, do not change the empty value.

FormAction.php, FillStoreForm.php, Store.php, QuickFormQuery.php, Save.php: Refactor setVarArray() to setStore()

#3253
FillStoreForm.php: If there is no STORE_TYPO3, get the old values from SIP: CLIENT_TYPO3VARS.
Store.php: new function fillTypo3StoreFromSip(), copyT3VarstToSip()
---
 extension/qfq/qfq/AbstractBuildForm.php   | 200 ++++++++++++----------
 extension/qfq/qfq/Constants.php           |   2 +
 extension/qfq/qfq/QuickFormQuery.php      |   6 +-
 extension/qfq/qfq/Save.php                |   2 +-
 extension/qfq/qfq/form/FormAction.php     |   2 +-
 extension/qfq/qfq/store/FillStoreForm.php |  75 ++++----
 extension/qfq/qfq/store/Store.php         | 111 ++++++++----
 extension/qfq/tests/phpunit/StoreTest.php |   6 +-
 8 files changed, 239 insertions(+), 165 deletions(-)

diff --git a/extension/qfq/qfq/AbstractBuildForm.php b/extension/qfq/qfq/AbstractBuildForm.php
index 1ef841270..df11cc0ae 100644
--- a/extension/qfq/qfq/AbstractBuildForm.php
+++ b/extension/qfq/qfq/AbstractBuildForm.php
@@ -146,6 +146,7 @@ abstract class AbstractBuildForm {
     public function process($mode, $htmlElementNameIdZero = false) {
         $htmlHead = '';
         $htmlTail = '';
+        $htmlT3vars = '';
         $htmlSubrecords = '';
         $htmlElements = '';
         $json = array();
@@ -169,7 +170,7 @@ abstract class AbstractBuildForm {
 
             $parentRecords = $this->db->sql($this->formSpec['multiSql']);
             foreach ($parentRecords as $row) {
-                $this->store->setVarArray($row, STORE_PARENT_RECORD, true);
+                $this->store->setStore($row, STORE_PARENT_RECORD, true);
                 $jsonTmp = array();
                 $htmlElements = $this->elements($row['_id'], $filter, 0, $jsonTmp, $modeCollectFe);
                 $json[] = $jsonTmp;
@@ -181,13 +182,14 @@ abstract class AbstractBuildForm {
 
         // <form>
         if ($mode === FORM_LOAD) {
+            $htmlT3vars = $this->prepareT3VarsForSave();
             $htmlTail = $this->tail();
             $htmlSubrecords = $this->doSubrecords();
         }
 
         $htmlSip = $this->buildHiddenSip($json);
 
-        return ($mode === FORM_LOAD) ? $htmlHead . $htmlElements . $htmlSip . $htmlTail . $htmlSubrecords : $json;
+        return ($mode === FORM_LOAD) ? $htmlHead . $htmlElements . $htmlSip . $htmlT3vars . $htmlTail . $htmlSubrecords : $json;
     }
 
     /**
@@ -354,7 +356,7 @@ abstract class AbstractBuildForm {
         // get current data record
         if ($recordId > 0 && $this->store->getVar('id', STORE_RECORD) === false) {
             $row = $this->db->sql("SELECT * FROM " . $this->formSpec[F_TABLE_NAME] . " WHERE id = ?", ROW_EXPECT_1, array($recordId), "Form '" . $this->formSpec[F_NAME] . "' failed to load record '$recordId' from table '" . $this->formSpec[F_TABLE_NAME] . "'.");
-            $this->store->setVarArray($row, STORE_RECORD);
+            $this->store->setStore($row, STORE_RECORD);
         }
 
         $this->checkAutoFocus();
@@ -397,9 +399,17 @@ abstract class AbstractBuildForm {
             $name = (isset($formElement[FE_RETYPE_SOURCE_NAME])) ? $formElement[FE_RETYPE_SOURCE_NAME] : $formElement[FE_NAME];
 
             // Get default value
-            $value = ($formElement[FE_VALUE] === '') ? $this->store->getVar($name, $storeUse,
-                $formElement['checkType']) : $formElement[FE_VALUE];
-
+//            $value = ($formElement[FE_VALUE] === '') ? $this->store->getVar($name, $storeUse,
+//                $formElement['checkType']) : $formElement[FE_VALUE];
+
+            $value = $formElement[FE_VALUE];
+            // If there is no value, check the default.
+            if ($value === '') {
+                // Only take the default, if the FE is a real tablecolumn.
+                if ($this->store->getVar($formElement[FE_NAME], STORE_RECORD) !== false) {
+                    $value = $this->store->getVar($name, $storeUse, $formElement['checkType']);
+                }
+            }
             // Typically: $htmlElementNameIdZero = true
             // After Saving a record, staying on the form, the FormElements on the Client are still known as '<feName>:0'.
             $htmlFormElementId = HelperFormElement::buildFormElementName($formElement[FE_NAME], ($htmlElementNameIdZero) ? 0 : $recordId);
@@ -498,6 +508,31 @@ abstract class AbstractBuildForm {
 
     abstract public function fillWrapLabelInputNote($label, $input, $note);
 
+    /**
+     * Copy a subset of current STORE_TYPO3 variables to SIP. Set a hidden form field to submit the assigned SIP to save/update.
+     *
+     * @throws CodeException
+     * @throws UserFormException
+     */
+    private function prepareT3VarsForSave() {
+
+        $t3VarsSip = $this->store->copyT3VarsToSip();
+
+        return $this->buildNativeHidden(CLIENT_TYPO3VARS, $t3VarsSip);
+
+    }
+
+    /**
+     * Builds a real HTML hidden form element. Useful for checkboxes, Multiple-Select and Radios.
+     *
+     * @param $htmlFormElementId
+     * @param $value
+     * @return string
+     */
+    public function buildNativeHidden($htmlFormElementId, $value) {
+        return '<input type="hidden" name="' . $htmlFormElementId . '" value="' . htmlentities($value) . '">';
+    }
+
     abstract public function tail();
 
     abstract public function doSubrecords();
@@ -592,17 +627,6 @@ abstract class AbstractBuildForm {
         }
     }
 
-    /**
-     * Builds a real HTML hidden form element. Useful for checkboxes, Multiple-Select and Radios.
-     *
-     * @param $htmlFormElementId
-     * @param $value
-     * @return string
-     */
-    public function buildNativeHidden($htmlFormElementId, $value) {
-        return '<input type="hidden" name="' . $htmlFormElementId . '" value="' . htmlentities($value) . '">';
-    }
-
     /**
      * Takes the current SIP ('form' and additional parameter), set SIP_RECORD_ID=0 and create a new 'NewRecordUrl'.
      *
@@ -2318,77 +2342,6 @@ abstract class AbstractBuildForm {
         return $html;
     }
 
-    /**
-     * Build real FormElements based on the current templateGroup FormElements in $this->feSpecNative.
-     * Take a templateGroup 'copy', if at least one of the elements is filled with a non default value.
-     * Stop filling elements if there are no further elements filled.
-     *
-     * @param int $max
-     * @param string $htmlDelete
-     * @param array $json
-     * @return string
-     * @throws CodeException
-     * @throws \qfq\UserFormException
-     */
-    private function templateGroupCollectFilledElements($max, $htmlDelete, array &$json) {
-
-        $record = $this->store->getStore(STORE_RECORD); // current values
-        if($record===false || count($record)===0) {
-            return '';
-        }
-        $default = $this->store->getStore(STORE_TABLE_DEFAULT); // current defaults
-
-        $lastFilled = 0; // Marker if there is at least one element per copy who is filled.
-        $feSpecNativeCopy = array();
-        for($ii = 1; $ii < $max; $ii++) {
-
-            // Per copy, iterate over all templateGroup FormElements
-            foreach($this->feSpecNative as $fe) {
-
-                $columnName = str_replace(FE_TEMPLATE_GROUP_NAME_PATTERN, $ii, $fe[FE_NAME]);
-
-                $fe[FE_LABEL] = str_replace(FE_TEMPLATE_GROUP_NAME_PATTERN, $ii, $fe[FE_LABEL]);
-                $fe[FE_NOTE] = str_replace(FE_TEMPLATE_GROUP_NAME_PATTERN, $ii, $fe[FE_NOTE]);
-                if(isset($record[$columnName])) {
-                    if($record[$columnName] != $default[$columnName]) {
-                        $lastFilled = $ii;
-                    }
-                } else {
-                    throw new UserFormException("Not implemented: templateGroup FormElement-columns not found in primary table.", ERROR_NOT_IMPLEMENTED);
-                }
-                $fe[FE_NAME] = $columnName;
-                $feSpecNativeCopy[$ii-1][] = $fe; // Build array with current copy of templateGroup.
-            }
-
-            // Append $htmlDelete on the last element of all copies,, but not the first.
-            if($ii>1) {
-                // Count defined FormElements in the current templateGroup
-                $last = count($feSpecNativeCopy[$ii-1]) - 1;
-                // Append 'delete' Button at the note of the last element
-                $feSpecNativeCopy[$ii-1][$last][FE_NOTE] .= $htmlDelete;
-            }
-        }
-
-        // Nothing found: return
-        if(count($feSpecNativeCopy)==0){
-            return '';
-        }
-
-        $feSpecNativeSave = $this->feSpecNative;
-
-        $html = '';
-        for($ii=0; $ii<$lastFilled; $ii++) {
-            $this->feSpecNative = $feSpecNativeCopy[$ii];
-            $htmlCopy = $this->elements($this->store->getVar(SIP_RECORD_ID, STORE_SIP), FORM_ELEMENTS_NATIVE, 0, $json);
-            $htmlCopy = Support::wrapTag('<div class="qfq-line">', $htmlCopy);
-            $html .= $htmlCopy;
-        }
-
-        $this->feSpecNative = $feSpecNativeSave;
-
-        return $html;
-    }
-
     /**
      * Build a 'templateGroup'. Renders all assigned FormElements of the templateGroup.
      * If there are already vlaues for the formElements, fill as much copies as values exist
@@ -2497,6 +2450,77 @@ EOT;
 
     }
 
+    /**
+     * Build real FormElements based on the current templateGroup FormElements in $this->feSpecNative.
+     * Take a templateGroup 'copy', if at least one of the elements is filled with a non default value.
+     * Stop filling elements if there are no further elements filled.
+     *
+     * @param int $max
+     * @param string $htmlDelete
+     * @param array $json
+     * @return string
+     * @throws CodeException
+     * @throws \qfq\UserFormException
+     */
+    private function templateGroupCollectFilledElements($max, $htmlDelete, array &$json) {
+
+        $record = $this->store->getStore(STORE_RECORD); // current values
+        if ($record === false || count($record) === 0) {
+            return '';
+        }
+        $default = $this->store->getStore(STORE_TABLE_DEFAULT); // current defaults
+
+        $lastFilled = 0; // Marker if there is at least one element per copy who is filled.
+        $feSpecNativeCopy = array();
+        for ($ii = 1; $ii < $max; $ii++) {
+
+            // Per copy, iterate over all templateGroup FormElements
+            foreach ($this->feSpecNative as $fe) {
+
+                $columnName = str_replace(FE_TEMPLATE_GROUP_NAME_PATTERN, $ii, $fe[FE_NAME]);
+
+                $fe[FE_LABEL] = str_replace(FE_TEMPLATE_GROUP_NAME_PATTERN, $ii, $fe[FE_LABEL]);
+                $fe[FE_NOTE] = str_replace(FE_TEMPLATE_GROUP_NAME_PATTERN, $ii, $fe[FE_NOTE]);
+                if (isset($record[$columnName])) {
+                    if ($record[$columnName] != $default[$columnName]) {
+                        $lastFilled = $ii;
+                    }
+                } else {
+                    throw new UserFormException("Not implemented: templateGroup FormElement-columns not found in primary table.", ERROR_NOT_IMPLEMENTED);
+                }
+                $fe[FE_NAME] = $columnName;
+                $feSpecNativeCopy[$ii - 1][] = $fe; // Build array with current copy of templateGroup.
+            }
+
+            // Append $htmlDelete on the last element of all copies,, but not the first.
+            if ($ii > 1) {
+                // Count defined FormElements in the current templateGroup
+                $last = count($feSpecNativeCopy[$ii - 1]) - 1;
+                // Append 'delete' Button at the note of the last element
+                $feSpecNativeCopy[$ii - 1][$last][FE_NOTE] .= $htmlDelete;
+            }
+        }
+
+        // Nothing found: return
+        if (count($feSpecNativeCopy) == 0) {
+            return '';
+        }
+
+        $feSpecNativeSave = $this->feSpecNative;
+
+        $html = '';
+        for ($ii = 0; $ii < $lastFilled; $ii++) {
+            $this->feSpecNative = $feSpecNativeCopy[$ii];
+            $htmlCopy = $this->elements($this->store->getVar(SIP_RECORD_ID, STORE_SIP), FORM_ELEMENTS_NATIVE, 0, $json);
+            $htmlCopy = Support::wrapTag('<div class="qfq-line">', $htmlCopy);
+            $html .= $htmlCopy;
+        }
+
+        $this->feSpecNative = $feSpecNativeSave;
+
+        return $html;
+    }
+
     abstract public function buildRowNative(array $formElement, $htmlElement, $htmlFormElementId);
 
 
diff --git a/extension/qfq/qfq/Constants.php b/extension/qfq/qfq/Constants.php
index b52763028..3470e2e16 100644
--- a/extension/qfq/qfq/Constants.php
+++ b/extension/qfq/qfq/Constants.php
@@ -256,6 +256,7 @@ const CLIENT_UPLOAD_FE_NAME = 'name';
 
 const CLIENT_SIP_FOR_FORM = '_sipForForm';
 const CLIENT_FE_NAME = '_feName';
+const CLIENT_TYPO3VARS = '_sipForTypo3Vars';
 
 // ALL $_SERVER variables: http://php.net/manual/en/reserved.variables.server.php
 // The following exist and might be the most used ones.
@@ -277,6 +278,7 @@ const CLIENT_PHP_SELF = 'PHP_SELF';
 // T3 Bodytext Keywords
 const TYPO3_FORM = CLIENT_FORM;
 const TYPO3_RECORD_ID = CLIENT_RECORD_ID;
+const TYPO3_BE_USER_LOGGED_IN = 'beUser';   // 'yes' | 'no'
 const TYPO3_FE_USER = 'feUser';
 const TYPO3_FE_USER_UID = 'feUserUid';
 const TYPO3_FE_USER_GROUP = 'feUserGroup';
diff --git a/extension/qfq/qfq/QuickFormQuery.php b/extension/qfq/qfq/QuickFormQuery.php
index a7798036f..0d0d27719 100644
--- a/extension/qfq/qfq/QuickFormQuery.php
+++ b/extension/qfq/qfq/QuickFormQuery.php
@@ -668,7 +668,7 @@ class QuickFormQuery {
     private function fillStoreWithRecord($table, $recordId, $store = STORE_RECORD) {
         if ($recordId !== false && $recordId > 0) {
             $record = $this->db->sql("SELECT * FROM $table WHERE id = ?", ROW_EXPECT_1, [$recordId]);
-            $this->store->setVarArray($record, $store, true);
+            $this->store->setStore($record, $store, true);
         }
     }
 
@@ -688,7 +688,7 @@ class QuickFormQuery {
         }
 
         $sipArray[SIP_RECORD_ID] = $recordId;
-        $this->store->setVarArray($sipArray, STORE_SIP, true);
+        $this->store->setStore($sipArray, STORE_SIP, true);
 
         // Update SIP urlparam
         store::getSipInstance()->updateSipToSession($sipArray);
@@ -784,7 +784,7 @@ class QuickFormQuery {
 
         // Overwrite SIP Store
         $tmpParam[SIP_SIP] = $sip;
-        $this->store->setVarArray($tmpParam, STORE_SIP, true);
+        $this->store->setStore($tmpParam, STORE_SIP, true);
     }
 
 }
\ No newline at end of file
diff --git a/extension/qfq/qfq/Save.php b/extension/qfq/qfq/Save.php
index cebe79b3f..08270c6a1 100644
--- a/extension/qfq/qfq/Save.php
+++ b/extension/qfq/qfq/Save.php
@@ -60,7 +60,7 @@ class Save {
 
             $parentRecords = $this->db->sql($this->formSpec['multiSql']);
             foreach ($parentRecords as $row) {
-                $this->store->setVarArray($row, STORE_PARENT_RECORD, true);
+                $this->store->setStore($row, STORE_PARENT_RECORD, true);
                 $rc = $this->elements($row['_id']);
             }
         } else {
diff --git a/extension/qfq/qfq/form/FormAction.php b/extension/qfq/qfq/form/FormAction.php
index a43e2c217..774a8a4d5 100644
--- a/extension/qfq/qfq/form/FormAction.php
+++ b/extension/qfq/qfq/form/FormAction.php
@@ -129,7 +129,7 @@ class FormAction {
 
         if ($recordId !== false && $recordId > 0) {
             $record = $this->db->sql("SELECT * FROM $table WHERE id = ?", ROW_EXPECT_1, [$recordId]);
-            $this->store->setVarArray($record, STORE_RECORD, true);
+            $this->store->setStore($record, STORE_RECORD, true);
         }
     }
 
diff --git a/extension/qfq/qfq/store/FillStoreForm.php b/extension/qfq/qfq/store/FillStoreForm.php
index 824572a63..42a0907c2 100644
--- a/extension/qfq/qfq/store/FillStoreForm.php
+++ b/extension/qfq/qfq/store/FillStoreForm.php
@@ -48,6 +48,33 @@ class FillStoreForm {
 
     }
 
+    /**
+     * Loads a minimal definition of FormElement of the form specified in SIP.
+     *
+     * @return array
+     * @throws CodeException
+     * @throws DbException
+     * @throws UserFormException
+     */
+    private function loadFormElementsBasedOnSIP() {
+        $formName = $this->store->getVar(SIP_FORM, STORE_SIP);
+
+        // Preparation for Log, Debug
+        $this->store->setVar(SYSTEM_FORM, $formName, STORE_SYSTEM);
+
+        $feSpecNative = $this->db->sql(SQL_FORM_ELEMENT_SIMPLE_ALL_CONTAINER, ROW_EXPECT_GE_1, [$formName],
+            'Form or FormElements not found: ' . ERROR_FORM_NOT_FOUND);
+        HelperFormElement::explodeParameterInArrayElements($feSpecNative);
+
+        $feSpecTemplateGroup = $this->db->sql(SQL_FORM_ELEMENT_CONTAINER_TEMPLATE_GROUP, ROW_REGULAR, [$formName]);
+        HelperFormElement::explodeParameterInArrayElements($feSpecTemplateGroup);
+
+        $feSpecNative = $this->expandTemplateGroupFormElement($feSpecTemplateGroup, $feSpecNative);
+
+
+        return $feSpecNative;
+    }
+
     /**
      * Checks if there are templateGroups defined. If yes, expand them. Return expanded feSpecNative array.
      *
@@ -58,20 +85,20 @@ class FillStoreForm {
     private function expandTemplateGroupFormElement(array $feSpecTemplateGroup, array $feSpecNative) {
         $expanded = array();
 
-        if(count($feSpecTemplateGroup)==0) {
+        if (count($feSpecTemplateGroup) == 0) {
             return $feSpecNative; // No templateGroups >> nothing to do >> just return
         }
 
         // Iterate over all 'FormElements': part of a templateGroup?
-        foreach($feSpecNative as $fe) {
-            $flagCopied=false;
+        foreach ($feSpecNative as $fe) {
+            $flagCopied = false;
 
-            if($fe[FE_ID_CONTAINER]>0) {
+            if ($fe[FE_ID_CONTAINER] > 0) {
                 // Search for a corresponding template group.
                 foreach ($feSpecTemplateGroup as $templateGroup) {
                     if ($fe[FE_ID_CONTAINER] = $templateGroup[FE_ID]) {
 
-                        $flagCopied=true;
+                        $flagCopied = true;
 
                         // Get max copies per template group
                         $maxCopies = ($templateGroup[FE_MAX_LENGTH] == 0 || $templateGroup[FE_MAX_LENGTH] == '') ? FE_TEMPLATE_GROUP_DEFAULT_MAX_LENGTH : $templateGroup[FE_MAX_LENGTH];
@@ -86,7 +113,7 @@ class FillStoreForm {
                 }
             }
 
-            if(!$flagCopied) {
+            if (!$flagCopied) {
                 $expanded[] = $fe;
             }
         }
@@ -94,33 +121,6 @@ class FillStoreForm {
         return $expanded;
     }
 
-    /**
-     * Loads a minimal definition of FormElement of the form specified in SIP.
-     *
-     * @return array
-     * @throws CodeException
-     * @throws DbException
-     * @throws UserFormException
-     */
-    private function loadFormElementsBasedOnSIP() {
-        $formName = $this->store->getVar(SIP_FORM, STORE_SIP);
-
-        // Preparation for Log, Debug
-        $this->store->setVar(SYSTEM_FORM, $formName, STORE_SYSTEM);
-
-        $feSpecNative = $this->db->sql(SQL_FORM_ELEMENT_SIMPLE_ALL_CONTAINER, ROW_EXPECT_GE_1, [$formName],
-            'Form or FormElements not found: ' . ERROR_FORM_NOT_FOUND);
-        HelperFormElement::explodeParameterInArrayElements($feSpecNative);
-
-        $feSpecTemplateGroup = $this->db->sql(SQL_FORM_ELEMENT_CONTAINER_TEMPLATE_GROUP, ROW_REGULAR, [$formName]);
-        HelperFormElement::explodeParameterInArrayElements($feSpecTemplateGroup);
-
-        $feSpecNative = $this->expandTemplateGroupFormElement($feSpecTemplateGroup, $feSpecNative);
-
-
-        return $feSpecNative;
-    }
-
     /**
      * Copies all current form parameter from STORE_CLIENT to STORE_FORM. Checks the values against FormElement
      * definition and throws an exception if check fails. FormElements.type=hidden will be taken from STORE_SIP.
@@ -137,6 +137,11 @@ class FillStoreForm {
 
         $clientValues = $this->store->getStore(STORE_CLIENT);
 
+        // If called through 'api/...': get STORE_TYPO3 via SIP parameter.
+        if (isset($clientValues[CLIENT_TYPO3VARS])) {
+            $this->store->fillTypo3StoreFromSip($clientValues[CLIENT_TYPO3VARS]);
+        }
+
         // Retrieve SIP vars, e.g. for HIDDEN elements.
         $sipValues = $this->store->getStore(STORE_SIP);
 
@@ -161,7 +166,7 @@ class FillStoreForm {
         // no: regular situation, take real 'recordid'
         $fakeRecordId = isset($sipValues[SIP_MAKE_URLPARAM_UNIQ]) ? 0 : $sipValues[SIP_RECORD_ID];
 
-        // Iterate over all formelements. Sanatize values. Built an assoc array $newValues.
+        // Iterate over all FormElements. Sanatize values. Built an assoc array $newValues.
         foreach ($this->feSpecNative AS $formElement) {
 
             // Never get a predefined 'id'
@@ -228,7 +233,7 @@ class FillStoreForm {
             }
         }
 
-        $this->store->setVarArray($newValues, STORE_FORM, true);
+        $this->store->setStore($newValues, STORE_FORM, true);
     }
 
     /**
diff --git a/extension/qfq/qfq/store/Store.php b/extension/qfq/qfq/store/Store.php
index ea0c789a0..24dbd9ca1 100644
--- a/extension/qfq/qfq/store/Store.php
+++ b/extension/qfq/qfq/store/Store.php
@@ -81,6 +81,9 @@ class Store {
 
     /**
      * @param string $bodytext
+     * @param string $fileConfigIni
+     * @throws UserFormException
+     * @throws \qfq\CodeException
      */
     private function __construct($bodytext = '', $fileConfigIni = '') {
 
@@ -100,6 +103,7 @@ class Store {
 //            TYPO3_FE_USER_GROUP => SANITIZE_ALLOW_ALNUMX,
 
             CLIENT_SIP => SANITIZE_ALLOW_ALNUMX,
+            CLIENT_TYPO3VARS => SANITIZE_ALLOW_ALNUMX,
             CLIENT_RECORD_ID => SANITIZE_ALLOW_DIGIT,
             CLIENT_KEY_SEM_ID => SANITIZE_ALLOW_DIGIT,
             CLIENT_KEY_SEM_ID_USER => SANITIZE_ALLOW_DIGIT,
@@ -167,7 +171,6 @@ class Store {
         self::fillStoreClient();
         self::fillStoreSip();
         self::fillStoreExtra();
-
     }
 
     /**
@@ -212,7 +215,7 @@ class Store {
 
         self::checkMandatoryParameter($config);
 
-        self::setVarArray($config, STORE_SYSTEM, true);
+        self::setStore($config, STORE_SYSTEM, true);
     }
 
     /**
@@ -333,7 +336,7 @@ class Store {
      * @throws UserFormException
      * @throws \qfq\CodeException
      */
-    public static function setVarArray(array $dataArray, $store, $flagOverwrite = false) {
+    public static function setStore(array $dataArray, $store, $flagOverwrite = false) {
 
         // Check valid Storename
         if (!isset(self::$sanitizeStore))
@@ -394,15 +397,15 @@ class Store {
 
         } else {
 
-            // NO T3 environment (called by API): restore from SESSION
-            foreach([ SESSION_FE_USER, SESSION_FE_USER_UID, SESSION_FE_USER_GROUP ] as $key) {
+            // No T3 environment (called by API): restore from SESSION
+            foreach ([SESSION_FE_USER, SESSION_FE_USER_UID, SESSION_FE_USER_GROUP] as $key) {
                 if (isset($_SESSION[SESSION_NAME][$key])) {
                     $arr[$key] = $_SESSION[SESSION_NAME][$key];
                 }
             }
         }
 
-        self::setVarArray($arr, STORE_TYPO3, true);
+        self::setStore($arr, STORE_TYPO3, true);
     }
 
     /**
@@ -425,7 +428,7 @@ class Store {
 
         $arr = \qfq\Sanitize::normalize($arr);
 
-        self::setVarArray($arr, STORE_CLIENT, true);
+        self::setStore($arr, STORE_CLIENT, true);
 
     }
 
@@ -447,7 +450,7 @@ class Store {
             $param[SIP_URLPARAM] = self::$sip->getQueryStringFromSip($s);
 
 //            self::setVarArray(KeyValueStringParser::parse($param, "=", "&"), STORE_SIP);
-            self::setVarArray($param, STORE_SIP, true);
+            self::setStore($param, STORE_SIP, true);
         }
     }
 
@@ -530,9 +533,9 @@ class Store {
         }
 
         if ($value === false) {
-            self::setVarArray(array(), STORE_EXTRA, true);
+            self::setStore(array(), STORE_EXTRA, true);
         } else {
-            self::setVarArray($_SESSION[SESSION_NAME][STORE_EXTRA], STORE_EXTRA, true);
+            self::setStore($_SESSION[SESSION_NAME][STORE_EXTRA], STORE_EXTRA, true);
         }
     }
 
@@ -679,7 +682,7 @@ class Store {
 
         // Store in SIP Store (cause it's empty until now).
         $tmpParam[SIP_SIP] = $sip;
-        self::setVarArray($tmpParam, STORE_SIP, true);
+        self::setStore($tmpParam, STORE_SIP, true);
 
     }
 
@@ -713,6 +716,69 @@ class Store {
         return $tmpParam;
     }
 
+    /**
+     * Returns a pointer to this class.
+     *
+     * @return null|Sip
+     */
+    public static function getSipInstance() {
+        return self::$sip;
+    }
+
+    /**
+     * Fills STORE_TABLE_DEFAULT and STORE_TABLE_COLUMN_TYPES
+     *
+     * @param $tableName
+     * @throws CodeException
+     */
+    public static function fillStoreTableDefaultColumnType($tableName) {
+        $db = new qfq\Database();
+
+        $tableDefinition = $db->getTableDefinition($tableName);
+
+        self::setStore(array_column($tableDefinition, 'Default', 'Field'), STORE_TABLE_DEFAULT, true);
+        self::setStore(array_column($tableDefinition, 'Type', 'Field'), STORE_TABLE_COLUMN_TYPES, true);
+    }
+
+    /**
+     * @throws CodeException
+     * @throws UserFormException
+     */
+    public static function copyT3VarsToSip() {
+
+        $tempArray = self::getStore(STORE_TYPO3);
+
+        foreach ([TYPO3_FE_USER, TYPO3_FE_USER_UID, TYPO3_FE_USER_GROUP, TYPO3_TT_CONTENT_UID, TYPO3_PAGE_ID, TYPO3_PAGE_TYPE, TYPO3_PAGE_LANGUAGE, TYPO3_BE_USER_LOGGED_IN] as $key) {
+            if (isset($tempArray[$key])) {
+                $t3varsArray[$key] = $tempArray[$key];
+            }
+        }
+
+        $t3varsArray[TYPO3_BE_USER_LOGGED_IN] = (isset($GLOBALS["TSFE"]->beUserLogin) && $GLOBALS["TSFE"]->beUserLogin === true) ? 'yes' : 'no';
+
+        $t3varsString = KeyValueStringParser::unparse($t3varsArray, '=', '&');
+        $t3sip = self::$sip->queryStringToSip($t3varsString, RETURN_SIP);
+
+        return $t3sip;
+    }
+
+    /**
+     *
+     * @param string $sipTypo3Vars
+     */
+    public function fillTypo3StoreFromSip($sipTypo3Vars) {
+        $t3vars = self::getStore(STORE_TYPO3);
+
+        // Do nothing if STORE_TYPO3 is already filled
+        if (isset($t3vars[TYPO3_TT_CONTENT_UID]) && $t3vars[TYPO3_TT_CONTENT_UID] != '0') {
+            return;
+        }
+
+        $typo3VarsArray = self::$sip->getVarsFromSip($sipTypo3Vars);
+
+        self::setStore($typo3VarsArray, STORE_TYPO3, true);
+    }
+
     /**
      * Returns a complete $store.
      *
@@ -736,29 +802,6 @@ class Store {
         return array();
     }
 
-    /**
-     * Returns a pointer to this class.
-     *
-     * @return null|Sip
-     */
-    public static function getSipInstance() {
-        return self::$sip;
-    }
-
-    /**
-     * Fills STORE_TABLE_DEFAULT and STORE_TABLE_COLUMN_TYPES
-     *
-     * @param $tableName
-     * @throws CodeException
-     */
-    public static function fillStoreTableDefaultColumnType($tableName) {
-        $db = new qfq\Database();
-
-        $tableDefinition = $db->getTableDefinition($tableName);
-
-        self::setVarArray(array_column($tableDefinition, 'Default', 'Field'), STORE_TABLE_DEFAULT, true);
-        self::setVarArray(array_column($tableDefinition, 'Type', 'Field'), STORE_TABLE_COLUMN_TYPES, true);
-    }
 }
 
 
diff --git a/extension/qfq/tests/phpunit/StoreTest.php b/extension/qfq/tests/phpunit/StoreTest.php
index 0a3ceb9df..b15d25bbc 100644
--- a/extension/qfq/tests/phpunit/StoreTest.php
+++ b/extension/qfq/tests/phpunit/StoreTest.php
@@ -156,14 +156,14 @@ class StoreTest extends \PHPUnit_Framework_TestCase {
     public function testUnsetStore() {
         $this->store->unsetStore(STORE_RECORD);
 
-        $this->store->setVarArray(array(), STORE_RECORD);
+        $this->store->setStore(array(), STORE_RECORD);
         $this->assertEquals(false, $this->store->getVar('apple', STORE_RECORD), "Retrieve a value from store.");
     }
 
     public function testSetVarArray() {
         $this->store->unsetStore(STORE_RECORD);
         $arr = ['a' => '1', 'apple' => 'green'];
-        $this->store->setVarArray($arr, STORE_RECORD);
+        $this->store->setStore($arr, STORE_RECORD);
         $this->assertEquals('1', $this->store->getVar('a', STORE_RECORD), "Retrieve a value from store 'fake'");
         $this->assertEquals('green', $this->store->getVar('apple', STORE_RECORD), "Retrieve a value from store.");
     }
@@ -172,7 +172,7 @@ class StoreTest extends \PHPUnit_Framework_TestCase {
     public function testSetVarArrayEmpty() {
         $this->store->unsetStore(STORE_RECORD);
         $arr = array();
-        $this->store->setVarArray($arr, STORE_RECORD);
+        $this->store->setStore($arr, STORE_RECORD);
         $this->assertEquals(false, $this->store->getVar('apple', STORE_RECORD), "Retrieve a value from store.");
     }
 
-- 
GitLab