‪TYPO3CMS  9.5
MigratePagesLanguageOverlayUpdate.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
18 use Symfony\Component\Console\Output\OutputInterface;
19 use TYPO3\CMS\Core\Configuration\ConfigurationManager;
23 
29 {
33  protected ‪$output;
34 
38  public function ‪getIdentifier(): string
39  {
40  return 'pagesLanguageOverlay';
41  }
42 
46  public function ‪getTitle(): string
47  {
48  return 'Migrate content from pages_language_overlay to pages';
49  }
50 
54  public function ‪getDescription(): string
55  {
56  return 'The table pages_language_overlay will be removed to align the translation '
57  . 'handling for pages with the rest of the core. This wizard transfers all data to the pages '
58  . 'table by creating new entries and linking them to the l10n parent. This might take a while, '
59  . 'because max. (amount of pages) x (active languages) new entries need be created.';
60  }
61 
67  public function ‪updateNecessary(): bool
68  {
69  // Check if the database table even exists
70  if ($this->‪checkIfWizardIsRequired()) {
71  return true;
72  }
73  return false;
74  }
75 
79  public function ‪getPrerequisites(): array
80  {
81  return [
82  DatabaseUpdatedPrerequisite::class
83  ];
84  }
85 
91  public function ‪setOutput(OutputInterface ‪$output): void
92  {
93  $this->output = ‪$output;
94  }
95 
101  public function ‪executeUpdate(): bool
102  {
103  // Warn for TCA relation configurations which are not migrated.
104  if (isset(‪$GLOBALS['TCA']['pages_language_overlay']['columns'])
105  && is_array(‪$GLOBALS['TCA']['pages_language_overlay']['columns'])
106  ) {
107  foreach (‪$GLOBALS['TCA']['pages_language_overlay']['columns'] as $fieldName => $fieldConfiguration) {
108  if (isset($fieldConfiguration['config']['MM'])) {
109  $this->output->writeln('The pages_language_overlay field ' . $fieldName
110  . ' with its MM relation configuration can not be migrated'
111  . ' automatically. Existing data relations to this field have'
112  . ' to be migrated manually.');
113  }
114  }
115  }
116 
117  // Ensure pages_language_overlay is still available in TCA
118  GeneralUtility::makeInstance(LoadTcaService::class)->loadExtensionTablesWithoutMigration();
120  $this->‪updateInlineRelations();
122  $this->‪enableFeatureFlag();
123  return true;
124  }
125 
135  protected function ‪mergePagesLanguageOverlayIntoPages()
136  {
137  $overlayQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages_language_overlay');
138  $overlayQueryBuilder->getRestrictions()->removeAll();
139  $overlayRecords = $overlayQueryBuilder
140  ->select('*')
141  ->from('pages_language_overlay')
142  ->execute();
143  $pagesConnection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('pages');
144  $pagesColumns = $pagesConnection->getSchemaManager()->listTableDetails('pages')->getColumns();
145  $pagesColumnTypes = [];
146  foreach ($pagesColumns as $pageColumn) {
147  $pagesColumnTypes[$pageColumn->getName()] = $pageColumn->getType()->getBindingType();
148  }
149  while ($overlayRecord = $overlayRecords->fetch()) {
150  // Early continue if record has been migrated before
151  if ($this->‪isOverlayRecordMigratedAlready((int)$overlayRecord['uid'])) {
152  continue;
153  }
154 
155  $values = [];
156  $originalPageId = (int)$overlayRecord['pid'];
157  $page = $this->‪fetchDefaultLanguagePageRecord($originalPageId);
158  if (!empty($page)) {
159  foreach ($pagesColumns as $pageColumn) {
160  $name = $pageColumn->getName();
161  if (isset($overlayRecord[$name])) {
162  $values[$name] = $overlayRecord[$name];
163  } elseif (isset($page[$name])) {
164  $values[$name] = $page[$name];
165  }
166  }
167 
168  $values['pid'] = $page['pid'];
169  $values['l10n_parent'] = $originalPageId;
170  $values['l10n_source'] = $originalPageId;
171  $values['legacy_overlay_uid'] = $overlayRecord['uid'];
172  unset($values['uid']);
173  $pagesConnection->insert(
174  'pages',
175  $values,
176  $pagesColumnTypes
177  );
178  }
179  }
180  }
181 
187  protected function ‪updateInlineRelations()
188  {
189  if (isset(‪$GLOBALS['TCA']['pages_language_overlay']['columns']) && is_array(‪$GLOBALS['TCA']['pages_language_overlay']['columns'])) {
190  foreach (‪$GLOBALS['TCA']['pages_language_overlay']['columns'] as $fieldName => $fieldConfiguration) {
191  // Migrate any 1:n relations
192  if ($fieldConfiguration['config']['type'] === 'inline'
193  && !empty($fieldConfiguration['config']['foreign_field'])
194  && !empty($fieldConfiguration['config']['foreign_table'])
195  && !empty($fieldConfiguration['config']['foreign_table_field'])
196  ) {
197  $foreignTable = trim($fieldConfiguration['config']['foreign_table']);
198  $foreignField = trim($fieldConfiguration['config']['foreign_field']);
199  $foreignTableField = trim($fieldConfiguration['config']['foreign_table_field']);
200  $translatedPagesQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
201  $translatedPagesQueryBuilder->getRestrictions()->removeAll();
202  $translatedPagesRows = $translatedPagesQueryBuilder
203  ->select('uid', 'legacy_overlay_uid')
204  ->from('pages')
205  ->where(
206  $translatedPagesQueryBuilder->expr()->gt(
207  'l10n_parent',
208  $translatedPagesQueryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
209  )
210  )
211  ->execute();
212  while ($translatedPageRow = $translatedPagesRows->fetch()) {
213  $foreignTableQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($foreignTable);
214  $foreignTableQueryBuilder->getRestrictions()->removeAll();
215  $foreignTableQueryBuilder
216  ->update($foreignTable)
217  ->set($foreignField, $translatedPageRow['uid'])
218  ->set($foreignTableField, 'pages')
219  ->where(
220  $foreignTableQueryBuilder->expr()->eq(
221  $foreignField,
222  $foreignTableQueryBuilder->createNamedParameter($translatedPageRow['legacy_overlay_uid'], \PDO::PARAM_INT)
223  ),
224  $foreignTableQueryBuilder->expr()->eq(
225  $foreignTableField,
226  $foreignTableQueryBuilder->createNamedParameter('pages_language_overlay', \PDO::PARAM_STR)
227  )
228  )
229  ->execute();
230  }
231  }
232  }
233  }
234  }
235 
240  protected function ‪updateSysHistoryRelations()
241  {
242  $translatedPagesQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
243  $translatedPagesQueryBuilder->getRestrictions()->removeAll();
244  $translatedPagesRows = $translatedPagesQueryBuilder
245  ->select('uid', 'legacy_overlay_uid')
246  ->from('pages')
247  ->where(
248  $translatedPagesQueryBuilder->expr()->gt(
249  'l10n_parent',
250  $translatedPagesQueryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
251  )
252  )
253  ->execute();
254  while ($translatedPageRow = $translatedPagesRows->fetch()) {
255  $historyTableQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_history');
256  $historyTableQueryBuilder->getRestrictions()->removeAll();
257  $historyTableQueryBuilder
258  ->update('sys_history')
259  ->set('tablename', 'pages')
260  ->set('recuid', $translatedPageRow['uid'])
261  ->where(
262  $historyTableQueryBuilder->expr()->eq(
263  'recuid',
264  $historyTableQueryBuilder->createNamedParameter($translatedPageRow['legacy_overlay_uid'], \PDO::PARAM_INT)
265  ),
266  $historyTableQueryBuilder->expr()->eq(
267  'tablename',
268  $historyTableQueryBuilder->createNamedParameter('pages_language_overlay', \PDO::PARAM_STR)
269  )
270  )
271  ->execute();
272  }
273  }
274 
281  protected function ‪fetchDefaultLanguagePageRecord(int $pageId): array
282  {
283  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
284  $queryBuilder->getRestrictions()->removeAll();
285  $page = $queryBuilder
286  ->select('*')
287  ->from('pages')
288  ->where(
289  $queryBuilder->expr()->eq(
290  'uid',
291  $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
292  )
293  )
294  ->execute()
295  ->fetch();
296  return $page ?: [];
297  }
298 
306  protected function ‪isOverlayRecordMigratedAlready(int $overlayUid): bool
307  {
308  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
309  $queryBuilder->getRestrictions()->removeAll();
310  $migratedRecord = $queryBuilder
311  ->select('uid')
312  ->from('pages')
313  ->where(
314  $queryBuilder->expr()->eq(
315  'legacy_overlay_uid',
316  $queryBuilder->createNamedParameter($overlayUid, \PDO::PARAM_INT)
317  )
318  )
319  ->execute()
320  ->fetch();
321  return !empty($migratedRecord);
322  }
323 
330  protected function ‪checkIfWizardIsRequired(): bool
331  {
332  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
333  $connection = $connectionPool->getConnectionByName('Default');
334  $tableNames = $connection->getSchemaManager()->listTableNames();
335  if (in_array('pages_language_overlay', $tableNames, true)) {
336  // table is available, now check if there are entries in it
337  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
338  ->getQueryBuilderForTable('pages_language_overlay');
339  $numberOfEntries = $queryBuilder->count('*')
340  ->from('pages_language_overlay')
341  ->execute()
342  ->fetchColumn();
343  return (bool)$numberOfEntries;
344  }
345 
346  return false;
347  }
348 
355  protected function ‪enableFeatureFlag()
356  {
357  GeneralUtility::makeInstance(ConfigurationManager::class)->enableFeature('unifiedPageTranslationHandling');
358  }
359 }
‪TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayUpdate\fetchDefaultLanguagePageRecord
‪array fetchDefaultLanguagePageRecord(int $pageId)
Definition: MigratePagesLanguageOverlayUpdate.php:280
‪TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayUpdate\getDescription
‪string getDescription()
Definition: MigratePagesLanguageOverlayUpdate.php:53
‪TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayUpdate\updateSysHistoryRelations
‪updateSysHistoryRelations()
Definition: MigratePagesLanguageOverlayUpdate.php:239
‪TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayUpdate\isOverlayRecordMigratedAlready
‪bool isOverlayRecordMigratedAlready(int $overlayUid)
Definition: MigratePagesLanguageOverlayUpdate.php:305
‪TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayUpdate\getPrerequisites
‪string[] getPrerequisites()
Definition: MigratePagesLanguageOverlayUpdate.php:78
‪TYPO3\CMS\Install\Updates\ChattyInterface
Definition: ChattyInterface.php:25
‪TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayUpdate\getIdentifier
‪string getIdentifier()
Definition: MigratePagesLanguageOverlayUpdate.php:37
‪TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayUpdate\getTitle
‪string getTitle()
Definition: MigratePagesLanguageOverlayUpdate.php:45
‪TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayUpdate\$output
‪OutputInterface $output
Definition: MigratePagesLanguageOverlayUpdate.php:32
‪TYPO3\CMS\Install\Updates
Definition: AbstractDownloadExtensionUpdate.php:3
‪TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayUpdate\setOutput
‪setOutput(OutputInterface $output)
Definition: MigratePagesLanguageOverlayUpdate.php:90
‪TYPO3\CMS\Install\Service\LoadTcaService
Definition: LoadTcaService.php:26
‪TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayUpdate\executeUpdate
‪bool executeUpdate()
Definition: MigratePagesLanguageOverlayUpdate.php:100
‪TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayUpdate\enableFeatureFlag
‪enableFeatureFlag()
Definition: MigratePagesLanguageOverlayUpdate.php:354
‪TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayUpdate\updateInlineRelations
‪updateInlineRelations()
Definition: MigratePagesLanguageOverlayUpdate.php:186
‪TYPO3\CMS\Install\Updates\UpgradeWizardInterface
Definition: UpgradeWizardInterface.php:22
‪TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayUpdate\updateNecessary
‪bool updateNecessary()
Definition: MigratePagesLanguageOverlayUpdate.php:66
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayUpdate\checkIfWizardIsRequired
‪bool checkIfWizardIsRequired()
Definition: MigratePagesLanguageOverlayUpdate.php:329
‪TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayUpdate
Definition: MigratePagesLanguageOverlayUpdate.php:29
‪TYPO3\CMS\Install\Updates\MigratePagesLanguageOverlayUpdate\mergePagesLanguageOverlayIntoPages
‪mergePagesLanguageOverlayIntoPages()
Definition: MigratePagesLanguageOverlayUpdate.php:134
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:44
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45