/** * Find l10n-overlay records and perform the requested delete action for these records. * * @param string $table: Record Table * @param string $uid: Record UID * @return void */ function deleteL10nOverlayRecords($table, $uid) { // Check whether table can be localized or has a different table defined to store localizations: if (!t3lib_BEfunc::isTableLocalizable($table) || !empty($GLOBALS['TCA'][$table]['ctrl']['transForeignTable']) || !empty($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable'])) { return; } $where = ''; if (isset($GLOBALS['TCA'][$table]['ctrl']['versioningWS'])) { $where = ' AND t3ver_oid=0'; } $l10nRecords = t3lib_BEfunc::getRecordsByField($table, $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'], $uid, $where); if (is_array($l10nRecords)) { foreach ($l10nRecords as $record) { $this->deleteAction($table, intval($record['t3ver_oid']) > 0 ? intval($record['t3ver_oid']) : intval($record['uid'])); } } }
/** * Check if user has access to all existing localizations for a certain record * * Patch adds hook and applies changes due to #13194 * * @param string the table * @param array the current record * @return boolean */ function checkFullLanguagesAccess($table, $record) { $recordLocalizationAccess = $this->checkLanguageAccess(0); if ($recordLocalizationAccess && (t3lib_BEfunc::isTableLocalizable($table) || isset($GLOBALS['TCA'][$table]['ctrl']['transForeignTable']))) { if (isset($GLOBALS['TCA'][$table]['ctrl']['transForeignTable'])) { $l10nTable = $GLOBALS['TCA'][$table]['ctrl']['transForeignTable']; $pointerField = $GLOBALS['TCA'][$l10nTable]['ctrl']['transOrigPointerField']; $pointerValue = $record['uid']; } else { $l10nTable = $table; $pointerField = $GLOBALS['TCA'][$l10nTable]['ctrl']['transOrigPointerField']; $pointerValue = $record[$pointerField] > 0 ? $record[$pointerField] : $record['uid']; } $recordLocalizations = t3lib_BEfunc::getRecordsByField($l10nTable, $pointerField, $pointerValue, '', '', '', '1'); if (is_array($recordLocalizations)) { foreach ($recordLocalizations as $localization) { $recordLocalizationAccess = $recordLocalizationAccess && $this->checkLanguageAccess($localization[$GLOBALS['TCA'][$l10nTable]['ctrl']['languageField']]); if (!$recordLocalizationAccess) { break; } } } } if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['checkFullLanguagesAccess'])) { foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['checkFullLanguagesAccess'] as $_funcRef) { $_params = array('table' => $table, 'row' => $record, 'recordLocalizationAccess' => $recordLocalizationAccess); $recordLocalizationAccess = t3lib_div::callUserFunction($_funcRef, $_params, $this); } } return $recordLocalizationAccess; }
/** * Builds the WHERE clauses of the Index Queue initialization query based * on TCA information for the type to be initialized. * * @return string Conditions to only add indexable items to the Index Queue */ protected function buildTcaWhereClause() { $tcaWhereClause = ''; $conditions = array(); if (isset($GLOBALS['TCA'][$this->type]['ctrl']['delete'])) { $conditions['delete'] = $GLOBALS['TCA'][$this->type]['ctrl']['delete'] . ' = 0'; } if (isset($GLOBALS['TCA'][$this->type]['ctrl']['enablecolumns']['disabled'])) { $conditions['disabled'] = $GLOBALS['TCA'][$this->type]['ctrl']['enablecolumns']['disabled'] . ' = 0'; } if (isset($GLOBALS['TCA'][$this->type]['ctrl']['enablecolumns']['endtime'])) { // only include records with a future endtime or default value (0) $endTimeFieldName = $GLOBALS['TCA'][$this->type]['ctrl']['enablecolumns']['endtime']; $conditions['endtime'] = '(' . $endTimeFieldName . ' > ' . time() . ' OR ' . $endTimeFieldName . ' = 0)'; } if (t3lib_BEfunc::isTableLocalizable($this->type)) { $conditions['languageField'] = array($GLOBALS['TCA'][$this->type]['ctrl']['languageField'] . ' = 0', $GLOBALS['TCA'][$this->type]['ctrl']['languageField'] . ' = -1'); if (isset($GLOBALS['TCA'][$this->type]['ctrl']['transOrigPointerField'])) { $conditions['languageField'][] = $GLOBALS['TCA'][$this->type]['ctrl']['transOrigPointerField'] . ' = 0'; // translations without original language source } $conditions['languageField'] = '(' . implode(' OR ', $conditions['languageField']) . ')'; } if (!empty($GLOBALS['TCA'][$this->type]['ctrl']['versioningWS'])) { // versioning is enabled for this table: exclude draft workspace records $conditions['versioningWS'] = 'pid != -1'; } if (count($conditions)) { $tcaWhereClause = ' AND ' . implode(' AND ', $conditions); } return $tcaWhereClause; }
/** * Gets all localizations of the current record. * * @param string the table * @param array the current record * @return string HTML table rows */ function getLocalizations($table, $parentRec, $bgColClass, $pad) { $lines = array(); $tcaCtrl = $GLOBALS['TCA'][$table]['ctrl']; if ($table != 'pages' && t3lib_BEfunc::isTableLocalizable($table) && !$tcaCtrl['transOrigPointerTable']) { $where = array(); $where[] = $tcaCtrl['transOrigPointerField'] . '=' . intval($parentRec['uid']); $where[] = $tcaCtrl['languageField'] . '!=0'; if (isset($tcaCtrl['delete']) && $tcaCtrl['delete']) { $where[] = $tcaCtrl['delete'] . '=0'; } if (isset($tcaCtrl['versioningWS']) && $tcaCtrl['versioningWS']) { $where[] = 't3ver_wsid=' . $parentRec['t3ver_wsid']; } $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', $table, implode(' AND ', $where)); if (is_array($rows)) { $modeData = ''; if ($pad == 'normal') { $mode = $this->clipData['normal']['mode'] == 'copy' ? 'copy' : 'cut'; $modeData = ' <strong>(' . $this->clLabel($mode, 'cm') . ')</strong>'; } foreach ($rows as $rec) { $lines[] = ' <tr> <td class="' . $bgColClass . '">' . t3lib_iconWorks::getSpriteIconForRecord($table, $rec, array('style' => "margin-left: 38px;")) . '</td> <td class="' . $bgColClass . '" nowrap="nowrap" width="95%"> ' . htmlspecialchars(t3lib_div::fixed_lgd_cs(t3lib_BEfunc::getRecordTitle($table, $rec), $GLOBALS['BE_USER']->uc['titleLen'])) . $modeData . ' </td> <td class="' . $bgColClass . '" align="center" nowrap="nowrap"> </td> </tr>'; } } } return implode('', $lines); }
/** * Check if user has access to all existing localizations for a certain record * * @param string the table * @param array the current record * @return boolean */ function checkFullLanguagesAccess($table, $record) { $recordLocalizationAccess = $this->checkLanguageAccess(0); if ($recordLocalizationAccess && (t3lib_BEfunc::isTableLocalizable($table) || isset($GLOBALS['TCA'][$table]['ctrl']['transForeignTable']))) { if (isset($GLOBALS['TCA'][$table]['ctrl']['transForeignTable'])) { $l10nTable = $GLOBALS['TCA'][$table]['ctrl']['transForeignTable']; $pointerField = $GLOBALS['TCA'][$l10nTable]['ctrl']['transOrigPointerField']; $pointerValue = $record['uid']; } else { $l10nTable = $table; $pointerField = $GLOBALS['TCA'][$l10nTable]['ctrl']['transOrigPointerField']; $pointerValue = $record[$pointerField] > 0 ? $record[$pointerField] : $record['uid']; } $recordLocalizations = t3lib_BEfunc::getRecordsByField($l10nTable, $pointerField, $pointerValue, '', '', '', '1'); if (is_array($recordLocalizations)) { foreach ($recordLocalizations as $localization) { $recordLocalizationAccess = $recordLocalizationAccess && $this->checkLanguageAccess($localization[$GLOBALS['TCA'][$l10nTable]['ctrl']['languageField']]); if (!$recordLocalizationAccess) { break; } } } } return $recordLocalizationAccess; }
/** * Make 1st level clickmenu: * * @param string Table name * @param integer UID for the current record. * @return string HTML content */ function printDBClickMenu($table, $uid) { global $TCA, $BE_USER; // Get record: $this->rec = t3lib_BEfunc::getRecordWSOL($table, $uid); $menuItems = array(); $root = 0; $DBmount = FALSE; if ($table == 'pages' && !strcmp($uid, '0')) { // Rootlevel $root = 1; } if ($table == 'pages' && in_array($uid, $GLOBALS['BE_USER']->returnWebmounts())) { // DB mount $DBmount = TRUE; } // used to hide cut,copy icons for l10n-records $l10nOverlay = false; // should only be performed for overlay-records within the same table if (t3lib_BEfunc::isTableLocalizable($table) && !isset($TCA[$table]['ctrl']['transOrigPointerTable'])) { $l10nOverlay = intval($this->rec[$TCA[$table]['ctrl']['transOrigPointerField']]) != 0; } // If record found (or root), go ahead and fill the $menuItems array which will contain data for the elements to render. if (is_array($this->rec) || $root) { // Get permissions $lCP = $BE_USER->calcPerms(t3lib_BEfunc::getRecord('pages', $table == 'pages' ? $this->rec['uid'] : $this->rec['pid'])); // View if (!in_array('view', $this->disabledItems)) { if ($table == 'pages') { $menuItems['view'] = $this->DB_view($uid); } if ($table == $GLOBALS['TYPO3_CONF_VARS']['SYS']['contentTable']) { $ws_rec = t3lib_BEfunc::getRecordWSOL($table, $this->rec['uid']); $menuItems['view'] = $this->DB_view($ws_rec['pid']); } } // Edit: if (!$root && ($BE_USER->isPSet($lCP, $table, 'edit') || $BE_USER->isPSet($lCP, $table, 'editcontent'))) { if (!in_array('edit', $this->disabledItems)) { $menuItems['edit'] = $this->DB_edit($table, $uid); } $this->editOK = 1; } // New: if (!in_array('new', $this->disabledItems) && $BE_USER->isPSet($lCP, $table, 'new')) { $menuItems['new'] = $this->DB_new($table, $uid); } // Info: if (!in_array('info', $this->disabledItems) && !$root) { $menuItems['info'] = $this->DB_info($table, $uid); } $menuItems['spacer1'] = 'spacer'; // Copy: if (!in_array('copy', $this->disabledItems) && !$root && !$DBmount && !$l10nOverlay) { $menuItems['copy'] = $this->DB_copycut($table, $uid, 'copy'); } // Cut: if (!in_array('cut', $this->disabledItems) && !$root && !$DBmount && !$l10nOverlay) { $menuItems['cut'] = $this->DB_copycut($table, $uid, 'cut'); } // Paste: $elFromAllTables = count($this->clipObj->elFromTable('')); if (!in_array('paste', $this->disabledItems) && $elFromAllTables) { $selItem = $this->clipObj->getSelectedRecord(); $elInfo = array(t3lib_div::fixed_lgd_cs($selItem['_RECORD_TITLE'], $BE_USER->uc['titleLen']), $root ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] : t3lib_div::fixed_lgd_cs(t3lib_BEfunc::getRecordTitle($table, $this->rec), $BE_USER->uc['titleLen']), $this->clipObj->currentMode()); if ($table == 'pages' && $lCP & 8) { if ($elFromAllTables) { $menuItems['pasteinto'] = $this->DB_paste('', $uid, 'into', $elInfo); } } $elFromTable = count($this->clipObj->elFromTable($table)); if (!$root && !$DBmount && $elFromTable && $TCA[$table]['ctrl']['sortby']) { $menuItems['pasteafter'] = $this->DB_paste($table, -$uid, 'after', $elInfo); } } // Delete: $elInfo = array(t3lib_div::fixed_lgd_cs(t3lib_BEfunc::getRecordTitle($table, $this->rec), $BE_USER->uc['titleLen'])); if (!in_array('delete', $this->disabledItems) && !$root && !$DBmount && $BE_USER->isPSet($lCP, $table, 'delete')) { $menuItems['spacer2'] = 'spacer'; $menuItems['delete'] = $this->DB_delete($table, $uid, $elInfo); } if (!in_array('history', $this->disabledItems)) { $menuItems['history'] = $this->DB_history($table, $uid, $elInfo); } } // Adding external elements to the menuItems array $menuItems = $this->processingByExtClassArray($menuItems, $table, $uid); // Processing by external functions? $menuItems = $this->externalProcessingOfDBMenuItems($menuItems); if (!is_array($this->rec)) { $this->rec = array(); } // Return the printed elements: return $this->printItems($menuItems, $root ? t3lib_iconWorks::getSpriteIcon('apps-pagetree-root') . htmlspecialchars($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']) : t3lib_iconWorks::getSpriteIconForRecord($table, $this->rec, array('title' => htmlspecialchars(t3lib_BEfunc::getRecordIconAltText($this->rec, $table)))) . t3lib_BEfunc::getRecordTitle($table, $this->rec, TRUE)); }
/** * Generation of TCEform elements of the type "inline" * This will render inline-relational-record sets. Relations. * * @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 */ function getSingleField_typeInline($table, $field, $row, &$PA) { // check the TCA configuration - if false is returned, something was wrong if ($this->checkConfiguration($PA['fieldConf']['config']) === false) { return false; } // count the number of processed inline elements $this->inlineCount++; // Init: $config = $PA['fieldConf']['config']; $foreign_table = $config['foreign_table']; t3lib_div::loadTCA($foreign_table); if (t3lib_BEfunc::isTableLocalizable($table)) { $language = intval($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']]); } $minitems = t3lib_div::intInRange($config['minitems'], 0); $maxitems = t3lib_div::intInRange($config['maxitems'], 0); if (!$maxitems) { $maxitems = 100000; } // Register the required number of elements: $this->fObj->requiredElements[$PA['itemFormElName']] = array($minitems, $maxitems, 'imgName' => $table . '_' . $row['uid'] . '_' . $field); // remember the page id (pid of record) where inline editing started first // we need that pid for ajax calls, so that they would know where the action takes place on the page structure if (!isset($this->inlineFirstPid)) { // if this record is not new, try to fetch the inlineView states // @TODO: Add checking/cleaning for unused tables, records, etc. to save space in uc-field if (t3lib_div::testInt($row['uid'])) { $inlineView = unserialize($GLOBALS['BE_USER']->uc['inlineView']); $this->inlineView = $inlineView[$table][$row['uid']]; } // If the parent is a page, use the uid(!) of the (new?) page as pid for the child records: if ($table == 'pages') { $this->inlineFirstPid = $row['uid']; // If pid is negative, fetch the previous record and take its pid: } elseif ($row['pid'] < 0) { $prevRec = t3lib_BEfunc::getRecord($table, abs($row['pid'])); $this->inlineFirstPid = $prevRec['pid']; // Take the pid as it is: } else { $this->inlineFirstPid = $row['pid']; } } // add the current inline job to the structure stack $this->pushStructure($table, $row['uid'], $field, $config); // e.g. data[<table>][<uid>][<field>] $nameForm = $this->inlineNames['form']; // e.g. data-<pid>-<table1>-<uid1>-<field1>-<table2>-<uid2>-<field2> $nameObject = $this->inlineNames['object']; // get the records related to this inline record $relatedRecords = $this->getRelatedRecords($table, $field, $row, $PA, $config); // set the first and last record to the config array $relatedRecordsUids = array_keys($relatedRecords['records']); $config['inline']['first'] = reset($relatedRecordsUids); $config['inline']['last'] = end($relatedRecordsUids); // Tell the browser what we have (using JSON later): $top = $this->getStructureLevel(0); $this->inlineData['config'][$nameObject] = array('table' => $foreign_table, 'md5' => md5($nameObject)); $this->inlineData['config'][$nameObject . self::Structure_Separator . $foreign_table] = array('min' => $minitems, 'max' => $maxitems, 'sortable' => $config['appearance']['useSortable'], 'top' => array('table' => $top['table'], 'uid' => $top['uid'])); // Set a hint for nested IRRE and tab elements: $this->inlineData['nested'][$nameObject] = $this->fObj->getDynNestedStack(false, $this->isAjaxCall); // if relations are required to be unique, get the uids that have already been used on the foreign side of the relation if ($config['foreign_unique']) { // If uniqueness *and* selector are set, they should point to the same field - so, get the configuration of one: $selConfig = $this->getPossibleRecordsSelectorConfig($config, $config['foreign_unique']); // Get the used unique ids: $uniqueIds = $this->getUniqueIds($relatedRecords['records'], $config, $selConfig['type'] == 'groupdb'); $possibleRecords = $this->getPossibleRecords($table, $field, $row, $config, 'foreign_unique'); $uniqueMax = $config['appearance']['useCombination'] || $possibleRecords === false ? -1 : count($possibleRecords); $this->inlineData['unique'][$nameObject . self::Structure_Separator . $foreign_table] = array('max' => $uniqueMax, 'used' => $uniqueIds, 'type' => $selConfig['type'], 'table' => $config['foreign_table'], 'elTable' => $selConfig['table'], 'field' => $config['foreign_unique'], 'selector' => $selConfig['selector'], 'possible' => $this->getPossibleRecordsFlat($possibleRecords)); } // if it's required to select from possible child records (reusable children), add a selector box if ($config['foreign_selector']) { // if not already set by the foreign_unique, set the possibleRecords here and the uniqueIds to an empty array if (!$config['foreign_unique']) { $possibleRecords = $this->getPossibleRecords($table, $field, $row, $config); $uniqueIds = array(); } $selectorBox = $this->renderPossibleRecordsSelector($possibleRecords, $config, $uniqueIds); $item .= $selectorBox; } // wrap all inline fields of a record with a <div> (like a container) $item .= '<div id="' . $nameObject . '">'; // define how to show the "Create new record" link - if there are more than maxitems, hide it if ($relatedRecords['count'] >= $maxitems || $uniqueMax > 0 && $relatedRecords['count'] >= $uniqueMax) { $config['inline']['inlineNewButtonStyle'] = 'display: none;'; } // Render the level links (create new record, localize all, synchronize): if ($config['appearance']['levelLinksPosition'] != 'none') { $levelLinks = $this->getLevelInteractionLink('newRecord', $nameObject . self::Structure_Separator . $foreign_table, $config); if ($language > 0) { // Add the "Localize all records" link before all child records: if (isset($config['appearance']['showAllLocalizationLink']) && $config['appearance']['showAllLocalizationLink']) { $levelLinks .= $this->getLevelInteractionLink('localize', $nameObject . self::Structure_Separator . $foreign_table, $config); } // Add the "Synchronize with default language" link before all child records: if (isset($config['appearance']['showSynchronizationLink']) && $config['appearance']['showSynchronizationLink']) { $levelLinks .= $this->getLevelInteractionLink('synchronize', $nameObject . self::Structure_Separator . $foreign_table, $config); } } } // Add the level links before all child records: if (in_array($config['appearance']['levelLinksPosition'], array('both', 'top'))) { $item .= $levelLinks; } $item .= '<div id="' . $nameObject . '_records">'; $relationList = array(); if (count($relatedRecords['records'])) { foreach ($relatedRecords['records'] as $rec) { $item .= $this->renderForeignRecord($row['uid'], $rec, $config); if (!isset($rec['__virtual']) || !$rec['__virtual']) { $relationList[] = $rec['uid']; } } } $item .= '</div>'; // Add the level links after all child records: if (in_array($config['appearance']['levelLinksPosition'], array('both', 'bottom'))) { $item .= $levelLinks; } // add Drag&Drop functions for sorting to TCEforms::$additionalJS_post if (count($relationList) > 1 && $config['appearance']['useSortable']) { $this->addJavaScriptSortable($nameObject . '_records'); } // publish the uids of the child records in the given order to the browser $item .= '<input type="hidden" name="' . $nameForm . '" value="' . implode(',', $relationList) . '" class="inlineRecord" />'; // close the wrap for all inline fields (container) $item .= '</div>'; // on finishing this section, remove the last item from the structure stack $this->popStructure(); // if this was the first call to the inline type, restore the values if (!$this->getStructureDepth()) { unset($this->inlineFirstPid); } return $item; }