Index: t3lib/class.t3lib_tcemain.php
===================================================================
--- t3lib/class.t3lib_tcemain.php (revision 6108)
+++ t3lib/class.t3lib_tcemain.php (working copy)
@@ -2731,100 +2731,109 @@
}
// Now, the $uid is the actual record we will copy while $origUid is the record we asked to get copied - but that could be a live version.
*/
+
+
if ($this->doesRecordExist($table,$uid,'show')) { // This checks if the record can be selected which is all that a copy action requires.
- $data = Array();
+ if( $this->BE_USER->recordEditAccessInternals($table,$uid, false, false, true ) ) { //Used to check language and general editing rights
+ $data = Array();
- $nonFields = array_unique(t3lib_div::trimExplode(',','uid,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,t3ver_oid,t3ver_wsid,t3ver_id,t3ver_label,t3ver_state,t3ver_swapmode,t3ver_count,t3ver_stage,t3ver_tstamp,'.$excludeFields,1));
+ $nonFields = array_unique(t3lib_div::trimExplode(',','uid,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,t3ver_oid,t3ver_wsid,t3ver_id,t3ver_label,t3ver_state,t3ver_swapmode,t3ver_count,t3ver_stage,t3ver_tstamp,'.$excludeFields,1));
- // $row = $this->recordInfo($table,$uid,'*');
- $row = t3lib_BEfunc::getRecordWSOL($table,$uid); // So it copies (and localized) content from workspace...
- if (is_array($row)) {
+ // $row = $this->recordInfo($table,$uid,'*');
+ $row = t3lib_BEfunc::getRecordWSOL($table,$uid); // So it copies (and localized) content from workspace...
+ if (is_array($row)) {
- // Initializing:
- $theNewID = uniqid('NEW');
- $enableField = isset($TCA[$table]['ctrl']['enablecolumns']) ? $TCA[$table]['ctrl']['enablecolumns']['disabled'] : '';
- $headerField = $TCA[$table]['ctrl']['label'];
+ // Initializing:
+ $theNewID = uniqid('NEW');
+ $enableField = isset($TCA[$table]['ctrl']['enablecolumns']) ? $TCA[$table]['ctrl']['enablecolumns']['disabled'] : '';
+ $headerField = $TCA[$table]['ctrl']['label'];
- // Getting default data:
- $defaultData = $this->newFieldArray($table);
+ // Getting default data:
+ $defaultData = $this->newFieldArray($table);
- // Getting "copy-after" fields if applicable:
- $copyAfterFields = $destPid<0 ? $this->fixCopyAfterDuplFields($table,$uid,abs($destPid),0) : array();
+ // Getting "copy-after" fields if applicable:
+ $copyAfterFields = $destPid<0 ? $this->fixCopyAfterDuplFields($table,$uid,abs($destPid),0) : array();
- // Page TSconfig related:
- $tscPID = t3lib_BEfunc::getTSconfig_pidValue($table,$uid,$destPid); // NOT using t3lib_BEfunc::getTSCpid() because we need the real pid - not the ID of a page, if the input is a page...
- $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
- $tE = $this->getTableEntries($table,$TSConfig);
+ // Page TSconfig related:
+ $tscPID = t3lib_BEfunc::getTSconfig_pidValue($table,$uid,$destPid); // NOT using t3lib_BEfunc::getTSCpid() because we need the real pid - not the ID of a page, if the input is a page...
+ $TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
+ $tE = $this->getTableEntries($table,$TSConfig);
- // Traverse ALL fields of the selected record:
- foreach($row as $field => $value) {
- if (!in_array($field,$nonFields)) {
+ // Traverse ALL fields of the selected record:
+ foreach($row as $field => $value) {
+ if (!in_array($field,$nonFields)) {
- // Get TCA configuration for the field:
- $conf = $TCA[$table]['columns'][$field]['config'];
+ // Get TCA configuration for the field:
+ $conf = $TCA[$table]['columns'][$field]['config'];
- // Preparation/Processing of the value:
- if ($field=='pid') { // "pid" is hardcoded of course:
- $value = $destPid;
- } elseif (isset($overrideValues[$field])) { // Override value...
- $value = $overrideValues[$field];
- } elseif (isset($copyAfterFields[$field])) { // Copy-after value if available:
- $value = $copyAfterFields[$field];
- } elseif ($TCA[$table]['ctrl']['setToDefaultOnCopy'] && t3lib_div::inList($TCA[$table]['ctrl']['setToDefaultOnCopy'],$field)) { // Revert to default for some fields:
- $value = $defaultData[$field];
- } else {
- // Hide at copy may override:
- if ($first && $field==$enableField && $TCA[$table]['ctrl']['hideAtCopy'] && !$this->neverHideAtCopy && !$tE['disableHideAtCopy']) {
- $value=1;
+ // Preparation/Processing of the value:
+ if ($field=='pid') { // "pid" is hardcoded of course:
+ $value = $destPid;
+ } elseif (isset($overrideValues[$field])) { // Override value...
+ $value = $overrideValues[$field];
+ } elseif (isset($copyAfterFields[$field])) { // Copy-after value if available:
+ $value = $copyAfterFields[$field];
+ } elseif ($TCA[$table]['ctrl']['setToDefaultOnCopy'] && t3lib_div::inList($TCA[$table]['ctrl']['setToDefaultOnCopy'],$field)) { // Revert to default for some fields:
+ $value = $defaultData[$field];
+ } else {
+ // Hide at copy may override:
+ if ($first && $field==$enableField && $TCA[$table]['ctrl']['hideAtCopy'] && !$this->neverHideAtCopy && !$tE['disableHideAtCopy']) {
+ $value=1;
+ }
+ // Prepend label on copy:
+ if ($first && $field==$headerField && $TCA[$table]['ctrl']['prependAtCopy'] && !$tE['disablePrependAtCopy']) {
+ $value = $this->getCopyHeader($table,$this->resolvePid($table,$destPid),$field,$this->clearPrefixFromValue($table,$value),0);
+ }
+ // Processing based on the TCA config field type (files, references, flexforms...)
+ $value = $this->copyRecord_procBasedOnFieldType($table, $uid, $field, $value, $row, $conf, $tscPID, $language);
}
- // Prepend label on copy:
- if ($first && $field==$headerField && $TCA[$table]['ctrl']['prependAtCopy'] && !$tE['disablePrependAtCopy']) {
- $value = $this->getCopyHeader($table,$this->resolvePid($table,$destPid),$field,$this->clearPrefixFromValue($table,$value),0);
- }
- // Processing based on the TCA config field type (files, references, flexforms...)
- $value = $this->copyRecord_procBasedOnFieldType($table, $uid, $field, $value, $row, $conf, $tscPID, $language);
+
+ // Add value to array.
+ $data[$table][$theNewID][$field] = $value;
}
+ }
+ // Overriding values:
+ if ($TCA[$table]['ctrl']['editlock']) {
+ $data[$table][$theNewID][$TCA[$table]['ctrl']['editlock']] = 0;
+ }
- // Add value to array.
- $data[$table][$theNewID][$field] = $value;
+ // Setting original UID:
+ if ($TCA[$table]['ctrl']['origUid']) {
+ $data[$table][$theNewID][$TCA[$table]['ctrl']['origUid']] = $uid;
}
- }
- // Overriding values:
- if ($TCA[$table]['ctrl']['editlock']) {
- $data[$table][$theNewID][$TCA[$table]['ctrl']['editlock']] = 0;
- }
+ // Do the copy by simply submitting the array through TCEmain:
+ $copyTCE = t3lib_div::makeInstance('t3lib_TCEmain');
+ /* @var $copyTCE t3lib_TCEmain */
+ $copyTCE->stripslashes_values = 0;
+ $copyTCE->copyTree = $this->copyTree;
+ $copyTCE->cachedTSconfig = $this->cachedTSconfig; // Copy forth the cached TSconfig
+ $copyTCE->dontProcessTransformations=1; // Transformations should NOT be carried out during copy
- // Setting original UID:
- if ($TCA[$table]['ctrl']['origUid']) {
- $data[$table][$theNewID][$TCA[$table]['ctrl']['origUid']] = $uid;
- }
+ $copyTCE->start($data,'',$this->BE_USER);
+ $copyTCE->process_datamap();
- // Do the copy by simply submitting the array through TCEmain:
- $copyTCE = t3lib_div::makeInstance('t3lib_TCEmain');
- /* @var $copyTCE t3lib_TCEmain */
- $copyTCE->stripslashes_values = 0;
- $copyTCE->copyTree = $this->copyTree;
- $copyTCE->cachedTSconfig = $this->cachedTSconfig; // Copy forth the cached TSconfig
- $copyTCE->dontProcessTransformations=1; // Transformations should NOT be carried out during copy
+ // Getting the new UID:
+ $theNewSQLID = $copyTCE->substNEWwithIDs[$theNewID];
+ if ($theNewSQLID) {
+ $this->copyRecord_fixRTEmagicImages($table,t3lib_BEfunc::wsMapId($table,$theNewSQLID));
+ $this->copyMappingArray[$table][$origUid] = $theNewSQLID;
+ }
- $copyTCE->start($data,'',$this->BE_USER);
- $copyTCE->process_datamap();
+ // Copy back the cached TSconfig
+ $this->cachedTSconfig = $copyTCE->cachedTSconfig;
+ $this->errorLog = array_merge($this->errorLog,$copyTCE->errorLog);
+ unset($copyTCE);
- // Getting the new UID:
- $theNewSQLID = $copyTCE->substNEWwithIDs[$theNewID];
- if ($theNewSQLID) {
- $this->copyRecord_fixRTEmagicImages($table,t3lib_BEfunc::wsMapId($table,$theNewSQLID));
- $this->copyMappingArray[$table][$origUid] = $theNewSQLID;
- }
+ if($language == 0) {
+ //repointing the new translation records to the parent record we just created
+ $overrideValues[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] = $theNewSQLID;
+ $this->copyL10nOverlayRecords($table, $uid, $destPid, $first, $overrideValues, $excludeFields='');
+ }
- // Copy back the cached TSconfig
- $this->cachedTSconfig = $copyTCE->cachedTSconfig;
- $this->errorLog = array_merge($this->errorLog,$copyTCE->errorLog);
- unset($copyTCE);
-
- return $theNewSQLID;
- } else $this->log($table,$uid,3,0,1,'Attempt to copy record that did not exist!');
+ return $theNewSQLID;
+ } else $this->log($table,$uid,3,0,1,'Attempt to copy record that did not exist!');
+ } else $this->log($table,$uid,3,0,1,'Attempt to copy record without having permissions to do so. ['.$this->BE_USER->errorMsg.'].');
} else $this->log($table,$uid,3,0,1,'Attempt to copy record without permission');
}
}
@@ -3367,7 +3376,26 @@
+ /**
+ * Find l10n-overlay records and perform the requested move action for these records.
+ *
+ * @param string $table: Record Table
+ * @param string $uid: Record UID
+ * @param string $destPid: Position to move to
+ * @return void
+ */
+ function copyL10nOverlayRecords($table, $uid, $destPid, $first=0, $overrideValues=array(), $excludeFields='') {
+ //there's no need to perform this for page-records
+ if( $table == 'pages' ) return;
+ t3lib_div::loadTCA( $table );
+ $l10nRecords = t3lib_BEfunc::getRecordsByField( $table, $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'], $uid );
+ if( is_array($l10nRecords) ) {
+ foreach( $l10nRecords as $record ) {
+ $this->copyRecord($table, $record['uid'], $destPid, $first, $overrideValues, $excludeFields, $record[$GLOBALS['TCA'][$table]['ctrl']['languageField']]);
+ }
+ }
+ }
@@ -3377,6 +3405,7 @@
+
/*********************************************
*
* Cmd: Moving, Localizing
@@ -3424,7 +3453,7 @@
}
// Checking if there is anything else disallowing moving the record by checking if editing is allowed
- $mayEditAccess = $this->BE_USER->recordEditAccessInternals($table,$uid);
+ $mayEditAccess = $this->BE_USER->recordEditAccessInternals($table,$uid, false, false, true );
// If moving is allowed, begin the processing:
if ($mayEditAccess) {
@@ -3539,6 +3568,14 @@
$newVersion_placeholderFieldArray['t3ver_wsid'] = $this->BE_USER->workspace; // Setting workspace - only so display of place holders can filter out those from other workspaces.
$newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['label']] = '[MOVE-TO PLACEHOLDER for #'.$uid.', WS#'.$this->BE_USER->workspace.']';
+ // moving localized records requires to keep localization-settings for the placeholder too
+ if( array_key_exists('languageField', $GLOBALS['TCA'][$table]['ctrl']) && array_key_exists('transOrigPointerField', $GLOBALS['TCA'][$table]['ctrl']) ) {
+ $l10nParentRec = t3lib_BEfunc::getRecord($table,$uid);
+ $newVersion_placeholderFieldArray[ $GLOBALS['TCA'][$table]['ctrl']['languageField'] ] = $l10nParentRec[ $GLOBALS['TCA'][$table]['ctrl']['languageField'] ];
+ $newVersion_placeholderFieldArray[ $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] ] = $l10nParentRec[ $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] ];
+ unset($l10nParentRec);
+ }
+
$newVersion_placeholderFieldArray['pid'] = 0; // Initially, create at root level.
$id = 'NEW_MOVE_PLH';
$this->insertDB($table,$id,$newVersion_placeholderFieldArray,FALSE); // Saving placeholder as 'original'
@@ -3551,6 +3588,9 @@
$updateFields['t3ver_state'] = 4; // Setting placeholder state value for version (so it can know it is currently a new version...)
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($wsUid), $updateFields);
}
+
+ //check for the localizations of that element and move them as well
+ $this->moveL10nOverlayRecords($table,$uid,$destPid);
}
/**
@@ -3608,6 +3648,8 @@
$this->moveRecord_procFields($table,$uid,$destPid);
// Create query for update:
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), $updateFields);
+ // check for the localizations of that element
+ $this->moveL10nOverlayRecords($table,$uid,$destPid);
// Call post processing hooks:
foreach($hookObjectsArr as $hookObj) {
@@ -3651,6 +3693,8 @@
$this->moveRecord_procFields($table,$uid,$destPid);
// Create query for update:
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), $updateFields);
+ // check for the localizations of that element
+ $this->moveL10nOverlayRecords($table,$uid,$destPid);
// Call post processing hooks:
foreach($hookObjectsArr as $hookObj) {
@@ -3749,6 +3793,27 @@
}
/**
+ * Find l10n-overlay records and perform the requested move action for these records.
+ *
+ * @param string $table: Record Table
+ * @param string $uid: Record UID
+ * @param string $destPid: Position to move to
+ * @return void
+ */
+ function moveL10nOverlayRecords($table,$uid,$destPid) {
+ //there's no need to perform this for page-records
+ if( $table == 'pages' ) return;
+ t3lib_div::loadTCA( $table );
+
+ $l10nRecords = t3lib_BEfunc::getRecordsByField( $table, $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'], $uid );
+ if( is_array($l10nRecords) ) {
+ foreach( $l10nRecords as $record ) {
+ $this->moveRecord( $table, $record['uid'], $destPid );
+ }
+ }
+ }
+
+ /**
* Localizes a record to another system language
* In reality it only works if transOrigPointerTable is not set. For "pages" the implementation is hardcoded
*
@@ -4013,6 +4078,7 @@
} else {
// Otherwise, try to delete by versioning:
$this->versionizeRecord($table,$id,'DELETED!',TRUE);
+ $this->deleteL10nOverlayRecords($table,$id);
}
}
}
@@ -4088,7 +4154,7 @@
global $TCA;
// Checking if there is anything else disallowing deleting the record by checking if editing is allowed
- $mayEditAccess = $this->BE_USER->recordEditAccessInternals($table, $uid, FALSE, $undeleteRecord);
+ $mayEditAccess = $this->BE_USER->recordEditAccessInternals($table, $uid, FALSE, $undeleteRecord, TRUE );
$uid = intval($uid);
if ($TCA[$table] && $uid) {
@@ -4114,10 +4180,14 @@
if ($TCA[$table]['ctrl']['sortby'] && !$undeleteRecord) {
$updateFields[$TCA[$table]['ctrl']['sortby']] = 1000000000;
}
-
// before (un-)deleting this record, check for child records or references
$this->deleteRecord_procFields($table, $uid, $undeleteRecord);
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), $updateFields);
+
+ // delete all l10n records aswell, impossible during undelete because it might bring too many records back to life
+ if( !$undeleteRecord ) {
+ $this->deleteL10nOverlayRecords($table, $uid);
+ }
} else {
// Fetches all fields with flexforms and look for files to delete:
@@ -4149,6 +4219,8 @@
// Delete the hard way...:
$GLOBALS['TYPO3_DB']->exec_DELETEquery($table, 'uid='.intval($uid));
+
+ $this->deleteL10nOverlayRecords($table, $uid);
}
$state = $undeleteRecord ? 1 : 3; // 1 means insert, 3 means delete
@@ -4413,13 +4485,33 @@
}
}
+ /**
+ * Find l10n-overlay records and perform the requested delete action for these records.
+ *
+ * @param string $table: Record Table
+ * @param string $uid: Record UID
+ * @param string $destPid: Position to move to
+ * @return void
+ */
+ function deleteL10nOverlayRecords($table, $uid) {
+ if( $table == 'pages' ) return;
+ t3lib_div::loadTCA( $table );
+ $l10nRecords = t3lib_BEfunc::getRecordsByField( $table, $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'], $uid );
+ if( is_array($l10nRecords) ) {
+ foreach( $l10nRecords as $record ) {
+ $this->deleteAction($table, intval($record['t3ver_oid'])>0?intval($record['t3ver_oid']):intval($record['uid']));
+ }
+ }
+ }
+
+
/*********************************************
*
* Cmd: Versioning
@@ -4620,6 +4712,10 @@
if ($TCA[$table]['ctrl']['sortby']) {
$keepFields[] = $TCA[$table]['ctrl']['sortby'];
}
+ // l10n-fields must be kept otherwise the localization will be lost during the publishing
+ if ( $TCA[$table]['ctrl']['transOrigPointerField'] ) {
+ $keepFields[] = $TCA[$table]['ctrl']['transOrigPointerField'];
+ }
// Swap "keepfields"
foreach($keepFields as $fN) {
Index: t3lib/class.t3lib_userauthgroup.php
===================================================================
--- t3lib/class.t3lib_userauthgroup.php (revision 6108)
+++ t3lib/class.t3lib_userauthgroup.php (working copy)
@@ -538,6 +538,39 @@
}
/**
+ * Check if user has access to all existing localizations for a certain record
+ *
+ * @param array $record
+ * @return boolean
+ */
+ function checkFullLanguagesAccess( $table, $record ) {
+ $recordLocalizationAccess = $this->checkLanguageAccess(0);
+ if ($recordLocalizationAccess && t3lib_BEfunc::isTableLocalizable($table) ) {
+
+ $pointerField = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'];
+
+ $recordLocalizations = t3lib_BEfunc::getRecordsByField(
+ $table,
+ $pointerField,
+ $record[$pointerField]>0 ? $record[$pointerField] : $record['uid'],
+ '', //AND '.$GLOBALS['TCA'][$table]['ctrl']['languageField'].'>0 '.($andWhereClause ? ' '.$andWhereClause : ''),
+ '',
+ '',
+ '1'
+ );
+
+ if(is_array($recordLocalizations)) {
+ foreach($recordLocalizations as $localization) {
+ $recordLocalizationAccess = $recordLocalizationAccess && $this->checkLanguageAccess( $localization[$GLOBALS['TCA'][$table]['ctrl']['languageField']] );
+ if(!$recordLocalizationAccess) break;
+ }
+ }
+
+ }
+ return $recordLocalizationAccess;
+ }
+
+ /**
* Checking if a user has editing access to a record from a $TCA table.
* The checks does not take page permissions and other "environmental" things into account. It only deal with record internals; If any values in the record fields disallows it.
* For instance languages settings, authMode selector boxes are evaluated (and maybe more in the future).
@@ -550,7 +583,7 @@
* @param boolean Set, if testing a deleted record array.
* @return boolean True if OK, otherwise false
*/
- function recordEditAccessInternals($table, $idOrRow, $newRecord = FALSE, $deletedRecord = FALSE) {
+ function recordEditAccessInternals($table, $idOrRow, $newRecord = FALSE, $deletedRecord = FALSE, $checkFullLanguageAccess = FALSE) {
global $TCA;
if (isset($TCA[$table])) {
@@ -578,6 +611,9 @@
if (!$this->checkLanguageAccess($idOrRow[$TCA[$table]['ctrl']['languageField']])) {
$this->errorMsg = 'ERROR: Language was not allowed.';
return FALSE;
+ } elseif( $checkFullLanguageAccess && !$this->checkFullLanguagesAccess($table, $idOrRow ) ) {
+ $this->errorMsg = 'ERROR: Related/affected language was not allowed.';
+ return FALSE;
}
} else {
$this->errorMsg = 'ERROR: The "languageField" field named "'.$TCA[$table]['ctrl']['languageField'].'" was not found in testing record!';
Index: typo3/class.db_list_extra.inc
===================================================================
--- typo3/class.db_list_extra.inc (revision 6108)
+++ typo3/class.db_list_extra.inc (working copy)
@@ -1322,17 +1322,17 @@
$cells=array();
$cells['pasteAfter'] = $cells['pasteInto'] = $this->spaceIcon;
-
+ $isL10nOverlay = $this->localizationView && $row[$TCA[$table]['ctrl']['transOrigPointerField']]!=0;
// Return blank, if disabled:
// Whether a numeric clipboard pad is active or the normal pad we will see different content of the panel:
if ($this->clipObj->current=='normal') { // For the "Normal" pad:
// Show copy/cut icons:
$isSel = (string)$this->clipObj->isSelected($table,$row['uid']);
- $cells['copy']=''.
+ $cells['copy']= $isL10nOverlay ? $this->spaceIcon : ''.
'backPath,'gfx/clip_copy'.($isSel=='copy'?'_h':'').'.gif','width="12" height="12"').' title="'.$LANG->sL('LLL:EXT:lang/locallang_core.php:cm.copy',1).'" alt="" />'.
'';
- $cells['cut']=''.
+ $cells['cut']= $isL10nOverlay ? $this->spaceIcon : ''.
'backPath,'gfx/clip_cut'.($isSel=='cut'?'_h':'').'.gif','width="12" height="12"').' title="'.$LANG->sL('LLL:EXT:lang/locallang_core.php:cm.cut',1).'" alt="" />'.
'';
@@ -1355,7 +1355,7 @@
}
// Adding the checkbox to the panel:
- $cells['select']='';
+ $cells['select']= $isL10nOverlay ? $this->spaceIcon : '';
}
// Now, looking for selected elements from the current table: