/** * Handler for Flex Forms * * @param string $table The table name of the record * @param string $field The field name of the flexform field to work on * @param array $row The record data array * @param object $callBackObj Object in which the call back function is located * @param string $callBackMethod_value Method name of call back function in object for values * @return bool|string If TRUE, error happened (error string returned) */ public function traverseFlexFormXMLData($table, $field, $row, $callBackObj, $callBackMethod_value) { if (!is_array($GLOBALS['TCA'][$table]) || !is_array($GLOBALS['TCA'][$table]['columns'][$field])) { return 'TCA table/field was not defined.'; } $this->callBackObj = $callBackObj; // Get Data Structure: $dataStructArray = BackendUtility::getFlexFormDS($GLOBALS['TCA'][$table]['columns'][$field]['config'], $row, $table, $field); // If data structure was ok, proceed: if (is_array($dataStructArray)) { // Get flexform XML data: $xmlData = $row[$field]; // Convert charset: if ($this->convertCharset) { $xmlHeaderAttributes = GeneralUtility::xmlGetHeaderAttribs($xmlData); $storeInCharset = strtolower($xmlHeaderAttributes['encoding']); if ($storeInCharset) { $currentCharset = $GLOBALS['LANG']->charSet; $xmlData = $GLOBALS['LANG']->csConvObj->conv($xmlData, $storeInCharset, $currentCharset, 1); } } $editData = GeneralUtility::xml2array($xmlData); if (!is_array($editData)) { return 'Parsing error: ' . $editData; } // Tabs sheets if (is_array($dataStructArray['sheets'])) { $sKeys = array_keys($dataStructArray['sheets']); } else { $sKeys = array('sDEF'); } // Traverse languages: foreach ($sKeys as $sheet) { list($dataStruct, $sheet) = GeneralUtility::resolveSheetDefInDS($dataStructArray, $sheet); // Render sheet: if (is_array($dataStruct['ROOT']) && is_array($dataStruct['ROOT']['el'])) { $PA['vKeys'] = array('DEF'); $PA['lKey'] = 'lDEF'; $PA['callBackMethod_value'] = $callBackMethod_value; $PA['table'] = $table; $PA['field'] = $field; $PA['uid'] = $row['uid']; $this->traverseFlexFormXMLData_DS =& $dataStruct; $this->traverseFlexFormXMLData_Data =& $editData; // Render flexform: $this->traverseFlexFormXMLData_recurse($dataStruct['ROOT']['el'], $editData['data'][$sheet]['lDEF'], $PA, 'data/' . $sheet . '/lDEF'); } else { return 'Data Structure ERROR: No ROOT element found for sheet "' . $sheet . '".'; } } } else { return 'Data Structure ERROR: ' . $dataStructArray; } }
/** * Entry method * * @return array As defined in initializeResultArray() of AbstractNode */ public function render() { $languageService = $this->getLanguageService(); $table = $this->globalOptions['table']; $row = $this->globalOptions['databaseRow']; $field = $this->globalOptions['fieldName']; $parameterArray = $this->globalOptions['parameterArray']; // Data Structure $flexFormDataStructureArray = BackendUtility::getFlexFormDS($parameterArray['fieldConf']['config'], $row, $table, $field); // Early return if no data structure was found at all if (!is_array($flexFormDataStructureArray)) { $resultArray = $this->initializeResultArray(); $resultArray['html'] = 'Data Structure ERROR: ' . $flexFormDataStructureArray; return $resultArray; } // Manipulate Flex form DS via TSConfig and group access lists if (is_array($flexFormDataStructureArray)) { $flexFormHelper = GeneralUtility::makeInstance(FlexFormsHelper::class); $flexFormDataStructureArray = $flexFormHelper->modifyFlexFormDS($flexFormDataStructureArray, $table, $field, $row, $parameterArray['fieldConf']); } // Get data $xmlData = $parameterArray['itemFormElValue']; $xmlHeaderAttributes = GeneralUtility::xmlGetHeaderAttribs($xmlData); $storeInCharset = strtolower($xmlHeaderAttributes['encoding']); if ($storeInCharset) { $currentCharset = $languageService->charSet; $xmlData = $languageService->csConvObj->conv($xmlData, $storeInCharset, $currentCharset, 1); } $flexFormRowData = GeneralUtility::xml2array($xmlData); // Must be XML parsing error... if (!is_array($flexFormRowData)) { $flexFormRowData = array(); } elseif (!isset($flexFormRowData['meta']) || !is_array($flexFormRowData['meta'])) { $flexFormRowData['meta'] = array(); } $options = $this->globalOptions; $options['flexFormDataStructureArray'] = $flexFormDataStructureArray; $options['flexFormRowData'] = $flexFormRowData; $options['renderType'] = 'flexFormLanguageContainer'; /** @var NodeFactory $nodeFactory */ $nodeFactory = $this->globalOptions['nodeFactory']; return $nodeFactory->create($options)->render(); }
/** * Fetch / initialize data structure. * * The sub array with different possible data structures in ['config']['ds'] is * resolved here, ds array contains only the one resolved data structure after this method. * * @param array $result Result array * @param string $fieldName Currently handled field name * @return array Modified result * @throws \UnexpectedValueException */ protected function initializeDataStructure(array $result, $fieldName) { // Fetch / initialize data structure $dataStructureArray = BackendUtility::getFlexFormDS($result['processedTca']['columns'][$fieldName]['config'], $result['databaseRow'], $result['tableName'], $fieldName); // If data structure can't be parsed, this is a developer error, so throw a non catchable exception if (!is_array($dataStructureArray)) { throw new \UnexpectedValueException('Data structure error: ' . $dataStructureArray, 1440506893); } if (!isset($dataStructureArray['meta']) || !is_array($dataStructureArray['meta'])) { $dataStructureArray['meta'] = array(); } // This kicks one array depth: config['ds']['matchingIdentifier'] becomes config['ds'] $result['processedTca']['columns'][$fieldName]['config']['ds'] = $dataStructureArray; return $result; }
/** * Processing of soft references * * @return void */ public function processSoftReferences() { // Initialize: $inData = array(); // Traverse records: if (is_array($this->dat['header']['records'])) { foreach ($this->dat['header']['records'] as $table => $recs) { foreach ($recs as $uid => $thisRec) { // If there are soft references defined, traverse those: if (isset($GLOBALS['TCA'][$table]) && is_array($thisRec['softrefs'])) { // First traversal is to collect softref configuration and split them up based on fields. // This could probably also have been done with the "records" key instead of the header. $fieldsIndex = array(); foreach ($thisRec['softrefs'] as $softrefDef) { // If a substitution token is set: if ($softrefDef['field'] && is_array($softrefDef['subst']) && $softrefDef['subst']['tokenID']) { $fieldsIndex[$softrefDef['field']][$softrefDef['subst']['tokenID']] = $softrefDef; } } // The new id: $thisNewUid = BackendUtility::wsMapId($table, $this->import_mapId[$table][$uid]); // Now, if there are any fields that require substitution to be done, lets go for that: foreach ($fieldsIndex as $field => $softRefCfgs) { if (is_array($GLOBALS['TCA'][$table]['columns'][$field])) { $conf = $GLOBALS['TCA'][$table]['columns'][$field]['config']; if ($conf['type'] === 'flex') { // This will fetch the new row for the element (which should be updated with any references to data structures etc.) $origRecordRow = BackendUtility::getRecord($table, $thisNewUid, '*'); if (is_array($origRecordRow)) { // Get current data structure and value array: $dataStructArray = BackendUtility::getFlexFormDS($conf, $origRecordRow, $table, $field); $currentValueArray = GeneralUtility::xml2array($origRecordRow[$field]); // Do recursive processing of the XML data: /** @var $iteratorObj DataHandler */ $iteratorObj = GeneralUtility::makeInstance(DataHandler::class); $iteratorObj->callBackObj = $this; $currentValueArray['data'] = $iteratorObj->checkValue_flex_procInData($currentValueArray['data'], array(), array(), $dataStructArray, array($table, $uid, $field, $softRefCfgs), 'processSoftReferences_flexFormCallBack'); // The return value is set as an array which means it will be processed by tcemain for file and DB references! if (is_array($currentValueArray['data'])) { $inData[$table][$thisNewUid][$field] = $currentValueArray; } } } else { // Get tokenizedContent string and proceed only if that is not blank: $tokenizedContent = $this->dat['records'][$table . ':' . $uid]['rels'][$field]['softrefs']['tokenizedContent']; if (strlen($tokenizedContent) && is_array($softRefCfgs)) { $inData[$table][$thisNewUid][$field] = $this->processSoftReferences_substTokens($tokenizedContent, $softRefCfgs, $table, $uid); } } } } } } } } // Now write to database: $tce = $this->getNewTCE(); $tce->isImporting = true; $this->callHook('before_processSoftReferences', array('tce' => $tce, 'data' => &$inData)); $tce->enableLogging = true; $tce->start($inData, array()); $tce->process_datamap(); $this->callHook('after_processSoftReferences', array('tce' => $tce)); }
/** * Ajax handler for the "suggest" feature in TCEforms. * * @param array $params The parameters from the AJAX call * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj The AJAX object representing the AJAX call * @return void */ public function processAjaxRequest($params, &$ajaxObj) { // Get parameters from $_GET/$_POST $search = GeneralUtility::_GP('value'); $table = GeneralUtility::_GP('table'); $field = GeneralUtility::_GP('field'); $uid = GeneralUtility::_GP('uid'); $pageId = GeneralUtility::_GP('pid'); $newRecordRow = GeneralUtility::_GP('newRecordRow'); // If the $uid is numeric, we have an already existing element, so get the // TSconfig of the page itself or the element container (for non-page elements) // otherwise it's a new element, so use given id of parent page (i.e., don't modify it here) $row = NULL; if (is_numeric($uid)) { $row = BackendUtility::getRecord($table, $uid); if ($table == 'pages') { $pageId = $uid; } else { $pageId = $row['pid']; } } else { $row = unserialize($newRecordRow); } $TSconfig = BackendUtility::getPagesTSconfig($pageId); $queryTables = array(); $foreign_table_where = ''; $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$field]['config']; $parts = explode('|', $field); if ($GLOBALS['TCA'][$table]['columns'][$parts[0]]['config']['type'] === 'flex') { $flexfieldTCAConfig = $GLOBALS['TCA'][$table]['columns'][$parts[0]]['config']; $flexformDSArray = BackendUtility::getFlexFormDS($flexfieldTCAConfig, $row, $table, $parts[0]); $flexformDSArray = GeneralUtility::resolveAllSheetsInDS($flexformDSArray); $flexformElement = $parts[count($parts) - 2]; $continue = TRUE; foreach ($flexformDSArray as $sheet) { foreach ($sheet as $dataStructure) { $fieldConfig = $this->getNestedDsFieldConfig($dataStructure, $flexformElement); if (!empty($fieldConfig)) { $continue = FALSE; break; } } if (!$continue) { break; } } $field = str_replace('|', '][', $field); } $wizardConfig = $fieldConfig['wizards']['suggest']; if (isset($fieldConfig['allowed'])) { if ($fieldConfig['allowed'] === '*') { foreach ($GLOBALS['TCA'] as $tableName => $tableConfig) { // @todo Refactor function to BackendUtility if (empty($tableConfig['ctrl']['hideTable']) && ($GLOBALS['BE_USER']->isAdmin() || empty($tableConfig['ctrl']['adminOnly']) && (empty($tableConfig['ctrl']['rootLevel']) || !empty($tableConfig['ctrl']['security']['ignoreRootLevelRestriction'])))) { $queryTables[] = $tableName; } } unset($tableName, $tableConfig); } else { $queryTables = GeneralUtility::trimExplode(',', $fieldConfig['allowed']); } } elseif (isset($fieldConfig['foreign_table'])) { $queryTables = array($fieldConfig['foreign_table']); $foreign_table_where = $fieldConfig['foreign_table_where']; // strip ORDER BY clause $foreign_table_where = trim(preg_replace('/ORDER[[:space:]]+BY.*/i', '', $foreign_table_where)); } $resultRows = array(); // fetch the records for each query table. A query table is a table from which records are allowed to // be added to the TCEForm selector, originally fetched from the "allowed" config option in the TCA foreach ($queryTables as $queryTable) { // if the table does not exist, skip it if (!is_array($GLOBALS['TCA'][$queryTable]) || empty($GLOBALS['TCA'][$queryTable])) { continue; } $config = (array) $wizardConfig['default']; if (is_array($wizardConfig[$queryTable])) { \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($config, $wizardConfig[$queryTable]); } // merge the configurations of different "levels" to get the working configuration for this table and // field (i.e., go from the most general to the most special configuration) if (is_array($TSconfig['TCEFORM.']['suggest.']['default.'])) { \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($config, $TSconfig['TCEFORM.']['suggest.']['default.']); } if (is_array($TSconfig['TCEFORM.']['suggest.'][$queryTable . '.'])) { \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($config, $TSconfig['TCEFORM.']['suggest.'][$queryTable . '.']); } // use $table instead of $queryTable here because we overlay a config // for the input-field here, not for the queried table if (is_array($TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.']['default.'])) { \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($config, $TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.']['default.']); } if (is_array($TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.'][$queryTable . '.'])) { \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($config, $TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.'][$queryTable . '.']); } //process addWhere if (!isset($config['addWhere']) && $foreign_table_where) { $config['addWhere'] = $foreign_table_where; } if (isset($config['addWhere'])) { $replacement = array('###THIS_UID###' => (int) $uid, '###CURRENT_PID###' => (int) $pageId); if (isset($TSconfig['TCEFORM.'][$table . '.'][$field . '.'])) { $fieldTSconfig = $TSconfig['TCEFORM.'][$table . '.'][$field . '.']; if (isset($fieldTSconfig['PAGE_TSCONFIG_ID'])) { $replacement['###PAGE_TSCONFIG_ID###'] = (int) $fieldTSconfig['PAGE_TSCONFIG_ID']; } if (isset($fieldTSconfig['PAGE_TSCONFIG_IDLIST'])) { $replacement['###PAGE_TSCONFIG_IDLIST###'] = $GLOBALS['TYPO3_DB']->cleanIntList($fieldTSconfig['PAGE_TSCONFIG_IDLIST']); } if (isset($fieldTSconfig['PAGE_TSCONFIG_STR'])) { $replacement['###PAGE_TSCONFIG_STR###'] = $GLOBALS['TYPO3_DB']->quoteStr($fieldTSconfig['PAGE_TSCONFIG_STR'], $fieldConfig['foreign_table']); } } $config['addWhere'] = strtr(' ' . $config['addWhere'], $replacement); } // instantiate the class that should fetch the records for this $queryTable $receiverClassName = $config['receiverClass']; if (!class_exists($receiverClassName)) { $receiverClassName = SuggestWizardDefaultReceiver::class; } $receiverObj = GeneralUtility::makeInstance($receiverClassName, $queryTable, $config); $params = array('value' => $search); $rows = $receiverObj->queryTable($params); if (empty($rows)) { continue; } $resultRows = $rows + $resultRows; unset($rows); } $listItems = array(); if (!empty($resultRows)) { // traverse all found records and sort them $rowsSort = array(); foreach ($resultRows as $key => $row) { $rowsSort[$key] = $row['text']; } asort($rowsSort); $rowsSort = array_keys($rowsSort); // Limit the number of items in the result list $maxItems = $config['maxItemsInResultList'] ?: 10; $maxItems = min(count($resultRows), $maxItems); // put together the selector entry for ($i = 0; $i < $maxItems; $i++) { $row = $resultRows[$rowsSort[$i]]; $rowId = $row['table'] . '-' . $row['uid'] . '-' . $table . '-' . $uid . '-' . $field; $listItems[] = '<li' . ($row['class'] != '' ? ' class="' . $row['class'] . '"' : '') . ' id="' . $rowId . '"' . ($row['style'] != '' ? ' style="' . $row['style'] . '"' : '') . '>' . $row['sprite'] . $row['text'] . '</li>'; } } if (!empty($listItems)) { $list = implode('', $listItems); } else { $list = '<li class="suggest-noresults"><i>' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.noRecordFound') . '</i></li>'; } $list = '<ul class="' . $this->cssClass . '-resultlist">' . $list . '</ul>'; $ajaxObj->addContent(0, $list); }
/** * Checks if the query comes from a Flexform element and if yes, resolves the field configuration from the Flexform * data structure. * * @param string $table * @param string &$field The field identifier, either a simple table field or a Flexform field path separated with | * @param array $row The row we're dealing with; optional (only required for Flexform records) * @param array|NULL &$fieldConfig */ protected function overrideFieldNameAndConfigurationForFlexform($table, &$field, array $row, &$fieldConfig) { // check if field is a flexform reference if (strpos($field, '|') === false) { $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$field]['config']; } else { $parts = explode('|', $field); if ($GLOBALS['TCA'][$table]['columns'][$parts[0]]['config']['type'] !== 'flex') { return; } $flexfieldTCAConfig = $GLOBALS['TCA'][$table]['columns'][$parts[0]]['config']; // @todo: should be done via data preparation, resolveAllSheetsInDS() can be deprecated then $flexformDSArray = BackendUtility::getFlexFormDS($flexfieldTCAConfig, $row, $table, $parts[0]); $flexformDSArray = GeneralUtility::resolveAllSheetsInDS($flexformDSArray); $flexformElement = $parts[count($parts) - 2]; $continue = true; foreach ($flexformDSArray as $sheet) { foreach ($sheet as $_ => $dataStructure) { $fieldConfig = $this->getNestedDsFieldConfig($dataStructure, $flexformElement); if (!empty($fieldConfig)) { $continue = false; break; } } if (!$continue) { break; } } // Flexform field name levels are separated with | instead of encapsulation in []; // reverse this here to be compatible with regular field names. $field = str_replace('|', '][', $field); } }
/** * Processes the fields with references as registered during the copy process. This includes all FlexForm fields which had references. * * @return void */ public function remapListedDBRecords() { if (!empty($this->registerDBList)) { foreach ($this->registerDBList as $table => $records) { foreach ($records as $uid => $fields) { $newData = array(); $theUidToUpdate = $this->copyMappingArray_merged[$table][$uid]; $theUidToUpdate_saveTo = BackendUtility::wsMapId($table, $theUidToUpdate); foreach ($fields as $fieldName => $value) { $conf = $GLOBALS['TCA'][$table]['columns'][$fieldName]['config']; switch ($conf['type']) { case 'group': case 'select': $vArray = $this->remapListedDBRecords_procDBRefs($conf, $value, $theUidToUpdate, $table); if (is_array($vArray)) { $newData[$fieldName] = implode(',', $vArray); } break; case 'flex': if ($value == 'FlexForm_reference') { // This will fetch the new row for the element $origRecordRow = $this->recordInfo($table, $theUidToUpdate, '*'); if (is_array($origRecordRow)) { BackendUtility::workspaceOL($table, $origRecordRow); // Get current data structure and value array: $dataStructArray = BackendUtility::getFlexFormDS($conf, $origRecordRow, $table, $fieldName); $currentValueArray = GeneralUtility::xml2array($origRecordRow[$fieldName]); // Do recursive processing of the XML data: $currentValueArray['data'] = $this->checkValue_flex_procInData($currentValueArray['data'], array(), array(), $dataStructArray, array($table, $theUidToUpdate, $fieldName), 'remapListedDBRecords_flexFormCallBack'); // The return value should be compiled back into XML, ready to insert directly in the field (as we call updateDB() directly later): if (is_array($currentValueArray['data'])) { $newData[$fieldName] = $this->checkValue_flexArray2Xml($currentValueArray, true); } } } break; case 'inline': $this->remapListedDBRecords_procInline($conf, $value, $uid, $table); break; default: debug('Field type should not appear here: ' . $conf['type']); } } // If any fields were changed, those fields are updated! if (!empty($newData)) { $this->updateDB($table, $theUidToUpdate_saveTo, $newData); } } } } }
/** * Handler for Flex Forms * * @param string $table The table name of the record * @param string $field The field name which this element is supposed to edit * @param array $row The record data array where the value(s) for the field can be found * @param array $PA An array with additional configuration options. * @return string The HTML code for the TCEform field * @todo Define visibility */ public function getSingleField_typeFlex($table, $field, $row, &$PA) { // Data Structure: $dataStructArray = BackendUtility::getFlexFormDS($PA['fieldConf']['config'], $row, $table, $field); $item = ''; // Manipulate Flexform DS via TSConfig and group access lists if (is_array($dataStructArray)) { $flexFormHelper = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\FlexFormsHelper'); $dataStructArray = $flexFormHelper->modifyFlexFormDS($dataStructArray, $table, $field, $row, $PA['fieldConf']); unset($flexFormHelper); } // Get data structure: if (is_array($dataStructArray)) { // Get data: $xmlData = $PA['itemFormElValue']; $xmlHeaderAttributes = GeneralUtility::xmlGetHeaderAttribs($xmlData); $storeInCharset = strtolower($xmlHeaderAttributes['encoding']); if ($storeInCharset) { $currentCharset = $this->getLanguageService()->charSet; $xmlData = $this->getLanguageService()->csConvObj->conv($xmlData, $storeInCharset, $currentCharset, 1); } $editData = GeneralUtility::xml2array($xmlData); // Must be XML parsing error... if (!is_array($editData)) { $editData = array(); } elseif (!isset($editData['meta']) || !is_array($editData['meta'])) { $editData['meta'] = array(); } // Find the data structure if sheets are found: $sheet = $editData['meta']['currentSheetId'] ? $editData['meta']['currentSheetId'] : 'sDEF'; // Sheet to display // Create language menu: $langChildren = $dataStructArray['meta']['langChildren'] ? 1 : 0; $langDisabled = $dataStructArray['meta']['langDisable'] ? 1 : 0; $editData['meta']['currentLangId'] = array(); // Look up page overlays: $checkPageLanguageOverlay = $this->getBackendUserAuthentication()->getTSConfigVal('options.checkPageLanguageOverlay') ? TRUE : FALSE; if ($checkPageLanguageOverlay) { $where_clause = 'pid=' . (int) $row['pid'] . BackendUtility::deleteClause('pages_language_overlay') . BackendUtility::versioningPlaceholderClause('pages_language_overlay'); $pageOverlays = $this->getDatabaseConnection()->exec_SELECTgetRows('*', 'pages_language_overlay', $where_clause, '', '', '', 'sys_language_uid'); } $languages = $this->getAvailableLanguages(); foreach ($languages as $lInfo) { if ($this->getBackendUserAuthentication()->checkLanguageAccess($lInfo['uid']) && (!$checkPageLanguageOverlay || $lInfo['uid'] <= 0 || is_array($pageOverlays[$lInfo['uid']]))) { $editData['meta']['currentLangId'][] = $lInfo['ISOcode']; } } if (!is_array($editData['meta']['currentLangId']) || !count($editData['meta']['currentLangId'])) { $editData['meta']['currentLangId'] = array('DEF'); } $editData['meta']['currentLangId'] = array_unique($editData['meta']['currentLangId']); $PA['_noEditDEF'] = FALSE; if ($langChildren || $langDisabled) { $rotateLang = array('DEF'); } else { if (!in_array('DEF', $editData['meta']['currentLangId'])) { array_unshift($editData['meta']['currentLangId'], 'DEF'); $PA['_noEditDEF'] = TRUE; } $rotateLang = $editData['meta']['currentLangId']; } // Tabs sheets if (is_array($dataStructArray['sheets'])) { $tabsToTraverse = array_keys($dataStructArray['sheets']); } else { $tabsToTraverse = array($sheet); } /** @var $elementConditionMatcher \TYPO3\CMS\Backend\Form\ElementConditionMatcher */ $elementConditionMatcher = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\ElementConditionMatcher'); foreach ($rotateLang as $lKey) { if (!$langChildren && !$langDisabled) { $item .= '<strong>' . $this->getLanguageIcon($table, $row, 'v' . $lKey) . $lKey . ':</strong>'; } // Default language, other options are "lUK" or whatever country code (independent of system!!!) $lang = 'l' . $lKey; $tabParts = array(); $sheetContent = ''; foreach ($tabsToTraverse as $sheet) { list($dataStruct, $sheet) = GeneralUtility::resolveSheetDefInDS($dataStructArray, $sheet); // If sheet has displayCond if ($dataStruct['ROOT']['TCEforms']['displayCond']) { $splitCondition = GeneralUtility::trimExplode(':', $dataStruct['ROOT']['TCEforms']['displayCond']); $skipCondition = FALSE; $fakeRow = array(); switch ($splitCondition[0]) { case 'FIELD': list($sheetName, $fieldName) = GeneralUtility::trimExplode('.', $splitCondition[1]); $fieldValue = $editData['data'][$sheetName][$lang][$fieldName]; $splitCondition[1] = $fieldName; $dataStruct['ROOT']['TCEforms']['displayCond'] = join(':', $splitCondition); $fakeRow = array($fieldName => $fieldValue); break; case 'HIDE_FOR_NON_ADMINS': case 'VERSION': case 'HIDE_L10N_SIBLINGS': case 'EXT': break; case 'REC': $fakeRow = array('uid' => $row['uid']); break; default: $skipCondition = TRUE; } $displayConditionResult = TRUE; if ($dataStruct['ROOT']['TCEforms']['displayCond']) { $displayConditionResult = $elementConditionMatcher->match($dataStruct['ROOT']['TCEforms']['displayCond'], $fakeRow, 'vDEF'); } // If sheets displayCond leads to false if (!$skipCondition && !$displayConditionResult) { // Don't create this sheet continue; } } // Render sheet: if (is_array($dataStruct['ROOT']) && is_array($dataStruct['ROOT']['el'])) { // Default language, other options are "lUK" or whatever country code (independent of system!!!) $PA['_valLang'] = $langChildren && !$langDisabled ? $editData['meta']['currentLangId'] : 'DEF'; $PA['_lang'] = $lang; // Assemble key for loading the correct CSH file $dsPointerFields = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['columns'][$field]['config']['ds_pointerField'], TRUE); $PA['_cshKey'] = $table . '.' . $field; foreach ($dsPointerFields as $key) { $PA['_cshKey'] .= '.' . $row[$key]; } // Push the sheet level tab to DynNestedStack $tabIdentString = ''; if (is_array($dataStructArray['sheets'])) { $tabIdentString = $this->getDocumentTemplate()->getDynTabMenuId('TCEFORMS:flexform:' . $PA['itemFormElName'] . $PA['_lang']); $this->pushToDynNestedStack('tab', $tabIdentString . '-' . (count($tabParts) + 1)); } // Render flexform: $tRows = $this->getSingleField_typeFlex_draw($dataStruct['ROOT']['el'], $editData['data'][$sheet][$lang], $table, $field, $row, $PA, '[data][' . $sheet . '][' . $lang . ']'); $sheetContent = '<div class="typo3-TCEforms-flexForm">' . $tRows . '</div>'; // Pop the sheet level tab from DynNestedStack if (is_array($dataStructArray['sheets'])) { $this->popFromDynNestedStack('tab', $tabIdentString . '-' . (count($tabParts) + 1)); } } else { $sheetContent = 'Data Structure ERROR: No ROOT element found for sheet "' . $sheet . '".'; } // Add to tab: $tabParts[] = array('label' => $dataStruct['ROOT']['TCEforms']['sheetTitle'] ? $this->sL($dataStruct['ROOT']['TCEforms']['sheetTitle']) : $sheet, 'description' => $dataStruct['ROOT']['TCEforms']['sheetDescription'] ? $this->sL($dataStruct['ROOT']['TCEforms']['sheetDescription']) : '', 'linkTitle' => $dataStruct['ROOT']['TCEforms']['sheetShortDescr'] ? $this->sL($dataStruct['ROOT']['TCEforms']['sheetShortDescr']) : '', 'content' => $sheetContent); } if (is_array($dataStructArray['sheets'])) { $dividersToTabsBehaviour = isset($GLOBALS['TCA'][$table]['ctrl']['dividers2tabs']) ? $GLOBALS['TCA'][$table]['ctrl']['dividers2tabs'] : 1; $item .= $this->getDynTabMenu($tabParts, 'TCEFORMS:flexform:' . $PA['itemFormElName'] . $PA['_lang'], $dividersToTabsBehaviour); } else { $item .= $sheetContent; } } } else { $item = 'Data Structure ERROR: ' . $dataStructArray; } return $item; }
/** * Checks if the query comes from a Flexform element and if yes, resolves the field configuration from the Flexform * data structure. * * @param string $table * @param string &$field The field identifier, either a simple table field or a Flexform field path separated with | * @param array $row The row we're dealing with; optional (only required for Flexform records) * @param array|NULL &$fieldConfig */ protected function overrideFieldNameAndConfigurationForFlexform($table, &$field, array $row, &$fieldConfig) { // check if field is a flexform reference if (strpos($field, '|') === false) { $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$field]['config']; } else { $parts = explode('|', $field); if ($GLOBALS['TCA'][$table]['columns'][$parts[0]]['config']['type'] !== 'flex') { return; } $flexfieldTCAConfig = $GLOBALS['TCA'][$table]['columns'][$parts[0]]['config']; // @todo: should be done via data preparation, resolveAllSheetsInDS() can be deprecated then if (substr($row['uid'], 0, 3) === 'NEW') { // We have to cleanup record information as they are coming from FormEngines DataProvider $pointerFields = GeneralUtility::trimExplode(',', $flexfieldTCAConfig['ds_pointerField']); foreach ($pointerFields as $pointerField) { if (is_array($row[$pointerField])) { $row[$pointerField] = $row[$pointerField][0]; } } } $flexformDSArray = BackendUtility::getFlexFormDS($flexfieldTCAConfig, $row, $table, $parts[0]); $flexformDSArray = GeneralUtility::resolveAllSheetsInDS($flexformDSArray); $fieldConfig = $this->getFieldConfiguration($parts, $flexformDSArray); // Flexform field name levels are separated with | instead of encapsulation in []; // reverse this here to be compatible with regular field names. $field = str_replace('|', '][', $field); } }
/** * Processing of the data value in case the field type is "flex" * MUST NOT be called in case of already INSIDE a flexform! * * @param string $data The field value * @param array $fieldConfig CA field config * @param array $TSconfig TCEform TSconfig for the record * @param string $table Table name * @param array $row The row * @param string $field Field name * @return string The processed input field value ($data) * @access private * @see renderRecord() */ public function renderRecord_flexProc($data, $fieldConfig, $TSconfig, $table, $row, $field) { // Convert the XML data to PHP array: if (!is_array($data)) { $currentValueArray = GeneralUtility::xml2array($data); } else { $currentValueArray = $data; } if (is_array($currentValueArray)) { // Get current value array: $dataStructArray = BackendUtility::getFlexFormDS($fieldConfig['config'], $row, $table, $field); // Manipulate Flexform DS via TSConfig and group access lists if (is_array($dataStructArray)) { $flexFormHelper = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Form\FlexFormsHelper::class); $dataStructArray = $flexFormHelper->modifyFlexFormDS($dataStructArray, $table, $field, $row, $fieldConfig); unset($flexFormHelper); } if (is_array($dataStructArray)) { $currentValueArray['data'] = $this->renderRecord_flexProc_procInData($currentValueArray['data'], $dataStructArray, array($data, $fieldConfig, $TSconfig, $table, $row, $field)); $flexObj = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools::class); $data = $flexObj->flexArray2Xml($currentValueArray, TRUE); } } return $data; }
/** * Returns relation information for a $table/$row-array * Traverses all fields in input row which are configured in TCA/columns * It looks for hard relations to files and records in the TCA types "select" and "group" * * @param string $table Table name * @param array $row Row from table * @param string $onlyField Specific field to fetch for. * @return array Array with information about relations * @see export_addRecord() * @todo Define visibility */ public function getRelations($table, $row, $onlyField = '') { // Initialize: $uid = $row['uid']; $nonFields = explode(',', 'uid,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,pid'); $outRow = array(); foreach ($row as $field => $value) { if (!in_array($field, $nonFields) && is_array($GLOBALS['TCA'][$table]['columns'][$field]) && (!$onlyField || $onlyField === $field)) { $conf = $GLOBALS['TCA'][$table]['columns'][$field]['config']; // Add files $resultsFromFiles = $this->getRelations_procFiles($value, $conf, $uid); if (!empty($resultsFromFiles)) { // We have to fill different arrays here depending on the result. // internal_type file is still a relation of type file and // since http://forge.typo3.org/issues/49538 internal_type file_reference // is a database relation to a sys_file record $fileResultsFromFiles = array(); $dbResultsFromFiles = array(); foreach ($resultsFromFiles as $resultFromFiles) { if (isset($resultFromFiles['table']) && $resultFromFiles['table'] === 'sys_file') { $dbResultsFromFiles[] = $resultFromFiles; } else { // Creates an entry for the field with all the files: $fileResultsFromFiles[] = $resultFromFiles; } } if (!empty($fileResultsFromFiles)) { $outRow[$field] = array('type' => 'file', 'newValueFiles' => $fileResultsFromFiles); } if (!empty($dbResultsFromFiles)) { $outRow[$field] = array('type' => 'db', 'itemArray' => $dbResultsFromFiles); } } // Add DB: $resultsFromDatabase = $this->getRelations_procDB($value, $conf, $uid, $table, $field); if (!empty($resultsFromDatabase)) { // Create an entry for the field with all DB relations: $outRow[$field] = array('type' => 'db', 'itemArray' => $resultsFromDatabase); } // For "flex" fieldtypes we need to traverse the structure looking for file and db references of course! if ($conf['type'] == 'flex') { // Get current value array: // NOTICE: failure to resolve Data Structures can lead to integrity problems with the reference index. Please look up the note in the JavaDoc documentation for the function \TYPO3\CMS\Backend\Utility\BackendUtility::getFlexFormDS() $dataStructArray = BackendUtility::getFlexFormDS($conf, $row, $table, $field, $this->WSOL); $currentValueArray = GeneralUtility::xml2array($value); // Traversing the XML structure, processing files: if (is_array($currentValueArray)) { $this->temp_flexRelations = array('db' => array(), 'file' => array(), 'softrefs' => array()); // Create and call iterator object: $flexObj = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Configuration\\FlexForm\\FlexFormTools'); $flexObj->traverseFlexFormXMLData($table, $field, $row, $this, 'getRelations_flexFormCallBack'); // Create an entry for the field: $outRow[$field] = array('type' => 'flex', 'flexFormRels' => $this->temp_flexRelations); } } // Soft References: if (strlen($value) && ($softRefs = BackendUtility::explodeSoftRefParserList($conf['softref']))) { $softRefValue = $value; foreach ($softRefs as $spKey => $spParams) { $softRefObj = BackendUtility::softRefParserObj($spKey); if (is_object($softRefObj)) { $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams); if (is_array($resultArray)) { $outRow[$field]['softrefs']['keys'][$spKey] = $resultArray['elements']; if (strlen($resultArray['content'])) { $softRefValue = $resultArray['content']; } } } } if (is_array($outRow[$field]['softrefs']) && count($outRow[$field]['softrefs']) && (string) $value !== (string) $softRefValue && strstr($softRefValue, '{softref:')) { $outRow[$field]['softrefs']['tokenizedContent'] = $softRefValue; } } } } return $outRow; }
/** * Returns relation information for a $table/$row-array * Traverses all fields in input row which are configured in TCA/columns * It looks for hard relations to files and records in the TCA types "select" and "group" * * @param string $table Table name * @param array $row Row from table * @param string $onlyField Specific field to fetch for. * @return array Array with information about relations * @see export_addRecord() * @todo Define visibility */ public function getRelations($table, $row, $onlyField = '') { // Load full table description \TYPO3\CMS\Core\Utility\GeneralUtility::loadTCA($table); // Initialize: $uid = $row['uid']; $nonFields = explode(',', 'uid,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,pid'); $outRow = array(); foreach ($row as $field => $value) { if (!in_array($field, $nonFields) && is_array($GLOBALS['TCA'][$table]['columns'][$field]) && (!$onlyField || $onlyField === $field)) { $conf = $GLOBALS['TCA'][$table]['columns'][$field]['config']; // Add files if ($result = $this->getRelations_procFiles($value, $conf, $uid)) { // Creates an entry for the field with all the files: $outRow[$field] = array('type' => 'db', 'itemArray' => $result); } // Add DB: if ($result = $this->getRelations_procDB($value, $conf, $uid, $table, $field)) { // Create an entry for the field with all DB relations: $outRow[$field] = array('type' => 'db', 'itemArray' => $result); } // For "flex" fieldtypes we need to traverse the structure looking for file and db references of course! if ($conf['type'] == 'flex') { // Get current value array: // NOTICE: failure to resolve Data Structures can lead to integrity problems with the reference index. Please look up the note in the JavaDoc documentation for the function t3lib_BEfunc::getFlexFormDS() $dataStructArray = \TYPO3\CMS\Backend\Utility\BackendUtility::getFlexFormDS($conf, $row, $table, '', $this->WSOL); $currentValueArray = \TYPO3\CMS\Core\Utility\GeneralUtility::xml2array($value); // Traversing the XML structure, processing files: if (is_array($currentValueArray)) { $this->temp_flexRelations = array('db' => array(), 'file' => array(), 'softrefs' => array()); // Create and call iterator object: $flexObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Configuration\\FlexForm\\FlexFormTools'); $flexObj->traverseFlexFormXMLData($table, $field, $row, $this, 'getRelations_flexFormCallBack'); // Create an entry for the field: $outRow[$field] = array('type' => 'flex', 'flexFormRels' => $this->temp_flexRelations); } } // Soft References: if (strlen($value) && ($softRefs = \TYPO3\CMS\Backend\Utility\BackendUtility::explodeSoftRefParserList($conf['softref']))) { $softRefValue = $value; foreach ($softRefs as $spKey => $spParams) { $softRefObj = \TYPO3\CMS\Backend\Utility\BackendUtility::softRefParserObj($spKey); if (is_object($softRefObj)) { $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams); if (is_array($resultArray)) { $outRow[$field]['softrefs']['keys'][$spKey] = $resultArray['elements']; if (strlen($resultArray['content'])) { $softRefValue = $resultArray['content']; } } } } if (is_array($outRow[$field]['softrefs']) && count($outRow[$field]['softrefs']) && strcmp($value, $softRefValue) && strstr($softRefValue, '{softref:')) { $outRow[$field]['softrefs']['tokenizedContent'] = $softRefValue; } } } } return $outRow; }
/** * Handler for Flex Forms * * @param string $table The table name of the record * @param string $field The field name of the flexform field to work on * @param array $row The record data array * @param object $callBackObj Object in which the call back function is located * @param string $callBackMethod_value Method name of call back function in object for values * @return bool|string If TRUE, error happened (error string returned) */ public function traverseFlexFormXMLData($table, $field, $row, $callBackObj, $callBackMethod_value) { if (!is_array($GLOBALS['TCA'][$table]) || !is_array($GLOBALS['TCA'][$table]['columns'][$field])) { return 'TCA table/field was not defined.'; } $this->callBackObj = $callBackObj; // Get Data Structure: $dataStructArray = BackendUtility::getFlexFormDS($GLOBALS['TCA'][$table]['columns'][$field]['config'], $row, $table, $field); // If data structure was ok, proceed: if (is_array($dataStructArray)) { // Get flexform XML data: $xmlData = $row[$field]; // Convert charset: if ($this->convertCharset) { $xmlHeaderAttributes = GeneralUtility::xmlGetHeaderAttribs($xmlData); $storeInCharset = strtolower($xmlHeaderAttributes['encoding']); if ($storeInCharset) { $currentCharset = $GLOBALS['LANG']->charSet; $xmlData = $GLOBALS['LANG']->csConvObj->conv($xmlData, $storeInCharset, $currentCharset, 1); } } $editData = GeneralUtility::xml2array($xmlData); if (!is_array($editData)) { return 'Parsing error: ' . $editData; } // Language settings: $langChildren = $dataStructArray['meta']['langChildren'] ? 1 : 0; $langDisabled = $dataStructArray['meta']['langDisable'] ? 1 : 0; // Empty or invalid <meta> if (!is_array($editData['meta'])) { $editData['meta'] = array(); } $editData['meta']['currentLangId'] = array(); $languages = $this->getAvailableLanguages(); foreach ($languages as $lInfo) { $editData['meta']['currentLangId'][] = $lInfo['ISOcode']; } if (empty($editData['meta']['currentLangId'])) { $editData['meta']['currentLangId'] = array('DEF'); } $editData['meta']['currentLangId'] = array_unique($editData['meta']['currentLangId']); if ($langChildren || $langDisabled) { $lKeys = array('DEF'); } else { $lKeys = $editData['meta']['currentLangId']; } // Tabs sheets if (is_array($dataStructArray['sheets'])) { $sKeys = array_keys($dataStructArray['sheets']); } else { $sKeys = array('sDEF'); } // Traverse languages: foreach ($lKeys as $lKey) { foreach ($sKeys as $sheet) { $sheetCfg = $dataStructArray['sheets'][$sheet]; list($dataStruct, $sheet) = GeneralUtility::resolveSheetDefInDS($dataStructArray, $sheet); // Render sheet: if (is_array($dataStruct['ROOT']) && is_array($dataStruct['ROOT']['el'])) { // Separate language key $lang = 'l' . $lKey; $PA['vKeys'] = $langChildren && !$langDisabled ? $editData['meta']['currentLangId'] : array('DEF'); $PA['lKey'] = $lang; $PA['callBackMethod_value'] = $callBackMethod_value; $PA['table'] = $table; $PA['field'] = $field; $PA['uid'] = $row['uid']; $this->traverseFlexFormXMLData_DS =& $dataStruct; $this->traverseFlexFormXMLData_Data =& $editData; // Render flexform: $this->traverseFlexFormXMLData_recurse($dataStruct['ROOT']['el'], $editData['data'][$sheet][$lang], $PA, 'data/' . $sheet . '/' . $lang); } else { return 'Data Structure ERROR: No ROOT element found for sheet "' . $sheet . '".'; } } } } else { return 'Data Structure ERROR: ' . $dataStructArray; } }
/** * Ajax handler for the "suggest" feature in TCEforms. * * @param array $params The parameters from the AJAX call * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj The AJAX object representing the AJAX call * @return void */ public function processAjaxRequest($params, &$ajaxObj) { // Get parameters from $_GET/$_POST $search = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('value'); $table = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('table'); $field = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('field'); $uid = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('uid'); $pageId = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('pid'); \TYPO3\CMS\Core\Utility\GeneralUtility::loadTCA($table); // If the $uid is numeric, we have an already existing element, so get the // TSconfig of the page itself or the element container (for non-page elements) // otherwise it's a new element, so use given id of parent page (i.e., don't modify it here) if (is_numeric($uid)) { if ($table == 'pages') { $pageId = $uid; } else { $row = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord($table, $uid); $pageId = $row['pid']; } } $TSconfig = \TYPO3\CMS\Backend\Utility\BackendUtility::getPagesTSconfig($pageId); $queryTables = array(); $foreign_table_where = ''; $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$field]['config']; $parts = explode('|', $field); if ($GLOBALS['TCA'][$table]['columns'][$parts[0]]['config']['type'] === 'flex') { if (is_array($row) && count($row) > 0) { $flexfieldTCAConfig = $GLOBALS['TCA'][$table]['columns'][$parts[0]]['config']; $flexformDSArray = \TYPO3\CMS\Backend\Utility\BackendUtility::getFlexFormDS($flexfieldTCAConfig, $row, $table); $flexformDSArray = \TYPO3\CMS\Core\Utility\GeneralUtility::resolveAllSheetsInDS($flexformDSArray); $flexformElement = $parts[count($parts) - 2]; $continue = TRUE; foreach ($flexformDSArray as $sheet) { foreach ($sheet as $_ => $dataStructure) { if (isset($dataStructure['ROOT']['el'][$flexformElement]['TCEforms']['config'])) { $fieldConfig = $dataStructure['ROOT']['el'][$flexformElement]['TCEforms']['config']; $continue = FALSE; break; } } if (!$continue) { break; } } $field = str_replace('|', '][', $field); } } $wizardConfig = $fieldConfig['wizards']['suggest']; if (isset($fieldConfig['allowed'])) { $queryTables = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $fieldConfig['allowed']); } elseif (isset($fieldConfig['foreign_table'])) { $queryTables = array($fieldConfig['foreign_table']); $foreign_table_where = $fieldConfig['foreign_table_where']; // strip ORDER BY clause $foreign_table_where = trim(preg_replace('/ORDER[[:space:]]+BY.*/i', '', $foreign_table_where)); } $resultRows = array(); // fetch the records for each query table. A query table is a table from which records are allowed to // be added to the TCEForm selector, originally fetched from the "allowed" config option in the TCA foreach ($queryTables as $queryTable) { \TYPO3\CMS\Core\Utility\GeneralUtility::loadTCA($queryTable); // if the table does not exist, skip it if (!is_array($GLOBALS['TCA'][$queryTable]) || !count($GLOBALS['TCA'][$queryTable])) { continue; } $config = (array) $wizardConfig['default']; if (is_array($wizardConfig[$queryTable])) { $config = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($config, $wizardConfig[$queryTable]); } // merge the configurations of different "levels" to get the working configuration for this table and // field (i.e., go from the most general to the most special configuration) if (is_array($TSconfig['TCEFORM.']['suggest.']['default.'])) { $config = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($config, $TSconfig['TCEFORM.']['suggest.']['default.']); } if (is_array($TSconfig['TCEFORM.']['suggest.'][$queryTable . '.'])) { $config = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($config, $TSconfig['TCEFORM.']['suggest.'][$queryTable . '.']); } // use $table instead of $queryTable here because we overlay a config // for the input-field here, not for the queried table if (is_array($TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.']['default.'])) { $config = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($config, $TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.']['default.']); } if (is_array($TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.'][$queryTable . '.'])) { $config = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($config, $TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.'][$queryTable . '.']); } //process addWhere if (!isset($config['addWhere']) && $foreign_table_where) { $config['addWhere'] = $foreign_table_where; } if (isset($config['addWhere'])) { $config['addWhere'] = strtr(' ' . $config['addWhere'], array('###THIS_UID###' => intval($uid), '###CURRENT_PID###' => intval($pageId))); } // instantiate the class that should fetch the records for this $queryTable $receiverClassName = $config['receiverClass']; if (!class_exists($receiverClassName)) { $receiverClassName = 'TYPO3\\CMS\\Backend\\Form\\Element\\SuggestDefaultReceiver'; } $receiverObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($receiverClassName, $queryTable, $config); $params = array('value' => $search); $rows = $receiverObj->queryTable($params); if (empty($rows)) { continue; } $resultRows = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge($resultRows, $rows); unset($rows); } $listItems = array(); if (count($resultRows) > 0) { // traverse all found records and sort them $rowsSort = array(); foreach ($resultRows as $key => $row) { $rowsSort[$key] = $row['text']; } asort($rowsSort); $rowsSort = array_keys($rowsSort); // Limit the number of items in the result list $maxItems = $config['maxItemsInResultList'] ? $config['maxItemsInResultList'] : 10; $maxItems = min(count($resultRows), $maxItems); // put together the selector entry for ($i = 0; $i < $maxItems; $i++) { $row = $resultRows[$rowsSort[$i]]; $rowId = $row['table'] . '-' . $row['uid'] . '-' . $table . '-' . $uid . '-' . $field; $listItems[] = '<li' . ($row['class'] != '' ? ' class="' . $row['class'] . '"' : '') . ' id="' . $rowId . '" style="' . $row['style'] . '">' . $row['text'] . '</li>'; } } if (count($listItems) > 0) { $list = implode('', $listItems); } else { $list = '<li class="suggest-noresults"><i>' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:labels.noRecordFound') . '</i></li>'; } $list = '<ul class="' . $this->cssClass . '-resultlist">' . $list . '</ul>'; $ajaxObj->addContent(0, $list); }
/** * Look for flexform field and add to internal translation details * * @param string $table Table name * @param array $row Table row * @return void */ function _lookForFlexFormFieldAndAddToInternalTranslationDetails($table, $row) { global $TCA; foreach ($TCA[$table]['columns'] as $field => $cfg) { $conf = $cfg['config']; // For "flex" fieldtypes we need to traverse the structure looking for file and db references of course! if ($conf['type'] == 'flex') { // We might like to add the filter that detects if record is tt_content/CType is "tx_flex...:" since otherwise we would translate flexform content that might be hidden if say the record had a DS set but was later changed back to "Text w/Image" or so... But probably this is a rare case. // Get current data structure to see if translation is needed: $dataStructArray = BackendUtility::getFlexFormDS($conf, $row, $table); $this->detailsOutput['log'][] = 'FlexForm field "' . $field . '": DataStructure status: ' . (is_array($dataStructArray) ? 'OK' : 'Error: ' . $dataStructArray); if (is_array($dataStructArray) && !$dataStructArray['meta']['langDisable']) { $this->detailsOutput['log'][] = 'FlexForm Localization enabled, type: ' . ($dataStructArray['meta']['langChildren'] ? 'Inheritance: Continue' : 'Separate: Stop'); if ($dataStructArray['meta']['langChildren']) { $currentValueArray = GeneralUtility::xml2array($row[$field]); // Traversing the XML structure, processing files: if (is_array($currentValueArray)) { // Create and call iterator object: /** @var $flexObj t3lib_flexformtools */ $flexObj = GeneralUtility::makeInstance(FlexFormTools::class); $flexObj->traverseFlexFormXMLData($table, $field, $row, $this, 'translationDetails_flexFormCallBack'); } } } else { $this->detailsOutput['log'][] = 'FlexForm Localization disabled. Nothing to do.'; } } } }