/** * Hook for updating translation index when records are edited (hooks into TCEmain) * * @param $status * @param $table * @param $id * @param $fieldArray * @param $pObj */ function processDatamap_afterDatabaseOperations($status, $table, $id, $fieldArray, &$pObj) { global $TCA; // Check if # debug(array($status, $table, $id)); // Map id for new records: if ($status == "new") { $id = $pObj->substNEWwithIDs[$id]; # echo "New fixed<br>"; } // Find live record if any: if (!($liveRecord = BackendUtility::getLiveVersionOfRecord($table, $id))) { // If it was a version we find live... $liveRecord = BackendUtility::getRecord($table, $id); // Otherwise we load live record. # echo "Live version<br>"; } if (is_array($liveRecord)) { // Now, see if this record is a translation of another one: $t8ToolsObj = GeneralUtility::makeInstance(TranslationConfigurationProvider::class); if ($t8ToolsObj->isTranslationInOwnTable($table) && $liveRecord[$TCA[$table]['ctrl']['transOrigPointerField']]) { // So it had a translation pointer - lets look for the root record then: $liveRecord = BackendUtility::getRecord($table, $liveRecord[$TCA[$table]['ctrl']['transOrigPointerField']], 'uid'); # echo "Finding root version<br>"; } elseif ($TCA[$table]['ctrl']['transOrigPointerTable'] && $liveRecord[$TCA[$table]['ctrl']['transOrigPointerField']]) { $fld = $TCA[$table]['ctrl']['transOrigPointerField']; $table = $TCA[$table]['ctrl']['transOrigPointerTable']; // Changeing table value here on purpose! $liveRecord = BackendUtility::getRecord($table, $liveRecord[$fld], 'uid'); } $languageID = L10nBaseService::getTargetLanguageID(); if (is_array($liveRecord)) { # echo "indexing id ".$liveRecord['uid']; // Finally, we have found the "root record" and will check it: $t8Tools = GeneralUtility::makeInstance(Tools::class); $t8Tools->verbose = false; // Otherwise it will show records which has fields but none editable. # debug($t8Tools->indexDetailsRecord($table,$liveRecord['uid'])); $t8Tools->updateIndexTableFromDetailsArray($t8Tools->indexDetailsRecord($table, $liveRecord['uid'], $languageID)); } } }
/** * Release version from this workspace (and into "Live" workspace but as an offline version). * * @param string $table Table name * @param int $id Record UID * @param bool $flush If set, will completely delete element * @param DataHandler $tcemainObj TCEmain object * @return void */ protected function version_clearWSID($table, $id, $flush = FALSE, DataHandler $tcemainObj) { if ($errorCode = $tcemainObj->BE_USER->workspaceCannotEditOfflineVersion($table, $id)) { $tcemainObj->newlog('Attempt to reset workspace for record failed: ' . $errorCode, 1); return; } if (!$tcemainObj->checkRecordUpdateAccess($table, $id)) { $tcemainObj->newlog('Attempt to reset workspace for record failed because you do not have edit access', 1); return; } $liveRec = BackendUtility::getLiveVersionOfRecord($table, $id, 'uid,t3ver_state'); if (!$liveRec) { return; } // Clear workspace ID: $updateData = array('t3ver_wsid' => 0, 't3ver_tstamp' => $GLOBALS['EXEC_TIME']); $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid=' . (int) $id, $updateData); // Clear workspace ID for live version AND DELETE IT as well because it is a new record! if (VersionState::cast($liveRec['t3ver_state'])->equals(VersionState::NEW_PLACEHOLDER) || VersionState::cast($liveRec['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)) { $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid=' . (int) $liveRec['uid'], $updateData); // THIS assumes that the record was placeholder ONLY for ONE record (namely $id) $tcemainObj->deleteEl($table, $liveRec['uid'], TRUE); } // If "deleted" flag is set for the version that got released // it doesn't make sense to keep that "placeholder" anymore and we delete it completly. $wsRec = BackendUtility::getRecord($table, $id); if ($flush || (VersionState::cast($wsRec['t3ver_state'])->equals(VersionState::NEW_PLACEHOLDER) || VersionState::cast($wsRec['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER))) { $tcemainObj->deleteEl($table, $id, TRUE, TRUE); } // Remove the move-placeholder if found for live record. if ((int) $GLOBALS['TCA'][$table]['ctrl']['versioningWS'] >= 2) { if ($plhRec = BackendUtility::getMovePlaceholder($table, $liveRec['uid'], 'uid')) { $tcemainObj->deleteEl($table, $plhRec['uid'], TRUE, TRUE); } } }
/** * @param \GeorgRinger\News\Domain\Model\News $newsItem * @return int */ protected function getNewsId(\GeorgRinger\News\Domain\Model\News $newsItem) { $uid = $newsItem->getUid(); // If a user is logged in and not in live workspace if ($GLOBALS['BE_USER'] && $GLOBALS['BE_USER']->workspace > 0) { $record = \TYPO3\CMS\Backend\Utility\BackendUtility::getLiveVersionOfRecord('tx_news_domain_model_news', $newsItem->getUid()); if ($record['uid']) { $uid = $record['uid']; } } return $uid; }
/** * Get the final pid based on $table and $pid ($destPid type... pos/neg) * * @param string $table Table name * @param int $pid "Destination pid" : If the value is >= 0 it's just returned directly (through (int)though) but if the value is <0 then the method looks up the record with the uid equal to abs($pid) (positive number) and returns the PID of that record! The idea is that negative numbers point to the record AFTER WHICH the position is supposed to be! * @return int */ public function resolvePid($table, $pid) { $pid = (int) $pid; if ($pid < 0) { $res = $this->databaseConnection->exec_SELECTquery('pid', $table, 'uid=' . abs($pid)); $row = $this->databaseConnection->sql_fetch_assoc($res); $this->databaseConnection->sql_free_result($res); // Look, if the record UID happens to be an offline record. If so, find its live version. // Offline uids will be used when a page is versionized as "branch" so this is when we // must correct - otherwise a pid of "-1" and a wrong sort-row number // is returned which we don't want. if ($lookForLiveVersion = BackendUtility::getLiveVersionOfRecord($table, abs($pid), 'pid')) { $row = $lookForLiveVersion; } $pid = (int) $row['pid']; } return $pid; }
/** * Initialization of the class. * * @return void */ protected function init() { // Init GPvars: $this->P = GeneralUtility::_GP('P'); $this->returnEditConf = GeneralUtility::_GP('returnEditConf'); // Get this record $record = BackendUtility::getRecord($this->P['table'], $this->P['uid']); // Set table: $this->table = $this->P['params']['table']; // Get TSconfig for it. $TSconfig = BackendUtility::getTCEFORM_TSconfig($this->P['table'], is_array($record) ? $record : array('pid' => $this->P['pid'])); // Set [params][pid] if (substr($this->P['params']['pid'], 0, 3) === '###' && substr($this->P['params']['pid'], -3) === '###') { $keyword = substr($this->P['params']['pid'], 3, -3); if (strpos($keyword, 'PAGE_TSCONFIG_') === 0) { $this->pid = (int) $TSconfig[$this->P['field']][$keyword]; } else { $this->pid = (int) $TSconfig['_' . $keyword]; } } else { $this->pid = (int) $this->P['params']['pid']; } // Return if new record as parent (not possibly/allowed) if ($this->pid === '') { HttpUtility::redirect(GeneralUtility::sanitizeLocalUrl($this->P['returnUrl'])); } // Else proceed: // If a new id has returned from a newly created record... if ($this->returnEditConf) { $editConfiguration = json_decode($this->returnEditConf, true); if (is_array($editConfiguration[$this->table]) && MathUtility::canBeInterpretedAsInteger($this->P['uid'])) { // Getting id and cmd from returning editConf array. reset($editConfiguration[$this->table]); $this->id = (int) key($editConfiguration[$this->table]); $cmd = current($editConfiguration[$this->table]); // ... and if everything seems OK we will register some classes for inclusion and instruct the object // to perform processing later. if ($this->P['params']['setValue'] && $cmd === 'edit' && $this->id && $this->P['table'] && $this->P['field'] && $this->P['uid']) { $liveRecord = BackendUtility::getLiveVersionOfRecord($this->table, $this->id, 'uid'); if ($liveRecord) { $this->id = $liveRecord['uid']; } $this->processDataFlag = 1; } } } }
/** * Make selector box for creating new translation for a record or switching to edit the record in an existing * language. * Displays only languages which are available for the current page. * * @param string $table Table name * @param int $uid Uid for which to create a new language * @param int $pid Pid of the record */ public function languageSwitch($table, $uid, $pid = null) { $languageField = $GLOBALS['TCA'][$table]['ctrl']['languageField']; $transOrigPointerField = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']; // Table editable and activated for languages? if ($this->getBackendUser()->check('tables_modify', $table) && $languageField && $transOrigPointerField && !$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable']) { if (is_null($pid)) { $row = BackendUtility::getRecord($table, $uid, 'pid'); $pid = $row['pid']; } // Get all available languages for the page $langRows = $this->getLanguages($pid); // Page available in other languages than default language? if (is_array($langRows) && count($langRows) > 1) { $rowsByLang = array(); $fetchFields = 'uid,' . $languageField . ',' . $transOrigPointerField; // Get record in current language $rowCurrent = BackendUtility::getLiveVersionOfRecord($table, $uid, $fetchFields); if (!is_array($rowCurrent)) { $rowCurrent = BackendUtility::getRecord($table, $uid, $fetchFields); } $currentLanguage = (int) $rowCurrent[$languageField]; // Disabled for records with [all] language! if ($currentLanguage > -1) { // Get record in default language if needed if ($currentLanguage && $rowCurrent[$transOrigPointerField]) { $rowsByLang[0] = BackendUtility::getLiveVersionOfRecord($table, $rowCurrent[$transOrigPointerField], $fetchFields); if (!is_array($rowsByLang[0])) { $rowsByLang[0] = BackendUtility::getRecord($table, $rowCurrent[$transOrigPointerField], $fetchFields); } } else { $rowsByLang[$rowCurrent[$languageField]] = $rowCurrent; } if ($rowCurrent[$transOrigPointerField] || $currentLanguage === 0) { // Get record in other languages to see what's already available $translations = $this->getDatabaseConnection()->exec_SELECTgetRows($fetchFields, $table, 'pid=' . (int) $pid . ' AND ' . $languageField . '>0' . ' AND ' . $transOrigPointerField . '=' . (int) $rowsByLang[0]['uid'] . BackendUtility::deleteClause($table) . BackendUtility::versioningPlaceholderClause($table)); foreach ($translations as $row) { $rowsByLang[$row[$languageField]] = $row; } } $languageMenu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu(); $languageMenu->setIdentifier('_langSelector'); $languageMenu->setLabel($this->getLanguageService()->sL('LLL:EXT:lang/locallang_general.xlf:LGL.language', true)); foreach ($langRows as $lang) { if ($this->getBackendUser()->checkLanguageAccess($lang['uid'])) { $newTranslation = isset($rowsByLang[$lang['uid']]) ? '' : ' [' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.new', true) . ']'; // Create url for creating a localized record if ($newTranslation) { $redirectUrl = BackendUtility::getModuleUrl('record_edit', array('justLocalized' => $table . ':' . $rowsByLang[0]['uid'] . ':' . $lang['uid'], 'returnUrl' => $this->retUrl)); $href = BackendUtility::getLinkToDataHandlerAction('&cmd[' . $table . '][' . $rowsByLang[0]['uid'] . '][localize]=' . $lang['uid'], $redirectUrl); } else { $href = BackendUtility::getModuleUrl('record_edit', array('edit[' . $table . '][' . $rowsByLang[$lang['uid']]['uid'] . ']' => 'edit', 'returnUrl' => $this->retUrl)); } $menuItem = $languageMenu->makeMenuItem()->setTitle($lang['title'] . $newTranslation)->setHref($href); if ((int) $lang['uid'] === $currentLanguage) { $menuItem->setActive(true); } $languageMenu->addMenuItem($menuItem); } } $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($languageMenu); } } } }
/** * Generates a view link for a page. * * @static * @param string $table Table to be used * @param int $uid Uid of the version(!) record * @param array $liveRecord Optional live record data * @param array $versionRecord Optional version record data * @return string */ public static function viewSingleRecord($table, $uid, array $liveRecord = null, array $versionRecord = null) { if ($table === 'pages') { return BackendUtility::viewOnClick(BackendUtility::getLiveVersionIdOfRecord('pages', $uid)); } if ($liveRecord === null) { $liveRecord = BackendUtility::getLiveVersionOfRecord($table, $uid); } if ($versionRecord === null) { $versionRecord = BackendUtility::getRecord($table, $uid); } if (VersionState::cast($versionRecord['t3ver_state'])->equals(VersionState::MOVE_POINTER)) { $movePlaceholder = BackendUtility::getMovePlaceholder($table, $liveRecord['uid'], 'pid'); } // Directly use pid value and consider move placeholders $previewPageId = empty($movePlaceholder['pid']) ? $liveRecord['pid'] : $movePlaceholder['pid']; $additionalParameters = '&tx_workspaces_web_workspacesworkspaces[previewWS]=' . $versionRecord['t3ver_wsid']; // Add language parameter if record is a localization if (BackendUtility::isTableLocalizable($table)) { $languageField = $GLOBALS['TCA'][$table]['ctrl']['languageField']; if ($versionRecord[$languageField] > 0) { $additionalParameters .= '&L=' . $versionRecord[$languageField]; } } $pageTsConfig = BackendUtility::getPagesTSconfig($previewPageId); $viewUrl = ''; // Directly use determined direct page id if ($table === 'pages_language_overlay' || $table === 'tt_content') { $viewUrl = BackendUtility::viewOnClick($previewPageId, '', '', '', '', $additionalParameters); // Analyze Page TSconfig options.workspaces.previewPageId } elseif (!empty($pageTsConfig['options.']['workspaces.']['previewPageId.'][$table]) || !empty($pageTsConfig['options.']['workspaces.']['previewPageId'])) { if (!empty($pageTsConfig['options.']['workspaces.']['previewPageId.'][$table])) { $previewConfiguration = $pageTsConfig['options.']['workspaces.']['previewPageId.'][$table]; } else { $previewConfiguration = $pageTsConfig['options.']['workspaces.']['previewPageId']; } // Extract possible settings (e.g. "field:pid") list($previewKey, $previewValue) = explode(':', $previewConfiguration, 2); if ($previewKey === 'field') { $previewPageId = (int) $liveRecord[$previewValue]; } else { $previewPageId = (int) $previewConfiguration; } $viewUrl = BackendUtility::viewOnClick($previewPageId, '', '', '', '', $additionalParameters); // Call user function to render the single record view } elseif (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['workspaces']['viewSingleRecord'])) { $_params = array('table' => $table, 'uid' => $uid, 'record' => $liveRecord, 'liveRecord' => $liveRecord, 'versionRecord' => $versionRecord); $_funcRef = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['workspaces']['viewSingleRecord']; $null = null; $viewUrl = GeneralUtility::callUserFunction($_funcRef, $_params, $null); } return $viewUrl; }
/** * Returns a node collection of filtered nodes * * @param \TYPO3\CMS\Backend\Tree\TreeNode $node * @param string $searchFilter * @param int $mountPoint * @return \TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNodeCollection the filtered nodes */ public function getFilteredNodes(\TYPO3\CMS\Backend\Tree\TreeNode $node, $searchFilter, $mountPoint = 0) { /** @var $nodeCollection \TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNodeCollection */ $nodeCollection = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNodeCollection::class); $records = $this->getSubpages(-1, $searchFilter); if (!is_array($records) || empty($records)) { return $nodeCollection; } elseif (count($records) > 500) { return $nodeCollection; } // check no temporary mountpoint is used $mountPoints = (int) $GLOBALS['BE_USER']->uc['pageTree_temporaryMountPoint']; if (!$mountPoints) { $mountPoints = array_map('intval', $GLOBALS['BE_USER']->returnWebmounts()); $mountPoints = array_unique($mountPoints); } else { $mountPoints = [$mountPoints]; } $isNumericSearchFilter = is_numeric($searchFilter) && $searchFilter > 0; $searchFilterQuoted = preg_quote($searchFilter, '/'); $nodeId = (int) $node->getId(); $processedRecordIds = []; foreach ($records as $record) { if ((int) $record['t3ver_wsid'] !== (int) $GLOBALS['BE_USER']->workspace && (int) $record['t3ver_wsid'] !== 0) { continue; } $liveVersion = BackendUtility::getLiveVersionOfRecord('pages', $record['uid'], 'uid'); if ($liveVersion !== null) { $record = $liveVersion; } $record = Commands::getNodeRecord($record['uid'], false); if ((int) $record['pid'] === -1 || in_array($record['uid'], $this->hiddenRecords) || in_array($record['uid'], $processedRecordIds)) { continue; } $processedRecordIds[] = $record['uid']; $rootline = BackendUtility::BEgetRootLine($record['uid'], '', $GLOBALS['BE_USER']->workspace != 0); $rootline = array_reverse($rootline); if (!in_array(0, $mountPoints, true)) { $isInsideMountPoints = false; foreach ($rootline as $rootlineElement) { if (in_array((int) $rootlineElement['uid'], $mountPoints, true)) { $isInsideMountPoints = true; break; } } if (!$isInsideMountPoints) { continue; } } $reference = $nodeCollection; $inFilteredRootline = false; $amountOfRootlineElements = count($rootline); for ($i = 0; $i < $amountOfRootlineElements; ++$i) { $rootlineElement = $rootline[$i]; $rootlineElement['uid'] = (int) $rootlineElement['uid']; $isInWebMount = (int) $GLOBALS['BE_USER']->isInWebMount($rootlineElement['uid']); if (!$isInWebMount || $rootlineElement['uid'] === (int) $mountPoints[0] && $rootlineElement['uid'] !== $isInWebMount) { continue; } if ((int) $rootlineElement['pid'] === $nodeId || $rootlineElement['uid'] === $nodeId || $rootlineElement['uid'] === $isInWebMount && in_array($rootlineElement['uid'], $mountPoints, true)) { $inFilteredRootline = true; } if (!$inFilteredRootline || $rootlineElement['uid'] === $mountPoint) { continue; } $rootlineElement = Commands::getNodeRecord($rootlineElement['uid'], false); $ident = (int) $rootlineElement['sorting'] . (int) $rootlineElement['uid']; if ($reference && $reference->offsetExists($ident)) { /** @var $refNode \TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode */ $refNode = $reference->offsetGet($ident); $refNode->setExpanded(true); $refNode->setLeaf(false); $reference = $refNode->getChildNodes(); if ($reference == null) { $reference = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNodeCollection::class); $refNode->setChildNodes($reference); } } else { $refNode = Commands::getNewNode($rootlineElement, $mountPoint); $replacement = '<span class="typo3-pagetree-filteringTree-highlight">$1</span>'; if ($isNumericSearchFilter && (int) $rootlineElement['uid'] === (int) $searchFilter) { $text = str_replace('$1', $refNode->getText(), $replacement); } else { $text = preg_replace('/(' . $searchFilterQuoted . ')/iu', $replacement, $refNode->getText()); } $refNode->setText($text, $refNode->getTextSourceField(), $refNode->getPrefix(), $refNode->getSuffix()); /** @var $childCollection \TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNodeCollection */ $childCollection = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNodeCollection::class); if ($i + 1 >= $amountOfRootlineElements) { $childNodes = $this->getNodes($refNode, $mountPoint); foreach ($childNodes as $childNode) { /** @var $childNode \TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode */ $childRecord = $childNode->getRecord(); $childIdent = (int) $childRecord['sorting'] . (int) $childRecord['uid']; $childCollection->offsetSet($childIdent, $childNode); } $refNode->setChildNodes($childNodes); } $refNode->setChildNodes($childCollection); $reference->offsetSet($ident, $refNode); $reference->ksort(); $reference = $childCollection; } } } foreach ($this->processCollectionHookObjects as $hookObject) { /** @var $hookObject \TYPO3\CMS\Backend\Tree\Pagetree\CollectionProcessorInterface */ $hookObject->postProcessFilteredNodes($node, $searchFilter, $mountPoint, $nodeCollection); } return $nodeCollection; }
/** * Generates a view link for a page. * * @static * @param string $table Table to be used * @param integer $uid Uid of the version(!) record * @param array $liveRecord Optional live record data * @param array $versionRecord Optional version record data * @return string */ public static function viewSingleRecord($table, $uid, array $liveRecord = NULL, array $versionRecord = NULL) { $viewUrl = ''; if ($table == 'pages') { $viewUrl = BackendUtility::viewOnClick(BackendUtility::getLiveVersionIdOfRecord('pages', $uid)); } elseif ($table === 'pages_language_overlay' || $table === 'tt_content') { if ($liveRecord === NULL) { $liveRecord = BackendUtility::getLiveVersionOfRecord($table, $uid); } if ($versionRecord === NULL) { $versionRecord = BackendUtility::getRecord($table, $uid); } if (VersionState::cast($versionRecord['t3ver_state'])->equals(VersionState::MOVE_POINTER)) { $movePlaceholder = BackendUtility::getMovePlaceholder($table, $liveRecord['uid'], 'pid'); } $previewPageId = empty($movePlaceholder['pid']) ? $liveRecord['pid'] : $movePlaceholder['pid']; $additionalParameters = '&tx_workspaces_web_workspacesworkspaces[previewWS]=' . $versionRecord['t3ver_wsid']; $languageField = $GLOBALS['TCA'][$table]['ctrl']['languageField']; if ($versionRecord[$languageField] > 0) { $additionalParameters .= '&L=' . $versionRecord[$languageField]; } $viewUrl = BackendUtility::viewOnClick($previewPageId, '', '', '', '', $additionalParameters); } else { if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['workspaces']['viewSingleRecord'])) { $_params = array('table' => $table, 'uid' => $uid, 'record' => $liveRecord, 'liveRecord' => $liveRecord, 'versionRecord' => $versionRecord); $_funcRef = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['workspaces']['viewSingleRecord']; $null = NULL; $viewUrl = \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($_funcRef, $_params, $null); } } return $viewUrl; }
/** * Make selector box for creating new translation for a record or switching to edit the record in an existing language. * Displays only languages which are available for the current page. * * @param string $table Table name * @param int $uid Uid for which to create a new language * @param int $pid Pid of the record * @return string <select> HTML element (if there were items for the box anyways...) */ public function languageSwitch($table, $uid, $pid = NULL) { $content = ''; $languageField = $GLOBALS['TCA'][$table]['ctrl']['languageField']; $transOrigPointerField = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']; // Table editable and activated for languages? if ($this->getBackendUser()->check('tables_modify', $table) && $languageField && $transOrigPointerField && !$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable']) { if (is_null($pid)) { $row = BackendUtility::getRecord($table, $uid, 'pid'); $pid = $row['pid']; } // Get all avalibale languages for the page $langRows = $this->getLanguages($pid); // Page available in other languages than default language? if (is_array($langRows) && count($langRows) > 1) { $rowsByLang = array(); $fetchFields = 'uid,' . $languageField . ',' . $transOrigPointerField; // Get record in current language $rowCurrent = BackendUtility::getLiveVersionOfRecord($table, $uid, $fetchFields); if (!is_array($rowCurrent)) { $rowCurrent = BackendUtility::getRecord($table, $uid, $fetchFields); } $currentLanguage = $rowCurrent[$languageField]; // Disabled for records with [all] language! if ($currentLanguage > -1) { // Get record in default language if needed if ($currentLanguage && $rowCurrent[$transOrigPointerField]) { $rowsByLang[0] = BackendUtility::getLiveVersionOfRecord($table, $rowCurrent[$transOrigPointerField], $fetchFields); if (!is_array($rowsByLang[0])) { $rowsByLang[0] = BackendUtility::getRecord($table, $rowCurrent[$transOrigPointerField], $fetchFields); } } else { $rowsByLang[$rowCurrent[$languageField]] = $rowCurrent; } if ($rowCurrent[$transOrigPointerField] || $currentLanguage === '0') { // Get record in other languages to see what's already available $translations = $this->getDatabaseConnection()->exec_SELECTgetRows($fetchFields, $table, 'pid=' . (int) $pid . ' AND ' . $languageField . '>0' . ' AND ' . $transOrigPointerField . '=' . (int) $rowsByLang[0]['uid'] . BackendUtility::deleteClause($table) . BackendUtility::versioningPlaceholderClause($table)); foreach ($translations as $row) { $rowsByLang[$row[$languageField]] = $row; } } $langSelItems = array(); foreach ($langRows as $lang) { if ($this->getBackendUser()->checkLanguageAccess($lang['uid'])) { $newTranslation = isset($rowsByLang[$lang['uid']]) ? '' : ' [' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.new', TRUE) . ']'; // Create url for creating a localized record if ($newTranslation) { $redirectUrl = BackendUtility::getModuleUrl('record_edit', array('justLocalized' => $table . ':' . $rowsByLang[0]['uid'] . ':' . $lang['uid'], 'returnUrl' => $this->retUrl)) . BackendUtility::getUrlToken('editRecord'); $href = $this->doc->issueCommand('&cmd[' . $table . '][' . $rowsByLang[0]['uid'] . '][localize]=' . $lang['uid'], $redirectUrl); } else { $href = BackendUtility::getModuleUrl('record_edit', array('edit[' . $table . '][' . $rowsByLang[$lang['uid']]['uid'] . ']' => 'edit', 'returnUrl' => $this->retUrl)) . BackendUtility::getUrlToken('editRecord'); } $langSelItems[$lang['uid']] = ' <option value="' . htmlspecialchars($href) . '"' . ($currentLanguage == $lang['uid'] ? ' selected="selected"' : '') . '>' . htmlspecialchars($lang['title'] . $newTranslation) . '</option>'; } } // If any languages are left, make selector: if (count($langSelItems) > 1) { $onChange = 'if(this.options[this.selectedIndex].value){window.location.href=(this.options[this.selectedIndex].value);}'; $content = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_general.xlf:LGL.language', TRUE) . ' <select name="_langSelector" onchange="' . htmlspecialchars($onChange) . '"> ' . implode('', $langSelItems) . ' </select>'; } } } } return $content; }
/** * Render the context settings field for a certain table * * @param array $params Array of record information * - table - table name * - row - array with database row data * @param t3lib_TCEforms $fobj * @return string */ public function renderRecordSettingsField($params, $fobj) { global $TCA; $table = $params['table']; $fobj->addStyleSheet('tx_contexts_bestyles', t3lib_extMgm::extRelPath('contexts') . 'Resources/Public/StyleSheet/be.css'); $contexts = new Tx_Contexts_Context_Container(); $contexts->initAll(); $namePre = str_replace('[' . $params['field'] . '_', '[' . $params['field'] . '][', $params['itemFormElName']); $settings = $params['fieldConf']['config']['settings']; $content = ''; //Check for the current workspace. If it's not LIVE, throw info message and disable context editing further down $currentWorkspace = $GLOBALS['BE_USER']->workspace; if ($currentWorkspace != 0) { $message = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\FlashMessage', 'Contexts are read-only in this workspace. Switch to LIVE version to change them.', '', \TYPO3\CMS\Core\Messaging\FlashMessage::INFO, FALSE); $content .= $message->render(); } $content .= '<table class="tx_contexts_table_settings typo3-dblist" style="width: auto; min-width:50%">' . '<tbody>' . '<tr class="t3-row-header">' . '<td></td>' . '<td class="tx_contexts_context">' . $fobj->sL('LLL:' . Tx_Contexts_Api_Configuration::LANG_FILE . ':tx_contexts_contexts') . '</td>'; foreach ($settings as $settingName => $config) { $content .= '<td class="tx_contexts_setting">' . $fobj->sL($config['label']) . '</td>'; } $content .= '</tr>'; $uid = (int) $params['row']['uid']; $row = $params['row']; //Is this a Workspace Overlay? If so, load original record for plain info view if ($currentWorkspace != 0 && $params['row']['t3ver_oid'] != 0) { $uid = (int) $params['row']['t3ver_oid']; $row = BackendUtility::getLiveVersionOfRecord($table, $params['row']['uid']); } $visibleContexts = 0; foreach ($contexts as $context) { if ($context->getDisabled() || $context->getHideInBackend()) { continue; } /* @var $context Tx_Contexts_Context_Abstract */ ++$visibleContexts; $contSettings = ''; $bHasSetting = false; foreach ($settings as $settingName => $config) { $setting = $uid ? $context->getSetting($table, $settingName, $uid, $row) : null; $bHasSetting = $bHasSetting || (bool) $setting; if ($currentWorkspace != 0) { $contSettings .= '<td class="tx_contexts_setting">'; if ($setting && $setting->getEnabled()) { $contSettings .= '<span class="context-active">Yes</span>'; } else { if ($setting && !$setting->getEnabled()) { $contSettings .= '<span class="context-active">No</span>'; } else { $contSettings .= 'n/a'; } } $contSettings .= '</td>'; } else { $contSettings .= '<td class="tx_contexts_setting">' . '<select name="' . $namePre . '[' . $context->getUid() . '][' . $settingName . ']">' . '<option value="">n/a</option>' . '<option value="1"' . ($setting && $setting->getEnabled() ? ' selected="selected"' : '') . '>Yes</option>' . '<option value="0"' . ($setting && !$setting->getEnabled() ? ' selected="selected"' : '') . '>No</option>' . '</select></td>'; } } list($icon, $title) = $this->getRecordPreview($context, $uid); $content .= '<tr class="db_list_normal">' . '<td class="tx_contexts_context col-icon"">' . $icon . '</td>' . '<td class="tx_contexts_context">' . '<span class="context-' . ($bHasSetting ? 'active' : 'inactive') . '">' . $title . '</span>' . '</td>' . $contSettings . '</tr>'; } if ($visibleContexts == 0) { $content .= '<tr>' . '<td colspan="4" style="text-align: center">' . $fobj->sL('LLL:' . Tx_Contexts_Api_Configuration::LANG_FILE . ':no_contexts') . '</td>' . '</tr>'; } $content .= '</tbody></table>'; return $content; }
/** * Initialization of the class. * * @return void * @todo Define visibility */ public function init() { // Init GPvars: $this->P = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('P'); $this->returnEditConf = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('returnEditConf'); // Get this record $origRow = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord($this->P['table'], $this->P['uid']); // Set table: $this->table = $this->P['params']['table']; // Get TSconfig for it. $TSconfig = \TYPO3\CMS\Backend\Utility\BackendUtility::getTCEFORM_TSconfig($this->P['table'], is_array($origRow) ? $origRow : array('pid' => $this->P['pid'])); // Set [params][pid] if (substr($this->P['params']['pid'], 0, 3) == '###' && substr($this->P['params']['pid'], -3) == '###') { $this->pid = intval($TSconfig['_' . substr($this->P['params']['pid'], 3, -3)]); } else { $this->pid = intval($this->P['params']['pid']); } // Return if new record as parent (not possibly/allowed) if (!strcmp($this->pid, '')) { \TYPO3\CMS\Core\Utility\HttpUtility::redirect(\TYPO3\CMS\Core\Utility\GeneralUtility::sanitizeLocalUrl($this->P['returnUrl'])); } // Else proceed: // If a new id has returned from a newly created record... if ($this->returnEditConf) { $eC = unserialize($this->returnEditConf); if (is_array($eC[$this->table]) && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($this->P['uid'])) { // Getting id and cmd from returning editConf array. reset($eC[$this->table]); $this->id = intval(key($eC[$this->table])); $cmd = current($eC[$this->table]); // ... and if everything seems OK we will register some classes for inclusion and instruct the object to perform processing later. if ($this->P['params']['setValue'] && $cmd == 'edit' && $this->id && $this->P['table'] && $this->P['field'] && $this->P['uid']) { if ($LiveRec = \TYPO3\CMS\Backend\Utility\BackendUtility::getLiveVersionOfRecord($this->table, $this->id, 'uid')) { $this->id = $LiveRec['uid']; } $this->processDataFlag = 1; } } } }
/** * Release version from this workspace (and into "Live" workspace but as an offline version). * * @param string $table Table name * @param int $id Record UID * @param bool $flush If set, will completely delete element * @param DataHandler $dataHandler DataHandler object * @return void */ protected function version_clearWSID($table, $id, $flush = false, DataHandler $dataHandler) { if ($errorCode = $dataHandler->BE_USER->workspaceCannotEditOfflineVersion($table, $id)) { $dataHandler->newlog('Attempt to reset workspace for record failed: ' . $errorCode, 1); return; } if (!$dataHandler->checkRecordUpdateAccess($table, $id)) { $dataHandler->newlog('Attempt to reset workspace for record failed because you do not have edit access', 1); return; } $liveRec = BackendUtility::getLiveVersionOfRecord($table, $id, 'uid,t3ver_state'); if (!$liveRec) { return; } // Clear workspace ID: $updateData = ['t3ver_wsid' => 0, 't3ver_tstamp' => $GLOBALS['EXEC_TIME']]; $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table); $connection->update($table, $updateData, ['uid' => (int) $id]); // Clear workspace ID for live version AND DELETE IT as well because it is a new record! if (VersionState::cast($liveRec['t3ver_state'])->equals(VersionState::NEW_PLACEHOLDER) || VersionState::cast($liveRec['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)) { $connection->update($table, $updateData, ['uid' => (int) $liveRec['uid']]); // THIS assumes that the record was placeholder ONLY for ONE record (namely $id) $dataHandler->deleteEl($table, $liveRec['uid'], true); } // If "deleted" flag is set for the version that got released // it doesn't make sense to keep that "placeholder" anymore and we delete it completly. $wsRec = BackendUtility::getRecord($table, $id); if ($flush || (VersionState::cast($wsRec['t3ver_state'])->equals(VersionState::NEW_PLACEHOLDER) || VersionState::cast($wsRec['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER))) { $dataHandler->deleteEl($table, $id, true, true); } // Remove the move-placeholder if found for live record. if (BackendUtility::isTableWorkspaceEnabled($table)) { if ($plhRec = BackendUtility::getMovePlaceholder($table, $liveRec['uid'], 'uid')) { $dataHandler->deleteEl($table, $plhRec['uid'], true, true); } } }
/** * Make selector box for creating new translation for a record or switching to edit the record in an existing * language. * Displays only languages which are available for the current page. * * @param string $table Table name * @param int $uid Uid for which to create a new language * @param int $pid Pid of the record */ public function languageSwitch($table, $uid, $pid = null) { $languageField = $GLOBALS['TCA'][$table]['ctrl']['languageField']; $transOrigPointerField = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']; // Table editable and activated for languages? if ($this->getBackendUser()->check('tables_modify', $table) && $languageField && $transOrigPointerField && $table !== 'pages_language_overlay') { if (is_null($pid)) { $row = BackendUtility::getRecord($table, $uid, 'pid'); $pid = $row['pid']; } // Get all available languages for the page $langRows = $this->getLanguages($pid); // Page available in other languages than default language? if (is_array($langRows) && count($langRows) > 1) { $rowsByLang = []; $fetchFields = 'uid,' . $languageField . ',' . $transOrigPointerField; // Get record in current language $rowCurrent = BackendUtility::getLiveVersionOfRecord($table, $uid, $fetchFields); if (!is_array($rowCurrent)) { $rowCurrent = BackendUtility::getRecord($table, $uid, $fetchFields); } $currentLanguage = (int) $rowCurrent[$languageField]; // Disabled for records with [all] language! if ($currentLanguage > -1) { // Get record in default language if needed if ($currentLanguage && $rowCurrent[$transOrigPointerField]) { $rowsByLang[0] = BackendUtility::getLiveVersionOfRecord($table, $rowCurrent[$transOrigPointerField], $fetchFields); if (!is_array($rowsByLang[0])) { $rowsByLang[0] = BackendUtility::getRecord($table, $rowCurrent[$transOrigPointerField], $fetchFields); } } else { $rowsByLang[$rowCurrent[$languageField]] = $rowCurrent; } if ($rowCurrent[$transOrigPointerField] || $currentLanguage === 0) { // Get record in other languages to see what's already available $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table); $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class))->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class)); $result = $queryBuilder->select(...GeneralUtility::trimExplode(',', $fetchFields, true))->from($table)->where($queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pid, \PDO::PARAM_INT)), $queryBuilder->expr()->gt($languageField, $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)), $queryBuilder->expr()->eq($transOrigPointerField, $queryBuilder->createNamedParameter($rowsByLang[0]['uid'], \PDO::PARAM_INT)))->execute(); while ($row = $result->fetch()) { $rowsByLang[$row[$languageField]] = $row; } } $languageMenu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu(); $languageMenu->setIdentifier('_langSelector'); $languageMenu->setLabel(htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.language'))); foreach ($langRows as $lang) { if ($this->getBackendUser()->checkLanguageAccess($lang['uid'])) { $newTranslation = isset($rowsByLang[$lang['uid']]) ? '' : ' [' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.new')) . ']'; // Create url for creating a localized record $addOption = true; if ($newTranslation) { $redirectUrl = BackendUtility::getModuleUrl('record_edit', ['justLocalized' => $table . ':' . $rowsByLang[0]['uid'] . ':' . $lang['uid'], 'returnUrl' => $this->retUrl]); if ($currentLanguage === 0) { $href = BackendUtility::getLinkToDataHandlerAction('&cmd[' . $table . '][' . $rowsByLang[0]['uid'] . '][localize]=' . $lang['uid'], $redirectUrl); } else { $addOption = false; } } else { $href = BackendUtility::getModuleUrl('record_edit', ['edit[' . $table . '][' . $rowsByLang[$lang['uid']]['uid'] . ']' => 'edit', 'returnUrl' => $this->retUrl]); } if ($addOption) { $menuItem = $languageMenu->makeMenuItem()->setTitle($lang['title'] . $newTranslation)->setHref($href); if ((int) $lang['uid'] === $currentLanguage) { $menuItem->setActive(true); } $languageMenu->addMenuItem($menuItem); } } } $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($languageMenu); } } } }
/** * Get the final pid based on $table and $pid ($destPid type... pos/neg) * * @param string $table Table name * @param int $pid "Destination pid" : If the value is >= 0 it's just returned directly (through (int)though) but if the value is <0 then the method looks up the record with the uid equal to abs($pid) (positive number) and returns the PID of that record! The idea is that negative numbers point to the record AFTER WHICH the position is supposed to be! * @return int */ public function resolvePid($table, $pid) { $pid = (int) $pid; if ($pid < 0) { $query = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table); $query->getRestrictions()->removeAll(); $row = $query->select('pid')->from($table)->where($query->expr()->eq('uid', $query->createNamedParameter(abs($pid), \PDO::PARAM_INT)))->execute()->fetch(); // Look, if the record UID happens to be an offline record. If so, find its live version. // Offline uids will be used when a page is versionized as "branch" so this is when we // must correct - otherwise a pid of "-1" and a wrong sort-row number // is returned which we don't want. if ($lookForLiveVersion = BackendUtility::getLiveVersionOfRecord($table, abs($pid), 'pid')) { $row = $lookForLiveVersion; } $pid = (int) $row['pid']; } return $pid; }