Commit 4188bb92 authored by Kasper Skårhøj's avatar Kasper Skårhøj
Browse files

Versioning and localization details (See changelog)


git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@441 709f56b5-9817-0410-a4d7-c38de5d9e867
parent 8c7ec8eb
2004-08-26 Kasper Skårhøj,,, <kasperYYYY@typo3.com>
* Bugfix: in browse_links where the record listing contained links to clickmenus:
* Added "Save and View" support for records which has another language set; For instance content elements and page overlay records will now view the page with the "&L=xx" parameter set to the language they represent.
* Version selector (implemented in template class) implemented in all Web>* modules (depends on "version" extension)
* Support for versioning in Web>List module ("v" button) (depends on "version" extension)
* Bugfix: In Web>List the page icon is restored. "Was lost, but now is found."
* Bugfix: Fixed access control in the interface of the page module and wizard_rte; Now checks if user has proper permissions before displaying certain buttons. Not critical bug, but obviously confusing for users to see the editing forms like if they actually could edit...
* Added view-page icons in Web>Page module for the language column view.
* Added first support for versioning previews in the frontend (CONTENT and RECORD cObjects)
* Implemented new localization modes configurable with TypoScript, "config.sys_language_overlay" and "config.sys_language_softMergeIfNotBlank"
* Added automatic character set conversion of frontend output if metaCharset and renderCharset are different. Also incoming POST arrays are converted in the reverse direction.
* Changed calling order of TSFE->getCompressedTCarray() in "index_ts.php": Now it loads before ->getConfigArray(). Should be no difference to anyone except internal processing in tslib_fe which can now access the array a little before it usually could.
* Added t3lib_cs::convArray() for charset conversion of array contents.
2004-08-23 Kasper Skårhøj,,, <kasper@typo3.com>
* Implemented versioning API in tcemain plus other places. Still not functional for the broad public (will be in 3.8.0). Missing conceptual testing, implementation in the backend interface (still to be discussed how that is best done and fitting workflow) and not at all in the frontend.
......
......@@ -40,6 +40,11 @@ TCEmain:
- Support for MM-records which does NOT get deleted, but is kept... and then support for having data in those!!
- Support that the content of a single field can be stored in an external file instead.
- Support that a list of fields can be stored in an external XML file instead.
- Record Reference tracking in a table in TCEmain; Used to:
- Check before deletion that a record is not used.
- Used by TemplaVoila where it is hard to track references in FlexForms
- A backend module can regenerate the "index-table" if it becomes invalid over time for some reason...
- Used for import/export module and anywhere else where we are looking up references!
- VERSIONING:
- See description in appendix.
- LOGGING:
......@@ -58,8 +63,6 @@ TCEmain:
- BUG:
- if a file is uploaded (directly in the form) and there is an upper limit to the number of files which is then exceeded, the uploaded file is STILL copied to the upload folder and will thus be listed as "Files with no references at all (delete them!):"
- TCEmain: If there is a comma in the filename supplied as an uploaded file it will confuse the handling of files because the comma is also used to split the filename from each other. (29/04/2003). This is a problem with Inter-Photo Netprint where files uploaded by FTP with comma in the name will not be attached as they should. I think the solution should be found in TCEmain so any filename can be supplied as uploaded.
- CHECK: hideAtCopy - does it work??
- CHECK: copyAfterDuplFields - check it (tt_content).
- RELATED: DBint/admin, logging-display, TCEforms, Web>List
- IDEA: check for potential dangerous php-extension
- TCEforms/TCEmain available for frontend?
......@@ -73,7 +76,7 @@ TCEmain/TCEforms for FlexForms:
- ['pi_flexform']['config']['ds'] must be set to some default message making sense!
- CSH for flexforms
- TCEmain features:
- caching of references/files in meta data (for analysis tools)?
- caching of references/files in meta data (for analysis tools)? --> NO, rather use the "new" planned reference index table, see above.
- mapping values to a plain-text search field(s)
- Offering API functions for add/delete/move/copy
- Cleaning the original data in field since this may have an invalid structure if the data structure has changed in the meantime.
......@@ -106,14 +109,12 @@ TCEforms:
- Reflect possible tree-structure for records in Select/Items list
- a way to grant read for the selectors without displaying the storagefolder in the treeview?
- move one up / one down buttons for the list (also for GROUP element)
- Ability to move items when selecting/deselecting them. Or ability to gray out elements in the right list if selected.
- CHECK: "multiple" feature, single, sorted and non-sorted selections.
- Having elements ordered by the "list-order" of the selection selector must be done in JS (or tcemain)
- making copies of select fields etc - check that remapped records are OK treated (with foreign/neg_foreign + free string values)
- Letting one selectorbox set another hidden fields value apart from its own? [USE: When selecting a template, that also sets the DS value! (Thus a template is always selected!)]
- Exclude field selection better, in a tree?
- set the width of the selector field
- Exclude field selection better, in a tree? (in IFRAME, could be cool!)
- BUG: itemsArrayProcFunc only active IF there is an array! Shouldn't it be in any case?
- set the width of the selector field(s)
- GROUP type:
- [file] allow the selection of files from the system to be added as REFERENCES, not copied! (Message-ID: <003f01c23503$8cdd69d0$55333bd4@comtech>, + notify "illuminatus")
- In the thumbnail list add the Edit and view icons as in the good old days.
......@@ -123,20 +124,10 @@ TCEforms:
- See JH mail: Message-ID: <C018FF617C61AB4588D15494126A5C0F23E410@Soulman.hanno-kirchhoff.de>
- IFRAME alternative for Element Browser.
- set the width of the selector field(s)
- ? type:
- "Inverse relations"/"Foreign relations": A "Pseudo field", which lists records REFERING TO this record (foreign relations, eg. many small price-records belonging to ONE shop-article). Possibly this could also EDIT those references (attaching/adding new, removing old, no manual ordering though! - This is what RENE is doing (Message-Id: <E17LO4D-0002hj-00@cube.colorcube>)
- TRANSLATION:
- Concept for translation of other language versions simultaneously? (Showing the default/any language side-by-side?)
- Would require UTF-8 display in backend! (or at least using forceCharset being set!)
- Support for "original/translation" relationships:
- The idea is that a) one field from a record is configured in [ctrl] to hold the sys_language (0=default, x=translation of default) value AND b) another field is configured to keep a reference back to the original element (for the translated records)
- If the record is "default" then ALL fields are shown.
- If the record is "translated" then SOME fields are disabled for editing (as configured) BUT shown in the form for information (the value from the original).
- When the record is selected for display or whatever an API call can fetch the original record and take the value of those configured fields and overlay in the translation (exactly like we do with page_overlay_records)
- The core support basically is, that TCEforms automatically understands to disable the fields if needed and display the original content.
- see Message-ID: <200205300155190552.08F5563C@smtp.worldonline.dk>, Message-ID: <mailman.1055945641.8348.typo3-english@lists.netfielders.de>
- DISPLAY_CONDITIONS:
- "readonly" flag, or user group dependant. See "Message-Id: <200210241441.50295.r.fritz@colorcube.de>"
- ? type:
- "Inverse relations"/"Foreign relations": A "Pseudo field", which lists records REFERING TO this record (foreign relations, eg. many small price-records belonging to ONE shop-article). Possibly this could also EDIT those references (attaching/adding new, removing old, no manual ordering though! - This is what RENE is doing (Message-Id: <E17LO4D-0002hj-00@cube.colorcube>)
- BUGS:
- Ask to save record when you want to add a category with the "Plus" icon.
- CHECK: ###STORAGE_PID### incorrectly calculated?
......@@ -606,37 +597,60 @@ Authors: Julle and Kasper.
OK - ONE element having an official position in the TYPO3 page tree, thus holding the official "uid" of the element! (If this element was deleted from the system, so are all versions of that element!)
OK - All versions of this one element being a) at pid "-1" and b) a field "real_id" pointing to the official UID
OK - Pages-versioning: For all elements belonging to a version of a page; They are just copied and has no official new version or binding back to whatever element they came from. They just came along. And in fact, they could even have their own version history for them selves!
- Backend user access to elements is based on the access restrictions for the official element. THis must be implemented on core level.
- Preview in fronend
- At page level, done with a simple selector in the AdminPanel. Just like date/user/hidden is done.
- For other element, time will show.
- clear-cache actions when swapping?
? - Backend user access to elements is based on the access restrictions for the official element. THis must be implemented on core level.
- Preview in frontend:
OK - Pages can be previewed just by their UID (which will select the offline version!)
OK - For other elements, sending ADMCMD_vPrev array
- Selector in the AdminPanel selects:
- Version of page for current ID?
- TAG (across many records)
- Tagging:
- Setting tags across records for mass-swapping:
- A tag can only be set for ONE version of a record
- There is a default tag used when new versions are created called "draft". Users can create own tags and select one of those instead.
- Implicitly the published version is tagged "published"
- When a tag is swapped into published, the records swapped into archive will get a new tag to remind us that they were swapped out instead of that TAG. Something like "TAG-archive". Only done when TAG-swapping is used, not for spontaneous swapping.
- We might set states like "draft (never published, many), published (online, only 1), archive (has been published, many) - but what significance does that carry?
- Permission setting:
- That NO record with PID!=-1 OR PID!=-1 in rootline can be edited or otherwise! This will effectively LOCK every single record capable of versioning in the live tree!
Enabled for tables with:
- versioning enabled
- a certain extra flag set in [ctrl] (eg. "versioning_freezeOnline"
- Globally set with a flag in TYPO3_CONF_VARS (so we can build the first version of the site)
- "admin" users can circumvent it.
- Swapping versions:
OK - clear-cache actions when swapping?
OK - Swapping might need to exclude fields like "sorting" etc. Others could be imagined.
OK - copies:
OK - Swapping should consider if a PAGE record should be swapped record-only OR including its content!!
- Swapping pages (pids) should consider that some records might be left inside a versionized branch. Question is; Should ALL records swap pids, not only the versioning_followPages ones?
- TODO: When swapping; Check "unique" fields (like pages.alias) etc.
- Swap by TAG (across many records)
- Trunk/Branch:
OK - Create version of single page (as above)
OK - Create version of page branch (1-... levels)
OK (API) - Either create version of EACH page individually (like tagging in CVS)
OK (API) - Or create single-point-of-reference so that pages INSIDE can be swapped, deleted and created (just like content elements can)
- Requirement: Intelligent swapping of "sub-element" ids that CAN be traced back to the original!
- ID-swapping for versioned elements
- Pages-versioning and the impact of NOT swapping tt_content element uids:
- Backend:
OK - In list-module we might display a) an icon to a version selector (where diff-ing could be done, swapping performed etc.), b) show archive versions as children in the listing.
OK - In Page module + TemplaVoila page module: There will be a version selector implemented so users can switch around between versions.
- Pages-versioning and the impact of NOT swapping tt_content element uids:
- Loose anchor-points, manually made (could be hack-fixed by some intelligent copying tracking)
- TemplaVoila references to elements from other pages (will break, however bad practice to reference elements not in some sort of central library which will NEVER be page-versioned anyways)
- Insert-records could potentially do the same
- Impact assesment: Low.
- Clean-up module (in templavoila?) could also track such things
- Problems for non-templavoila sites would be low.
OK - Swapping might need to exclude fields like "sorting" etc. Others could be imagined.
OK - copies:
- What about a page alias?
- Trunk/Branch:
- Create version of single page (as above)
- Create version of page branch (1-... levels)
- Either create version of EACH page individually (like tagging in CVS)
- Or create single-point-of-reference so that pages INSIDE can be swapped, deleted and created (just like content elements can)
- Requirement: Intelligent swapping of "sub-element" ids that CAN be traced back to the original!
- Backend:
- For single-editing of records we will show a version list from which to choose a version to edit (just like the delete button is also hidden at multi-edit)
- In list-module we might display a) an icon to a version selector (where diff-ing could be done, swapping performed etc.), b) show archive versions as children in the listing.
- In Page module + TemplaVoila page module: There will be a version selector implemented so users can switch around between versions.
......
......@@ -275,6 +275,7 @@ class t3lib_BEfunc {
* @param string Table name
* @param array Record array passed by reference. As minimum, "pid" and "uid" fields must exist! "t3ver_oid" is nice and will save you a DB query.
* @return void (Passed by ref).
* @see t3lib_page::fixVersioningPid()
*/
function fixVersioningPid($table,&$rr) {
global $TCA;
......@@ -2752,14 +2753,21 @@ class t3lib_BEfunc {
);
// Add rows to output array:
$realPid = 0;
$outputRows = array();
while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
if ($uid==$row['uid']) {
$row['_CURRENT_VERSION']=TRUE;
$realPid = $row['pid'];
}
$outputRows[] = $row;
}
// Set real-pid:
foreach($outputRows as $idx => $oRow) {
$outputRows[$idx]['_REAL_PID'] = $realPid;
}
return $outputRows;
}
}
......
......@@ -505,6 +505,7 @@ class t3lib_cs {
* @param string To charset (the output charset wanted)
* @param boolean If set, then characters that are not available in the destination character set will be encoded as numeric entities
* @return string Converted string
* @see convArray()
*/
function conv($str,$fromCS,$toCS,$useEntityForNoChar=0) {
if ($fromCS==$toCS) return $str;
......@@ -535,6 +536,26 @@ class t3lib_cs {
return $str;
}
/**
* Convert all elements in ARRAY from one charset to another charset.
* NOTICE: Array is passed by reference!
*
* @param string Input array, possibly multidimensional
* @param string From charset (the current charset of the string)
* @param string To charset (the output charset wanted)
* @param boolean If set, then characters that are not available in the destination character set will be encoded as numeric entities
* @return void
* @see conv()
*/
function convArray(&$array,$fromCS,$toCS,$useEntityForNoChar=0) {
foreach($array as $key => $value) {
if (is_array($array[$key])) {
$this->convArray($array[$key],$fromCS,$toCS,$useEntityForNoChar);
} else {
$array[$key] = $this->conv($array[$key],$fromCS,$toCS,$useEntityForNoChar);
}
}
}
/**
* Converts $str from $charset to UTF-8
......
......@@ -102,11 +102,18 @@
class t3lib_pageSelect {
var $urltypes = Array('','http://','ftp://','mailto:');
var $where_hid_del = ' AND pages.deleted=0'; // This is not the final clauses. There will normally be conditions for the hidden,starttime and endtime fields as well. You MUST initialize the object by the init() function
var $sys_language_uid=0;
var $sys_language_uid = 0;
// Versioning preview related:
var $versioningPreview = FALSE; // If true, preview of other record versions is allowed. THIS MUST ONLY BE SET IF the page is not cached and truely previewed by a backend user!!!
var $versionPreviewMap = array(
# EXAMPLE: 'tt_content:421' => 427
);
// Internal, dynamic:
var $error_getRootLine = ''; // Error string set by getRootLine
var $error_getRootLine = ''; // Error string set by getRootLine()
var $error_getRootLine_failPid = 0; // Error uid set by getRootLine()
/**
......@@ -159,6 +166,7 @@ class t3lib_pageSelect {
function getPage($uid) {
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'pages', 'uid='.intval($uid).$this->where_hid_del);
if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
#?? $this->versionOL('pages',$row);
return $this->getPageOverlay($row);
}
return Array();
......@@ -174,6 +182,7 @@ class t3lib_pageSelect {
function getPage_noCheck($uid) {
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'pages', 'uid='.intval($uid).$this->deleteClause('pages'));
if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
#?? $this->versionOL('pages',$row);
return $this->getPageOverlay($row);
}
return Array();
......@@ -190,6 +199,7 @@ class t3lib_pageSelect {
$output = '';
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'pages', 'pid='.intval($uid).$this->where_hid_del, '', 'sorting', '1');
if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
#?? $this->versionOL('pages',$row);
$output = $this->getPageOverlay($row);
}
$GLOBALS['TYPO3_DB']->sql_free_result($res);
......@@ -241,6 +251,8 @@ class t3lib_pageSelect {
Currently the showHiddenRecords of TSFE set will allow pages_language_overlay records to be selected as they are child-records of a page.
However you may argue that the showHiddenField flag should determine this. But that's not how it's done right now.
*/
// Selecting overlay record:
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
implode(',',$fieldArr),
'pages_language_overlay',
......@@ -252,6 +264,14 @@ class t3lib_pageSelect {
'1'
);
$row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
if (is_array($row)) {
$row['_PAGES_OVERLAY'] = TRUE;
$this->versionOL('pages_language_overlay',$row);
// Unset vital fields that are NOT allowed to be selected:
unset($row['uid']);
unset($row['pid']);
}
}
}
......@@ -263,6 +283,61 @@ class t3lib_pageSelect {
}
}
/**
* Creates language-overlay for records in general (where translation is found in records from the same table)
*
* @param string Table name
* @param array Record to overlay. Must containt uid, pid and $table]['ctrl']['languageField']
* @param integer Pointer to the sys_language uid for content on the site.
* @param string Overlay mode. If "hideNonTranslated" then records without translation will not be returned un-translated but unset (and return value is false)
* @return mixed Returns the input record, possibly overlaid with a translation. But if $OLmode is "hideNonTranslated" then it will return false if no translation is found.
*/
function getRecordOverlay($table,$row,$sys_language_content,$OLmode) {
global $TCA;
if ($sys_language_content>0 && $row['uid']>0 && $row['pid']>0) {
if ($TCA[$table] && $TCA[$table]['ctrl']['languageField'] && $TCA[$table]['ctrl']['transOrigPointerField']) {
if (!$TCA[$table]['ctrl']['transOrigPointerTable']) { // Will not be able to work with other tables (Just didn't implement it yet; Requires a scan over all tables [ctrl] part for first FIND the table that carries localization information for this table (which could even be more than a single table) and then use that. Could be implemented, but obviously takes a little more....)
if ($row[$TCA[$table]['ctrl']['languageField']]==0) { // Must be default language, otherwise no deal...
// Select overlay record:
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
'*',
$table,
'pid='.intval($row['pid']).
' AND '.$TCA[$table]['ctrl']['languageField'].'='.intval($sys_language_content).
' AND '.$TCA[$table]['ctrl']['transOrigPointerField'].'='.intval($row['uid']).
$this->enableFields($table),
'',
'',
'1'
);
$olrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
$this->versionOL($table,$olrow);
#debug($row);
#debug($olrow);
// Merge record content by traversing all fields:
if (is_array($olrow)) {
foreach($row as $fN => $fV) {
if ($fN!='uid' && $fN!='pid' && isset($olrow[$fN])) {
if ($GLOBALS['TSFE']->TCAcachedExtras[$table]['l10n_mode'][$fN]!='exclude'
&& ($GLOBALS['TSFE']->TCAcachedExtras[$table]['l10n_mode'][$fN]!='mergeIfNotBlank' || strcmp(trim($olrow[$fN]),''))) {
$row[$fN] = $olrow[$fN];
}
}
}
} elseif ($OLmode=='hideNonTranslated') {
unset($row);
}
}
}
}
}
return $row;
}
......@@ -302,6 +377,7 @@ class t3lib_pageSelect {
$output = Array();
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fields, 'pages', 'pid='.intval($uid).$this->where_hid_del.' '.$addWhere, '', $sortField);
while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
#?? $this->versionOL('pages',$row);
// Keep mount point:
$origUid = $row['uid'];
......@@ -383,8 +459,9 @@ class t3lib_pageSelect {
function getRootLine($uid, $MP='', $ignoreMPerrors=FALSE) {
// Initialize:
$selFields = t3lib_div::uniqueList('pid,uid,title,alias,nav_title,media,layout,hidden,starttime,endtime,fe_group,extendToSubpages,doktype,TSconfig,storage_pid,is_siteroot,mount_pid,mount_pid_ol,'.$GLOBALS['TYPO3_CONF_VARS']['FE']['addRootLineFields']);
$selFields = t3lib_div::uniqueList('pid,uid,t3ver_oid,title,alias,nav_title,media,layout,hidden,starttime,endtime,fe_group,extendToSubpages,doktype,TSconfig,storage_pid,is_siteroot,mount_pid,mount_pid_ol,'.$GLOBALS['TYPO3_CONF_VARS']['FE']['addRootLineFields']);
$this->error_getRootLine = '';
$this->error_getRootLine_failPid = 0;
// Splitting the $MP parameters if present
$MPA = array();
......@@ -403,6 +480,8 @@ class t3lib_pageSelect {
while ($uid!=0 && $loopCheck<20) { // Max 20 levels in the page tree.
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($selFields, 'pages', 'uid='.intval($uid).' AND pages.deleted=0 AND pages.doktype!=255');
if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
$this->fixVersioningPid('pages',$row);
#?? $this->versionOL('pages',$row);
// Mount Point page types are allowed ONLY a) if they are the outermost record in rootline and b) if the overlay flag is not set:
if ($GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids'] && $row['doktype']==7 && !$ignoreMPerrors) {
......@@ -424,6 +503,8 @@ class t3lib_pageSelect {
$mp_row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
if (is_array($mp_row)) {
$this->fixVersioningPid('pages',$mp_row);
#?? $this->versionOL('pages',$mp_row);
$mount_info = $this->getMountPointInfo($mp_row['uid'], $mp_row);
if (is_array($mount_info) && $mount_info['mount_pid']==$curMP[0]) {
$uid = $mp_row['pid']; // Setting next uid
......@@ -460,6 +541,7 @@ class t3lib_pageSelect {
$theRowArray[] = $this->getPageOverlay($row);
} else {
$this->error_getRootLine = 'Broken rootline';
$this->error_getRootLine_failPid = $uid;
return array(); // broken rootline.
}
......@@ -544,6 +626,7 @@ class t3lib_pageSelect {
if (!is_array($pageRec)) {
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,pid,doktype,mount_pid,mount_pid_ol', 'pages', 'uid='.intval($pageId).' AND pages.deleted=0 AND pages.doktype!=255');
$pageRec = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
#?? $this->versionOL('pages',$pageRec);
}
// Set first Page uid:
......@@ -557,6 +640,7 @@ class t3lib_pageSelect {
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,pid,doktype,mount_pid,mount_pid_ol', 'pages', 'uid='.$mount_pid.' AND pages.deleted=0 AND pages.doktype!=255');
$mount_rec = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
if (is_array($mount_rec)) {
#?? $this->versionOL('pages',$mount_rec);
// Look for recursive mount point:
$prevMountPids[] = $mount_pid;
......@@ -618,6 +702,7 @@ class t3lib_pageSelect {
if (is_array($TCA[$table])) {
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid='.intval($uid).$this->enableFields($table));
if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
#?? $this->versionOL($table,$row);
$GLOBALS['TYPO3_DB']->sql_free_result($res);
if ($checkPage) {
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'uid='.intval($row['pid']).$this->enableFields('pages'));
......@@ -645,9 +730,10 @@ class t3lib_pageSelect {
function getRawRecord($table,$uid,$fields='*') {
global $TCA;
$uid = intval($uid);
if (is_array($TCA[$table])) {
if (is_array($TCA[$table]) || $table=='pages') { // Excluding pages here so we can ask the function BEFORE TCA gets initialized. Support for this is followed up in deleteClause()...
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fields, $table, 'uid='.intval($uid).$this->deleteClause($table));
if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
#?? $this->versionOL($table,$row);
return $row;
}
}
......@@ -680,6 +766,7 @@ class t3lib_pageSelect {
);
$rows = array();
while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
#?? $this->versionOL($theTable,$row);
$rows[] = $row;
}
$GLOBALS['TYPO3_DB']->sql_free_result($res);
......@@ -759,7 +846,11 @@ class t3lib_pageSelect {
*/
function deleteClause($table) {
global $TCA;
return $TCA[$table]['ctrl']['delete'] ? ' AND '.$TCA[$table]['ctrl']['delete'].'=0' : '';
if (!strcmp($table,'pages')) { // Hardcode for pages...:
return ' AND deleted=0';
} else {
return $TCA[$table]['ctrl']['delete'] ? ' AND '.$TCA[$table]['ctrl']['delete'].'=0' : '';
}
}
/**
......@@ -810,6 +901,93 @@ class t3lib_pageSelect {
return $query;
}
/*********************************
*
* Versioning Preview
*
**********************************/
/**
* Find page-tree PID for versionized record
* Will look if the "pid" value of the input record is -1 and if the table supports versioning - if so, it will translate the -1 PID into the PID of the original record
*
* @param string Table name
* @param array Record array passed by reference. As minimum, "pid" and "uid" fields must exist! "t3ver_oid" is nice and will save you a DB query.
* @return void (Passed by ref).
* @see t3lib_BEfunc::fixVersioningPid()
*/
function fixVersioningPid($table,&$rr) {
global $TCA;
# SWAP uid as well???
if ($this->versioningPreview && $rr['pid']==-1 && ($table=='pages' || $TCA[$table]['ctrl']['versioning'])) { // Have to hardcode it for "pages" table since TCA is not loaded at this moment!
if ($rr['t3ver_oid']>0) { // If "t3ver_oid" is already a field, just set this:
$oid = $rr['t3ver_oid'];
} else { // Otherwise we have to expect "uid" to be in the record and look up based on this:
$newPidRec = $this->getRawRecord($table,$rr['uid'],'t3ver_oid');
if (is_array($newPidRec)) {
$oid = $newPidRec['t3ver_oid'];
}
}
// If ID of current online version is found, look up the PID value of that:
if ($oid) {
$oidRec = $this->getRawRecord($table,$oid,'pid');
if (is_array($oidRec)) {
$rr['_ORIG_pid'] = $rr['pid'];
$rr['pid'] = $oidRec['pid'];
}
}
}
}
/**
* Versioning Preview Overlay
* ONLY active when backend user is previewing records. MUST NEVER affect a site served which is not previewed by backend users!!!
*
* @param string Table name
* @param array Record array passed by reference. As minimum, the "uid" field must exist!
* @return void (Passed by ref).
*/
function versionOL($table,&$row) {
global $TCA;
if ($this->versioningPreview && $TCA[$table]['ctrl']['versioning']) {
#debug($row,$table);
#debug($this->versionPreviewMap);
if (is_array($row) && isset($this->versionPreviewMap[$table.':'.$row['uid']])) {
// ID to look for:
$lookFor = $this->versionPreviewMap[$table.':'.$row['uid']];
// Select the alternative version:
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid='.intval($lookFor).$this->deleteClause($table));
if ($altrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
if ($altrow['pid']==-1 && $altrow['t3ver_oid']==$row['uid']) {
unset($altrow['pid']); // Unsetting PID since this is basically the same as what fixVersioningPid would do to the record...
unset($altrow['uid']); // Unsetting UID because the overlaid record should KEEP its own UID.
# unset(...); // more fields being unset???
$row = t3lib_div::array_merge_recursive_overrule($row,$altrow,TRUE);
#debug($row,'Found:');
}
}
}
}
}
}
......
......@@ -270,12 +270,14 @@ class t3lib_recordList {
}
/**
* Returning "listURL" - the script with parameters to which forward/backward requests are sent
* Creates the URL to this script, including all relevant GPvars
*
* @return string
* @param string Alternative id value. Enter blank string for the current id ($this->id)
* @return string URL
*/
function listURL() {
return 'dummy.php?';
function listURL($altId='') {
return $this->script.
'?id='.(strcmp($altId,'')?$altId:$this->id);
}
/**
......
......@@ -2598,7 +2598,7 @@ class t3lib_TCEmain {
}
break;
case 'swap':
$this->version_swap($table,$id,$value['swapWith']);
$this->version_swap($table,$id,$value['swapWith'],$value['swapContent']);
break;
}
break;
......@@ -3398,9 +3398,10 @@ class t3lib_TCEmain {
* @param string Table name
* @param integer UID of the online record to swap
* @param integer UID of the archived version to swap with!
* @param boolean Swap content; If set then - for pages - the page content PIDs are swapped as well.
* @return void
*/
function version_swap($table,$id,$swapWith) {
function version_swap($table,$id,$swapWith,$swapContent) {
global $TCA;
/*
......@@ -3449,7 +3450,7 @@ class t3lib_TCEmain {
foreach($keepFields as $fN) {
$swapVerBaseArray[$fN] = $curVersion[$fN];
}
#debug($swapVerBaseArray);
// Check if the swapWith record really IS a version of the original!
if ($swapVersion['pid']==-1 && $swapVersion['t3ver_oid']==$id) {
#debug($curVersion,'$curVersion');
......@@ -3483,16 +3484,19 @@ class t3lib_TCEmain {
$this->log($table,$id,0,0,0,'Swapping successful for table "'.$table.'" uid '.$id.'=>'.$swapWith);
// SWAPPING pids for subrecords:
if ($table=='pages') {
if ($table=='pages' && $swapContent) {
// Collect table names that should be copied along with the tables:
foreach($TCA as $tN => $tCfg) {
if ($TCA[$tN]['ctrl']['versioning_followPages'] || $tN=='pages') {
if ($TCA[$tN]['ctrl']['versioning_followPages'] || $tN=='pages') { // THIS produces the problem that some records might be left inside a versionized branch. Question is; Should ALL records swap pids, not only the versioning_followPages ones?
$temporaryPid = -($id+1000000);
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN,'pid='.intval($id),array('pid'=>$temporaryPid));
if ($GLOBALS['TYPO3_DB']->sql_error()) $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN,'pid='.intval($swapWith),array('pid'=>$id));
if ($GLOBALS['TYPO3_DB']->sql_error()) $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN,'pid='.intval($temporaryPid),array('pid'=>$swapWith));
if ($GLOBALS['TYPO3_DB']->sql_error()) $sqlErrors[]=$GLOBALS['TYPO3_DB']->sql_error();
......@@ -3502,6 +3506,9 @@ class t3lib_TCEmain {