Skip to content

Commit

Permalink
[!!!][TASK] Remove move placeholders
Browse files Browse the repository at this point in the history
Workspaces ("Element-based versioning") previously had - due to
the "pid=-1" logic until TYPO3 v10 - a so-called "MOVE PLACEHOLDER".

This was indicated by t3ver_state = 3, all relevant fields:
* t3ver_state = 3 (move placeholder)
* t3ver_oid = 0 no connected live record, it allowed fetching these records
  with one query together with live records as db restrictions t3ver_oid > 0
* t3ver_wsid = workspace UID
* t3ver_move_id = UID of the live record
* pid = new PID the version was moved to
* sorting - when a record was moved within page with activated sorting

Other record fields were not important. However, when moving a record, the
value from TCA ctrl section "shadowColumnsForMovePlaceholders" was used to
fill in gaps from the live record.

The ACTUAL versioned record was indicated by t3ver_state = 4, the so-called
"MOVE POINTER". In previous version until TYPO3 v10, it's PID field was set
to -1, but since TYPO3 v10, it has the same PID as the "MOVE PLACEHOLDER".

Characteristics of the move pointer as of TYPO3 v10:
* t3ver_state = 4 (move pointer)
* t3ver_oid = UID of the live record
* t3ver_wsid = workspace UID
* t3ver_move_id = 0
* pid = PID the version was moved to
* sorting - same value as the live record (not evaluated until now)
* All other fields with optionally modified content

Both move placeholder and move pointer did not know each other directly.
Fetching the move pointer for a move placeheldor (or the other way around)
involved the live record, leading to many queries.

The patch obsoletes the move placeholder records, moving necessary
information to the move pointer: It now contains the updated sorting
and is considered in the Database Restrictions to be fetched.

In general, when publishing, the moved record now
behaves identical to the other versioned types.

This makes the internal code much easier, creates less DB queries
on read + write and leads to less DB records in the database.

The change removes creation of move placeholders, and considers the
move pointers when evaluating sorting and PID in DataHandler.

Read functionality from BackendUtility and PageRepository don't need an
additional step to fetch the live version of a move placeholder anymore.

An upgrade wizard takes existing move placeholders (state=3), updates
pid+sorting (PID generally not needed, just to be sure) of the move
pointer (state=4) and then deletes the move placeholder.

TCA definition $TCA[my-table][ctrl][shadowColumnsForMovePlaceholders]
is not needed anymore and removed by an auto TCA migration.

Finally, workspace enabled tables do not need the t3ver_move_id field
anymore: The live record UID is already in t3ver_oid field for state=4
records, just like with all other versioned records. The field will
be fully removed with a separate patch in order to keep the actual CSV
tests readable for this patch.

Resolves: #92497
Releases: master
Change-Id: I206336aec8be8a324fefdfd69f648f5a298c6ad1
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/65797
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Oliver Bartsch <bo@cedev.de>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Oliver Bartsch <bo@cedev.de>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
  • Loading branch information
bmack authored and lolli42 committed Oct 12, 2020
1 parent 64542d6 commit 27c7de8
Show file tree
Hide file tree
Showing 94 changed files with 868 additions and 1,366 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ class InlineOverrideChildTca implements FormDataProviderInterface
't3ver_wsid',
't3ver_state',
't3ver_stage',
't3ver_move_id',
];

/**
Expand Down
52 changes: 20 additions & 32 deletions typo3/sysext/backend/Classes/Tree/Repository/PageTreeRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ class PageTreeRepository
't3ver_wsid',
't3ver_state',
't3ver_stage',
't3ver_move_id',
'perms_userid',
'perms_user',
'perms_groupid',
Expand Down Expand Up @@ -227,12 +226,12 @@ protected function getChildPageRecords(array $parentPageIds): array
if ($this->currentWorkspace !== 0 && !empty($pageRecords)) {
$livePagePids = [];
$livePageIds = [];
$movePlaceholderData = [];
$movedPages = [];
foreach ($pageRecords as $pageRecord) {
$livePageIds[] = (int)$pageRecord['uid'];
$livePagePids[(int)$pageRecord['uid']] = (int)$pageRecord['pid'];
if ((int)$pageRecord['t3ver_state'] === VersionState::MOVE_PLACEHOLDER) {
$movePlaceholderData[$pageRecord['t3ver_move_id']] = [
if ((int)$pageRecord['t3ver_state'] === VersionState::MOVE_POINTER) {
$movedPages[$pageRecord['t3ver_oid']] = [
'pid' => (int)$pageRecord['pid'],
'sorting' => (int)$pageRecord['sorting']
];
Expand Down Expand Up @@ -263,23 +262,18 @@ protected function getChildPageRecords(array $parentPageIds): array
->fetchAll();

foreach ($pageRecords as &$pageRecord) {
if ((int)$pageRecord['t3ver_state'] === VersionState::MOVE_PLACEHOLDER) {
$liveRecord = BackendUtility::getRecord('pages', $pageRecord['t3ver_move_id']);
$pageRecord['uid'] = (int)$liveRecord['uid'];
$pageRecord['t3ver_oid'] = (int)$pageRecord['t3ver_move_id'];
$pageRecord['title'] = $liveRecord['title'];
} elseif ((int)$pageRecord['t3ver_state'] === VersionState::MOVE_POINTER && !empty($movePlaceholderData[$pageRecord['t3ver_oid']])) {
if ((int)$pageRecord['t3ver_state'] === VersionState::MOVE_POINTER && !empty($movedPages[$pageRecord['t3ver_oid']])) {
$pageRecord['uid'] = $pageRecord['t3ver_oid'];
$pageRecord['sorting'] = (int)$movePlaceholderData[$pageRecord['t3ver_oid']]['sorting'];
$pageRecord['t3ver_state'] = VersionState::MOVE_PLACEHOLDER;
$pageRecord['pid'] = (int)$movePlaceholderData[$pageRecord['t3ver_oid']]['pid'];
$pageRecord['sorting'] = (int)$movedPages[$pageRecord['t3ver_oid']]['sorting'];
$pageRecord['pid'] = (int)$movedPages[$pageRecord['t3ver_oid']]['pid'];
} elseif ((int)$pageRecord['t3ver_oid'] > 0) {
$liveRecord = BackendUtility::getRecord('pages', $pageRecord['t3ver_oid']);
$pageRecord['sorting'] = (int)$liveRecord['sorting'];
$pageRecord['uid'] = (int)$liveRecord['uid'];
$pageRecord['pid'] = (int)$liveRecord['pid'];
}
}
unset($pageRecord);
} else {
$pageRecords = [];
}
Expand Down Expand Up @@ -352,15 +346,15 @@ protected function fetchAllPages(array $dbMounts, bool $resolveUserPermissions =
}

$livePagePids = [];
$movePlaceholderData = [];
$movedPages = [];
// This is necessary to resolve all IDs in a workspace
if ($this->currentWorkspace !== 0 && !empty($pageRecords)) {
$livePageIds = [];
foreach ($pageRecords as $pageRecord) {
$livePageIds[] = (int)$pageRecord['uid'];
$livePagePids[(int)$pageRecord['uid']] = (int)$pageRecord['pid'];
if ((int)$pageRecord['t3ver_state'] === VersionState::MOVE_PLACEHOLDER) {
$movePlaceholderData[$pageRecord['t3ver_move_id']] = [
if ((int)$pageRecord['t3ver_state'] === VersionState::MOVE_POINTER) {
$movedPages[$pageRecord['t3ver_oid']] = [
'pid' => (int)$pageRecord['pid'],
'sorting' => (int)$pageRecord['sorting']
];
Expand Down Expand Up @@ -397,13 +391,10 @@ protected function fetchAllPages(array $dbMounts, bool $resolveUserPermissions =
// The uid+pid of the live-version record is fetched
// This is done in order to avoid fetching records again (e.g. via BackendUtility::workspaceOL()
if ((int)$pageRecord['t3ver_oid'] > 0) {
// When a move pointer is found, the pid+sorting of the MOVE_PLACEHOLDER should be used (this is the
// workspace record holding this information), also the t3ver_state is set to the MOVE_PLACEHOLDER
// because the record is then added
if ((int)$pageRecord['t3ver_state'] === VersionState::MOVE_POINTER && !empty($movePlaceholderData[$pageRecord['t3ver_oid']])) {
$parentPageId = (int)$movePlaceholderData[$pageRecord['t3ver_oid']]['pid'];
$pageRecord['sorting'] = (int)$movePlaceholderData[$pageRecord['t3ver_oid']]['sorting'];
$pageRecord['t3ver_state'] = VersionState::MOVE_PLACEHOLDER;
// When a move pointer is found, the pid+sorting of the versioned record should be used
if ((int)$pageRecord['t3ver_state'] === VersionState::MOVE_POINTER && !empty($movedPages[$pageRecord['t3ver_oid']])) {
$parentPageId = (int)$movedPages[$pageRecord['t3ver_oid']]['pid'];
$pageRecord['sorting'] = (int)$movedPages[$pageRecord['t3ver_oid']]['sorting'];
} else {
// Just a record in a workspace (not moved etc)
$parentPageId = (int)$livePagePids[$pageRecord['t3ver_oid']];
Expand Down Expand Up @@ -543,8 +534,8 @@ public function fetchFilteredTree(string $searchFilter, array $allowedMountPoint
if ((int)$pageRecord['t3ver_oid'] > 0) {
$livePagePids[(int)$pageRecord['t3ver_oid']] = (int)$pageRecord['pid'];
}
if ((int)$pageRecord['t3ver_state'] === VersionState::MOVE_PLACEHOLDER) {
$movePlaceholderData[$pageRecord['t3ver_move_id']] = [
if ((int)$pageRecord['t3ver_state'] === VersionState::MOVE_POINTER) {
$movedPages[$pageRecord['t3ver_oid']] = [
'pid' => (int)$pageRecord['pid'],
'sorting' => (int)$pageRecord['sorting']
];
Expand Down Expand Up @@ -588,13 +579,10 @@ public function fetchFilteredTree(string $searchFilter, array $allowedMountPoint
if ((int)$pageRecord['t3ver_state'] === VersionState::DELETE_PLACEHOLDER) {
continue;
}
// When a move pointer is found, the pid+sorting of the MOVE_PLACEHOLDER should be used (this is the
// workspace record holding this information), also the t3ver_state is set to the MOVE_PLACEHOLDER
// because the record is then added
if ((int)$pageRecord['t3ver_state'] === VersionState::MOVE_POINTER && !empty($movePlaceholderData[$pageRecord['t3ver_oid']])) {
$parentPageId = (int)$movePlaceholderData[$pageRecord['t3ver_oid']]['pid'];
$pageRecord['sorting'] = (int)$movePlaceholderData[$pageRecord['t3ver_oid']]['sorting'];
$pageRecord['t3ver_state'] = VersionState::MOVE_PLACEHOLDER;
// When a move pointer is found, the pid+sorting of the versioned record be used
if ((int)$pageRecord['t3ver_state'] === VersionState::MOVE_POINTER && !empty($movedPages[$pageRecord['t3ver_oid']])) {
$parentPageId = (int)$movedPages[$pageRecord['t3ver_oid']]['pid'];
$pageRecord['sorting'] = (int)$movedPages[$pageRecord['t3ver_oid']]['sorting'];
} else {
// Just a record in a workspace (not moved etc)
$parentPageId = (int)$livePagePids[$pageRecord['t3ver_oid']];
Expand Down
1 change: 0 additions & 1 deletion typo3/sysext/backend/Classes/Tree/View/BrowseTreeView.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ class BrowseTreeView extends AbstractTreeView
'extendToSubpages',
'nav_hide',
't3ver_wsid',
't3ver_move_id',
'is_siteroot'
];

Expand Down
Loading

0 comments on commit 27c7de8

Please sign in to comment.