/** * Render the form-fields of a related (foreign) record. * * @param string $parentUid The uid of the parent (embedding) record (uid or NEW...) * @param array $rec The table record of the child/embedded table (normaly post-processed by \TYPO3\CMS\Backend\Form\DataPreprocessor) * @param array $config Content of $PA['fieldConf']['config'] * @return string The HTML code for this "foreign record * @todo Define visibility */ public function renderForeignRecord($parentUid, $rec, $config = array()) { $foreign_table = $config['foreign_table']; $foreign_field = $config['foreign_field']; $foreign_selector = $config['foreign_selector']; // Register default localization content: $parent = $this->getStructureLevel(-1); if (isset($parent['localizationMode']) && $parent['localizationMode'] != FALSE) { $this->fObj->registerDefaultLanguageData($foreign_table, $rec); } // Send a mapping information to the browser via JSON: // e.g. data[<curTable>][<curId>][<curField>] => data-<pid>-<parentTable>-<parentId>-<parentField>-<curTable>-<curId>-<curField> $this->inlineData['map'][$this->inlineNames['form']] = $this->inlineNames['object']; // Set this variable if we handle a brand new unsaved record: $isNewRecord = !MathUtility::canBeInterpretedAsInteger($rec['uid']); // Set this variable if the record is virtual and only show with header and not editable fields: $isVirtualRecord = isset($rec['__virtual']) && $rec['__virtual']; // If there is a selector field, normalize it: if ($foreign_selector) { $rec[$foreign_selector] = $this->normalizeUid($rec[$foreign_selector]); } if (!$this->checkAccess($isNewRecord ? 'new' : 'edit', $foreign_table, $rec['uid'])) { return FALSE; } // Get the current naming scheme for DOM name/id attributes: $nameObject = $this->inlineNames['object']; $appendFormFieldNames = '[' . $foreign_table . '][' . $rec['uid'] . ']'; $objectId = $nameObject . self::Structure_Separator . $foreign_table . self::Structure_Separator . $rec['uid']; // Put the current level also to the dynNestedStack of TCEforms: $this->fObj->pushToDynNestedStack('inline', $objectId); $class = ''; if (!$isVirtualRecord) { // Get configuration: $collapseAll = isset($config['appearance']['collapseAll']) && $config['appearance']['collapseAll']; $expandAll = isset($config['appearance']['collapseAll']) && !$config['appearance']['collapseAll']; $ajaxLoad = isset($config['appearance']['ajaxLoad']) && !$config['appearance']['ajaxLoad'] ? FALSE : TRUE; if ($isNewRecord) { // Show this record expanded or collapsed $isExpanded = $expandAll || (!$collapseAll ? 1 : 0); } else { $isExpanded = $config['renderFieldsOnly'] || !$collapseAll && $this->getExpandedCollapsedState($foreign_table, $rec['uid']) || $expandAll; } // Render full content ONLY IF this is a AJAX-request, a new record, the record is not collapsed or AJAX-loading is explicitly turned off if ($isNewRecord || $isExpanded || !$ajaxLoad) { $combination = $this->renderCombinationTable($rec, $appendFormFieldNames, $config); $overruleTypesArray = isset($config['foreign_types']) ? $config['foreign_types'] : array(); $fields = $this->renderMainFields($foreign_table, $rec, $overruleTypesArray); $fields = $this->wrapFormsSection($fields); // Replace returnUrl in Wizard-Code, if this is an AJAX call $ajaxArguments = GeneralUtility::_GP('ajax'); if (isset($ajaxArguments[2]) && trim($ajaxArguments[2]) != '') { $fields = str_replace('P[returnUrl]=%2F' . rawurlencode(TYPO3_mainDir) . 'ajax.php', 'P[returnUrl]=' . rawurlencode($ajaxArguments[2]), $fields); } } else { $combination = ''; // This string is the marker for the JS-function to check if the full content has already been loaded $fields = '<!--notloaded-->'; } if ($isNewRecord) { // Get the top parent table $top = $this->getStructureLevel(0); $ucFieldName = 'uc[inlineView][' . $top['table'] . '][' . $top['uid'] . ']' . $appendFormFieldNames; // Set additional fields for processing for saving $fields .= '<input type="hidden" name="' . $this->prependFormFieldNames . $appendFormFieldNames . '[pid]" value="' . $rec['pid'] . '"/>'; $fields .= '<input type="hidden" name="' . $ucFieldName . '" value="' . $isExpanded . '" />'; } else { // Set additional field for processing for saving $fields .= '<input type="hidden" name="' . $this->prependCmdFieldNames . $appendFormFieldNames . '[delete]" value="1" disabled="disabled" />'; if (!$isExpanded && !empty($GLOBALS['TCA'][$foreign_table]['ctrl']['enablecolumns']['disabled']) && $ajaxLoad) { $checked = !empty($rec['hidden']) ? ' checked="checked"' : ''; $fields .= '<input type="checkbox" name="' . $this->prependFormFieldNames . $appendFormFieldNames . '[hidden]_0" value="1"' . $checked . ' />'; $fields .= '<input type="input" name="' . $this->prependFormFieldNames . $appendFormFieldNames . '[hidden]" value="' . $rec['hidden'] . '" />'; } } // If this record should be shown collapsed if (!$isExpanded) { $class = 't3-form-field-container-inline-collapsed'; } } if ($config['renderFieldsOnly']) { $out = $fields . $combination; } else { // Set the record container with data for output if ($isVirtualRecord) { $class .= ' t3-form-field-container-inline-placeHolder'; } if (isset($rec['hidden']) && (int) $rec['hidden']) { $class .= ' t3-form-field-container-inline-hidden'; } $out = '<div class="t3-form-field-record-inline" id="' . $objectId . '_fields" data-expandSingle="' . ($config['appearance']['expandSingle'] ? 1 : 0) . '" data-returnURL="' . htmlspecialchars(GeneralUtility::getIndpEnv('REQUEST_URI')) . '">' . $fields . $combination . '</div>'; $header = IconUtility::getSpriteIcon('apps-irre-' . ($class != '' ? 'collapsed' : 'expanded')); $header .= $this->renderForeignRecordHeader($parentUid, $foreign_table, $rec, $config, $isVirtualRecord); $out = '<div class="t3-form-field-header-inline" id="' . $objectId . '_header">' . $header . '</div>' . $out; // Wrap the header, fields and combination part of a child record with a div container $class .= ' inlineDiv' . ($isNewRecord ? ' inlineIsNewRecord' : ''); $out = '<div id="' . $objectId . '_div" class="t3-form-field-container-inline ' . trim($class) . '">' . $out . '</div>'; } // Remove the current level also from the dynNestedStack of TCEforms: $this->fObj->popFromDynNestedStack(); return $out; }
/** * Creates the editing form with TCEforms, based on the input from GPvars. * * @return string HTML form elements wrapped in tables * @todo Define visibility */ public function makeEditForm() { // Initialize variables: $this->elementsData = array(); $this->errorC = 0; $this->newC = 0; $thePrevUid = ''; $editForm = ''; $trData = NULL; // Traverse the GPvar edit array // Tables: foreach ($this->editconf as $table => $conf) { if (is_array($conf) && $GLOBALS['TCA'][$table] && $GLOBALS['BE_USER']->check('tables_modify', $table)) { // Traverse the keys/comments of each table (keys can be a commalist of uids) foreach ($conf as $cKey => $cmd) { if ($cmd == 'edit' || $cmd == 'new') { // Get the ids: $ids = GeneralUtility::trimExplode(',', $cKey, TRUE); // Traverse the ids: foreach ($ids as $theUid) { // Checking if the user has permissions? (Only working as a precaution, // because the final permission check is always down in TCE. But it's // good to notify the user on beforehand...) // First, resetting flags. $hasAccess = 1; $deniedAccessReason = ''; $deleteAccess = 0; $this->viewId = 0; // If the command is to create a NEW record...: if ($cmd == 'new') { // NOTICE: the id values in this case points to the page uid onto which the // record should be create OR (if the id is negativ) to a record from the // same table AFTER which to create the record. if ((int) $theUid) { // Find parent page on which the new record reside // Less than zero - find parent page if ($theUid < 0) { $calcPRec = BackendUtility::getRecord($table, abs($theUid)); $calcPRec = BackendUtility::getRecord('pages', $calcPRec['pid']); } else { // always a page $calcPRec = BackendUtility::getRecord('pages', abs($theUid)); } // Now, calculate whether the user has access to creating new records on this position: if (is_array($calcPRec)) { // Permissions for the parent page $CALC_PERMS = $GLOBALS['BE_USER']->calcPerms($calcPRec); if ($table == 'pages') { // If pages: $hasAccess = $CALC_PERMS & 8 ? 1 : 0; $this->viewId = 0; } else { $hasAccess = $CALC_PERMS & 16 ? 1 : 0; $this->viewId = $calcPRec['uid']; } } } // Don't save this document title in the document selector if the document is new. $this->dontStoreDocumentRef = 1; } else { // Edit: $calcPRec = BackendUtility::getRecord($table, $theUid); BackendUtility::fixVersioningPid($table, $calcPRec); if (is_array($calcPRec)) { if ($table == 'pages') { // If pages: $CALC_PERMS = $GLOBALS['BE_USER']->calcPerms($calcPRec); $hasAccess = $CALC_PERMS & 2 ? 1 : 0; $deleteAccess = $CALC_PERMS & 4 ? 1 : 0; $this->viewId = $calcPRec['uid']; } else { // Fetching pid-record first $CALC_PERMS = $GLOBALS['BE_USER']->calcPerms(BackendUtility::getRecord('pages', $calcPRec['pid'])); $hasAccess = $CALC_PERMS & 16 ? 1 : 0; $deleteAccess = $CALC_PERMS & 16 ? 1 : 0; $this->viewId = $calcPRec['pid']; // Adding "&L=xx" if the record being edited has a languageField with a value larger than zero! if ($GLOBALS['TCA'][$table]['ctrl']['languageField'] && $calcPRec[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0) { $this->viewId_addParams = '&L=' . $calcPRec[$GLOBALS['TCA'][$table]['ctrl']['languageField']]; } } // Check internals regarding access: $isRootLevelRestrictionIgnored = BackendUtility::isRootLevelRestrictionIgnored($table); if ($hasAccess || (int) $calcPRec['pid'] === 0 && $isRootLevelRestrictionIgnored) { $hasAccess = $GLOBALS['BE_USER']->recordEditAccessInternals($table, $calcPRec); $deniedAccessReason = $GLOBALS['BE_USER']->errorMsg; } } else { $hasAccess = 0; } } if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/alt_doc.php']['makeEditForm_accessCheck'])) { foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/alt_doc.php']['makeEditForm_accessCheck'] as $_funcRef) { $_params = array('table' => $table, 'uid' => $theUid, 'cmd' => $cmd, 'hasAccess' => $hasAccess); $hasAccess = GeneralUtility::callUserFunction($_funcRef, $_params, $this); } } // AT THIS POINT we have checked the access status of the editing/creation of // records and we can now proceed with creating the form elements: if ($hasAccess) { $prevPageID = is_object($trData) ? $trData->prevPageID : ''; $trData = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\DataPreprocessor'); $trData->addRawData = TRUE; $trData->defVals = $this->defVals; $trData->lockRecords = 1; $trData->disableRTE = !$GLOBALS['BE_USER']->isRTE(); $trData->prevPageID = $prevPageID; // 'new' $trData->fetchRecord($table, $theUid, $cmd == 'new' ? 'new' : ''); $rec = reset($trData->regTableItems_data); $rec['uid'] = $cmd == 'new' ? uniqid('NEW', TRUE) : $theUid; if ($cmd == 'new') { $rec['pid'] = $theUid == 'prev' ? (int) $thePrevUid : (int) $theUid; } $this->elementsData[] = array('table' => $table, 'uid' => $rec['uid'], 'pid' => $rec['pid'], 'cmd' => $cmd, 'deleteAccess' => $deleteAccess); // Now, render the form: if (is_array($rec)) { // Setting visual path / title of form: $this->generalPathOfForm = $this->tceforms->getRecordPath($table, $rec); if (!$this->storeTitle) { $this->storeTitle = $this->recTitle ? htmlspecialchars($this->recTitle) : BackendUtility::getRecordTitle($table, $rec, TRUE); } // Setting variables in TCEforms object: $this->tceforms->hiddenFieldList = ''; $this->tceforms->globalShowHelp = !$this->disHelp; if (is_array($this->overrideVals) && is_array($this->overrideVals[$table])) { $this->tceforms->hiddenFieldListArr = array_keys($this->overrideVals[$table]); } // Register default language labels, if any: $this->tceforms->registerDefaultLanguageData($table, $rec); // Create form for the record (either specific list of fields or the whole record): $panel = ''; if ($this->columnsOnly) { if (is_array($this->columnsOnly)) { $panel .= $this->tceforms->getListedFields($table, $rec, $this->columnsOnly[$table]); } else { $panel .= $this->tceforms->getListedFields($table, $rec, $this->columnsOnly); } } else { $panel .= $this->tceforms->getMainFields($table, $rec); } $panel = $this->tceforms->wrapTotal($panel, $rec, $table); // Setting the pid value for new records: if ($cmd == 'new') { $panel .= '<input type="hidden" name="data[' . htmlspecialchars($table) . '][' . htmlspecialchars($rec['uid']) . '][pid]" value="' . (int) $rec['pid'] . '" />'; $this->newC++; } // Display "is-locked" message: if ($lockInfo = BackendUtility::isRecordLocked($table, $rec['uid'])) { $flashMessage = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\FlashMessage', htmlspecialchars($lockInfo['msg']), '', \TYPO3\CMS\Core\Messaging\FlashMessage::WARNING); /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */ $flashMessageService = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\FlashMessageService'); /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */ $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier(); $defaultFlashMessageQueue->enqueue($flashMessage); } // Combine it all: $editForm .= $panel; } $thePrevUid = $rec['uid']; } else { $this->errorC++; $editForm .= $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.noEditPermission', TRUE) . '<br /><br />' . ($deniedAccessReason ? 'Reason: ' . htmlspecialchars($deniedAccessReason) . '<br /><br />' : ''); } } } } } } return $editForm; }